Portscan-Einzeiler mit Bordmitteln

Das seit einigen Jahren mit der PowerShell 4.0 eingeführte Cmdlet Test-NetConnection ist mit Sicherheit inzwischen ein vielgenutzter Helfer und ein sinnvoller Ersatz für die Verwendung von Telnet, um zu prüfen, ob ein Port offen ist.
Wer sich darüber hinaus die Zeit nimmt und die verfügbaren Parameter anschaut, findet neben des einfachen Socket-Connects noch eine ganze Menge weiterer hilfreicher Optionen.

Leider akzeptiert der Parameter „Port“ nur einen einzelnen Integer und kein Array, um mehrere Ports zu testen. Da der Parameter allerdings Pipelineeingaben akzeptiert, kann man das Problem schnell lösen.

PSPortScan

@(22, 80, 139, 443) | % { Write-Host Port $_":" $(Test-NetConnection 10.0.27.1 -Port $_ -InformationLevel Quiet -WarningAction SilentlyContinue) }

Gut kombinierbar ist das zudem mit der Array-Initialisierung mit Hilfe des Range-Operators (..), mit dem man größere Bereiche abdecken kann.

Das Ergebnis ist ein im Standard des Betriebssystems enthaltener Portscanner. Zwar eine sehr einfache, auf das absolute Minimum reduzierte Version eines Portscanners aber für einen schnellen Test meist ausreichend.

Advertisements

SharePoint Bulk-Delete via PowerShell

1.000+ ListItems in einer SharePoint-Liste und die müssen alle weg – und zwar fix. Manchmal sind es Demo- oder Test-Daten und mal soll schlicht nur aufgeräumt werden. Was tun? Eine Art „TRUNCATE TABLE“ wäre schön. Wieder hilft hier die PowerShell mit wenigen Zeilen und geladenen SharePoint-Commandlets weiter.

DELETE ALL ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$lst.Items | % { $lst.GetItemById($_.ID).Delete(); }

Zwar muss man dediziert für jedes ListItem die Delete-Methode rufen doch dafür verschwinden so zügig und unkompliziert die nicht länger benötigten Elemente aus SharePoint-Listen oder Bibliotheken.

Noch etwas interessanter wird der auf den ersten Blick nicht übermäßig elegant anmutende Ansatz für ein selektives Massen-Löschen…

DELETE SOME ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = „<Where><Eq><FieldRef Name=’Project‘ LookupId=’TRUE‘ /><Value Type=’Lookup‘>23</Value></Eq></Where>“
$lst.GetItems($query) | % { $lst.GetItemById($_.ID).Delete(); }

Mit Hilfe einer CAML-Abfrage holt man sich nur die ListItems, die man löschen möchte. Auf dem SPList-Objekt findet man die Methode GetItems(), welches als Parameter ein SPQuery-Objekt entgegennimmt. Im Beispiel oben sind ListItems zu löschen, die mit einem Projekt-Datensatz in einer zweiten Liste verknüpft sind, welcher auf die ID 23 hört.

Wer nun Freude am Löschen per PowerShell findet, für den habe ich hier noch ein paar CAML-Query Beispiele zusammengetragen, welche vielleicht die ein oder andere Idee zur eigenen Adaption bringt…

# ** Query-Beispiel: ListItems, deren ID kleiner als 250 ist
$query.Query = „<Where><Lt><FieldRef Name=’ID‘ /><Value Type=’Counter‘>250</Value></Lt></Where>“

# ** Query-Beispiel: ListItems, die am oder nach dem 01.01.2016 angelegt wurden
$query.Query = „<Where><Geq><FieldRef Name=’Created‘ /><Value IncludeTimeValue=’FALSE‘ Type=’DateTime‘>2016-01-01</Value></Geq></Where>“

# ** Query-Beispiel: ListItems, die im Titelfeld mit ‚A‘ beginnen
$query.Query = „<Where><BeginsWith><FieldRef Name=’Title‘ /><Value Type=’Text‘>A</Value></BeginsWith></Where>“

# ** Query-Beispiel: ListItems, deren Beschreibungsfeld (‚Description‘) das Wort ‚Prozess‘ enthält
$query.Query = „<Where><Contains><FieldRef Name=’Description‘ /><Value Type=’Note‘>Prozess</Value></Contains></Where>“

# ** Query-Beispiel: ListItems, deren Aktiv-Flag auf FALSE gesetzt ist
$query.Query = „<Where><Eq><FieldRef Name=’Active‘ /><Value Type=’Boolean‘>0</Value></Eq></Where>“

Und wem das nicht weit genug geht – man kann nicht nur die Delete-Methode auf dem Objekt rufen…

Web server in a PowerShell

Ein minimalistischer Webserver ohne viel Ballast, ohne Installation und für eine begrenzte Anzahl an Zugriffen macht sich gut für diverse kleine Aufgaben.

Auch, wenn es auf den ersten Blick etwas umständlich anmuten mag, lassen sich einige Einsatzmöglichkeiten finden. So möglicherweise, um schnell ein lokales Logfile auszuliefern, an welches man nicht ohne weiteren Aufwand heran kommt, um Systemeigenschaften anzuzeigen oder um Web Requests zu analysieren.
Denkbar wäre es auch, mit dieser Variante eines leichtgewichtigen Webservers, Kommandos von einer entfernten Maschine an einen Host abzusetzen, der sich bis auf wenige Ausnahmen, wie beispielsweise HTTP, gut hinter einer Firewall versteckt, und sich anschließend die Ausgabe anzeigen zu lassen.

Der Webserver bedient sich lediglich des System.Net.HttpListener, der im .NET Framework enthalten ist und den Standardfunktionen der PowerShell

Mit wenigen Zeilen Code ist ein solcher Server fix realisiert. Hier im Beispiel werden lediglich einige Details zu den verarbeiteten Web Requests ausgegeben…

Das Script ist relativ kompakt, so dass man es mit dürftiger Formatierung direkt per Copy’n Paste in die Shell einfügen kann…

Webserver in a PowerShell

Im Browser sieht das Beispiel dann so aus…

Webserver in a PowerShell - Chrome und IE

Jahresrückblick 2014

Jahresbericht 2014 - WordPressPünktlich kurz vor Toresschluss kommt WordPress mit seinem Jahresbericht um die Ecke. Grund genug, selbst noch einmal das Jahr Revue passieren zu lassen und einen kurzen als auch letzten 2014er Blogpost zu tippen.

Die Highlights im Blog…

  1. Zwei als Visio Add-Ins entwickelte Visualisierungstools zur Erzeugung von ERDs, für SharePoint sowie für Dynamics CRM, haben den Weg in eine Beta-Version geschafft.
  2. Kein ewiges Suchen von SharePoint-Feldnamen mehr, auch ohne den Einsatz von SPMetal. Mit Hilfe von SPWood kann man sich eine Helper-Klasse mit Enums erzeugen lassen, die im Intellisense jede Menge Informationen zu den Feldern preisgeben.
  3. Wer sich noch nicht für PowerShell im täglichen Einsatz begeistern hat lassen, der kann dies mit spannenden, allgemeinen Beispielen oder Ideen für Entwickler nachholen.

…und sonst so

  • .NET wird Open Source
    Die Details zu den jüngsten Bemühungen in Richtung cross platform, Zukunftssicherheit und Vereinheitlichung sind in den Blog-Einträgen „Introducing .NET Core“ und „Opening up Visual Studio and .NET to Every Developer, Any Application“ nachzulesen.
  • Microsoft Virtual Academy als ernstzunehmende Online-Lernplattform
    Zumindest zu Microsoft- und Microsoftnahen Themen definitiv eine vernünftige Alternative zu kostenpflichtigen Angeboten wie beispielsweise Pluralsight. Für Interessierte, die nach gut aufbereitetem Online-Kursen suchen sowie auch für Einsteiger lohnt es einen Blick unter www.microsoftvirtualacademy.com zu riskieren.
  • OneNote API wächst und wird erwachsen
    Nun erwachsen vielleicht noch nicht wirklich aber entgegen anfänglicher Befürchtungen, dass man das Thema genauso schnell wieder fallen lassen würde, wie man es in Redmond angeschoben hatte, wurde im Oktober die Referenzdokumentation unter dev.onenote.com/docs auf den aktuellen Stand gebracht.
  • Microsoft Band
    …ist gekauft; wenn es das gute Stück nur hierzulande schon geben würde.

Ich bin gespannt, was 2015 bringen wird und wünsche einen guten Rutsch ins neue Jahr! 🙂

PowerShell für Developer

Das eigentliche Killer-Feature der PowerShell ist tatsächlich die konsequent durchgesetzte Objektorientierung. Es muss ja nicht unbedingt immer gleich ein ganzes Script sein. Oft genug genügen auch ein paar .NET Objekte, die man sich mit wenigen Zeilen Code/Command(let)s von der ersten Property bis zu letzten Methode zu Gemüte führen kann.
Ganz besonders reizvoll wird dies bei APIs von komplexen Systemen, wie z. B. Microsoft SharePoint, mit deren Hilfe man per PowerShell auf dem gesamten Objektmodell mit minimalem Aufwand lesen und manipulieren kann.

Wie im letzten PowerShell-Post, hier ein paar meiner Favoriten kurz und knapp zusammengetragen:

#1 Get-Member: Objekt-Analyse

Direkt an der Konsole fehlt üblicherweise IntelliSense. Da man Eigenschaften und öffentliche Methoden von Objekten selten alle im Kopf hat, ist Get-Member das aus meiner Sicht wichtigste Cmdlet der PowerShell – ganz besonders dann, wenn man etwas abseits der Cmdlets mit .NET Objekten arbeitet. Den Spickzettel zu jedem Objekt gibt’s auf Befehl (im Beispiel für ein System.IO.FileInfo-Objekt) per Get-Member.

dir | Get-Member

Fehlen Methoden oder Eigenschaften, kann man dem Cmdlet mit der Option -Force noch ein wenig mehr Informationen entlocken.

dir | Get-Member -Force

#2 Invoke-WebRequest: Daten aus dem Netz verwenden

Mit einem Web Request Daten aus dem Netz laden: Beim Entwickeln von Software vor allem dann populär, wenn es um das Ansprechen von Web-APIs geht. Im nachfolgenden Beispiel wollen wir ein Diablo III Spielerprofil via REST Webservice abrufen.

// Daten abrufen; vorerst "Plain" per .NET Klassenbibliothek und dem WebClient
(New-Object System.Net.WebClient).DownloadString("http://eu.battle.net/api/d3/profile/quatze-2409/")
// Ganz ähnlich aber viel kürzer geht es mit dem Invoke-WebRequest Cmdlet, welches mit PS 3.0 eingeführt wurde
Invoke-WebRequest http://eu.battle.net/api/d3/profile/quatze-2409/

Soweit so gut aber wirklich arbeiten kann man damit noch nicht, da wir lediglich die JSON-Struktur in einem String haben. Mehr dazu mit dem nächsten Cmdlet…

#3 ConvertFrom-Json: Rückgabe des REST Webservice verarbeiten

Um mit den aus #2 abgerufenen Informationen zu arbeiten, kann man den abgerufenen String umständlich von Hand parsen und zerschneiden oder man konvertiert ihn in ein .NET Objekt. Das Cmdlet ConvertFrom-Json bringt hierfür alles mit, was wir benötigen.

// Der vom REST Webservice abgerufene String wird an das Cmdlet ConvertFrom-Json übergeben, welches ein Custom Object erzeugt
Invoke-WebRequest http://eu.battle.net/api/d3/profile/quatze-2409/ | ConvertFrom-Json
// In einem Schritt und ohne explizites Konvertieren erzeugen wir mit dem Cmdlet Invoke-RestMethod das Custom Object, ...
$d3profile = Invoke-RestMethod http://eu.battle.net/api/d3/profile/quatze-2409/
// ...an welchem wir alle Helden nebst Primärattribute im Spielerprofil ausgeben lassen können
$d3profile.heroes | ft name, level, hardcore, gender, last-updated -AutoSize

#4 Range Operator

Es klingt profan aber die Idee dahinter spart Zeit und Code: Der Range-Operator der PowerShell zum einfachen Erzeugen von nummerischen Bereichen. Praktischer Nutzen? Kommt sofort…

// 1 bis 10 ausgeben; zugegeben - eher unspannend aber es erklärt die Funktionsweise
1..10

// Alles von A-Z; immer noch kein umwerfendes Feature aber durchaus praktisch
65..90 | % { [char]$_ }
// Ein Array mit 23 bis 42 initialisieren
$a = 23..42
$a.Length
// Drei mal gpupdate ausführen mit jeweils 10 Sekunden Pause
1..3 | % { gpupdate ; "Update #$_ $(Get-Date) done." ; Start-Sleep 60 }

#5 [] als Indexer

Nur der Vollständigkeit halber noch zu erwähnen: Zugriffe auf Collections und Arrays sind analog zur C#-Syntax möglich…

// Hier im Beispiel des Arrays aus #4
$a[5]

 

Mehr Informationen zur PowerShell und den Standard-Cmdlets aus dem Microsoft.PowerShell.Utility Modul findet man im TechNet.

PowerShell: Schweizer Taschenmesser für alle

PowerShellVöllig unstrittig: Egal ob Bash, Cmd oder PowerShell – es gibt nicht selten Situationen, in denen geht es ohne Kommandozeile schlicht und ergreifend nicht weiter.
Gelegentlich – glücklicherweise zunehmend seltener – wird man trotzdem noch vor die Frage gestellt, was denn nun der Sinn der PowerShell sei, habe man doch alle Möglichkeiten mit der guten, alten Cmd. Dem Aufgeklärten fallen sofort Schlagworte wie objektorientiert und .NET Framework aus dem Gesicht, doch für einen echten Mehrwert reicht das noch nicht ganz. Gerade wenn die PowerShell von Softwareentwicklern beworben wird, schalten ambitionierte Endanwender auch gerne mal in den „brauch-ich-doch-nicht-Modus“, da das Handwerkszeug zu überdimensioniert erscheint, doch ist es das ganz und gar nicht.

Ein paar Beispiele, die mir mit der Zeit sehr ans Herz gewachsen sind und die das Potential haben, das Tagewerk eines jeden Keyboard-Junkies etwas zu erleichtern, kurz und knapp zusammengetragen:

#1 Get-ChildItem: Wer sucht, der findet

Dateien suchen… irgendwo auf der Platte hatte ich sie aber wo? Alles was im Index steckt – wie z. B. Dateien in der Bibliotheken oder dem Home-Folder – ist unproblematisch aber wie finde ich schnell und verlässlich Dateien, die irgendwo in den Untiefen des Systems liegen?
Das dir-Command (genau wie ls) an der PowerShell ist eigentlich ein Alias für das Commandlet Get-ChildItem. Entscheidend ist der Parameter -Recurse, der das Commandlet instruiert in allen erreichbaren Ordnern in/unterhalb des aktuellen Ordners zu suchen. Der Parameter -Filter hilft beim Eingrenzen der gesuchten Dateien.

ls -Recurse -Filter "*.log"

Ist zudem noch der Inhalt der per Get-ChildItem gesuchten Dateien interessant, so hilft die Übergabe der Ergebnisse an Select-String.

ls -Recurse -Filter "*.log" | Select-String "Exception"

#2 In alten DOS-Tools stets Standard: Datei-Attribute modifizieren

Möchte man z. B. das Erstellungsdatum oder das Änderungsdatum von Dateien anpassen, so führte in Prä-PowerShell-Zeiten der Weg gerne über eine hastig improvisierte Konsolenanwendung, welche man bis zum nächsten Einsatz gleich wieder verlegt hatte oder gar über ein Stück zwielichtige Freeware. Mit System.IO.File und einem Einzeiler ist man hier schneller am Ziel.

[IO.File]::SetLastWriteTime("C:\config.sys", (New-Object DateTime 1992, 1, 1))
[IO.File]::SetCreationTime("C:\config.sys", (New-Object DateTime 1992, 1, 1))

#3 Ausgabe in einer Tabelle sortieren und filtern ohne Umwege über Excel

Alles, was im Konsolenfenster passiert, bleibt im Konsolenfenster. Zumindest die Struktur bei tabellarischer Ausgabe kommt leider bei Copy&Paste abhanden. Möchte man mit den Daten weiterarbeiten, schafft hier das Commandlet Out-GridView Abhilfe, welches ein separates Tool zur tabellarischen Darstellung einer jeden PowerShell-Ausgabe startet; hier am Beispiel der letzten 10 Einträge aus dem Eventlog.

Get-EventLog Application -Newest 10 | Out-GridView

#4 Prüfsummen: MD5- oder SHA-Hash schnell berechnet

Nicht nur um zu prüfen, ob eine Datei sich gegenüber einem früheren Zeitpunkt verändert hat, sondern auch um diverse vorkompilierte Binaries aus der OpenSource-Gemeinde auf ihre Authentizität hin zu prüfen, kommt man an MD5 und SHA-Hashes kaum vorbei. Ungünstig nur, wenn man kein Tool zur Hand hat, in welches man den jüngst erworbenen Download stopfen kann. Der Security.Cryptography-Namespace des .NET Framework mit seinen Crypto Service Providern ist hier eine geeignete Anlaufstelle.

# MD5 
[BitConverter]::ToString((New-Object Security.Cryptography.MD5CryptoServiceProvider).ComputeHash((New-Object IO.FileInfo("C:\Windows\write.exe")).OpenRead())).Replace("-","").ToLower()
# SHA
[BitConverter]::ToString((New-Object Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash((New-Object IO.FileInfo("C:\Windows\write.exe")).OpenRead())).Replace("-","").ToLower()

#5 Es wird Zeit: Ticks und Timestamps

Häufig in Log-Dateien und Debugger-Ausgaben anzutreffen – Zeitstempel, die nicht auf den ersten Blick zielsicher im Kalender zuzuordnen sind. Mit einigen Bordmitteln bzw. statischen Methoden des .NET Typs DateTime kommt man den unterschiedlichsten Zeitangaben schnell auf die Schliche.

# Ticks in Datum/Zeit konvertieren 
[DateTime] 634539233533222331
# Datum/Zeit in Unix-Timestamp konvertieren
(([DateTime]::Now) - (New-Object DateTime 1970, 1, 1).ToLocalTime()).TotalSeconds
# Unix-Timestamp in Datum/Zeit konvertieren
(New-Object DateTime 1970, 1, 1).ToLocalTime().AddSeconds(1393023440)

Hyper-V Server 2012 beklagt fehlenden RPC-Dienst

Workgroup-Umgebung, ein Hyper-V Server 2012, Standalone, verwaltet von einem Windows 8 Client mit Hilfe des Hyper-V MMC Snap-Ins: Alles funktioniert problemlos.

Von einem Tag auf den nächsten, ohne Änderungen am Setup, meldet das MMC Snap-In, dass der RCP-Dienst auf dem Server nicht erreichbar/verfügbar sei: „Cannot connect to the RPC service on computer ‚HOSTNAME‘. Make sure your RPC service is running.“

Das Rätsels Lösung…
Die Ursache war das abgelaufene Kennwort des lokal auf dem Hyper-V Server erstellten Benutzerkontos, welches zur Verwaltung des Servers verwendet wurde.
Der einfachste Lösungsansatz wäre das Ablaufen des Kennworts für dieses Konto zu deaktivieren. Da es sich jedoch um eine Core-Installation handelt, galt es das Problem ohne GUI-Verwaltungstools sondern per PowerShell und WMI zu lösen.

# get all local user accounts 
$localUsers = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" -Filter "LocalAccount='$True'"
# index 2 is the hyper-v management user identified in $localUsers 
$localUsers[2].PasswordExpires 
# --> True
$localUsers[2].SetPropertyValue("PasswordExpires", $false)
$localUsers[2].PasswordExpires 
# --> False