Archiv der Kategorie: PowerShell-Praxis

Eine kurze Einführung in die PowerShell für erfahrene Skripter

Wer sein Leben lang eine klassische Skriptsprache (VBScript, Perl usw.) verwendet hat und nun mit der PowerShell arbeiten möchte, hat man Anfang oft unnötige Probleme und Startschwierigkeiten. Da bei der PowerShell vertraute Formalismen wie eine explizite Variablendeklaration oder ein expliziter AUsgabebfehl keine ROlle spielen bzw. optional sind, wirkt die PowerShell-Syntax für „Umsteiger“ ungewohnt, unlogisch und man tendiert schnell zu alles nur noch negativ zu sehen.

Ich muss zugegeben, dass ich am Anfang auch meine kleineren Problemee hatte, aber nach ein paar Jahren kam ich dann ganz gut mit der PowerShell-Syntax klar;)

Angeregt wurde ich für diesen Blog-Eintrag durch einen längeren Thread in einem Forum auf Administrator.de, in der der Fragesteller (offensichtlich ein älterer Mensch mit sehr viel VBScript-Erfahrung) mit der Art und Weise wie in PowerShell Arrays verwendet nicht klar kam und in jeder „geht leider immer noch nicht“-Antwort auf am Anfang sehr hilfsbereite Antworten immer mehr der Frust über die vermeintlich „grausame“ PowerShell-Syntax anklang. Am Ende schlug die Hilfsbereitschaft natürlich in Kritik um und er musste sich ein „Du wetterst hier seit Tagen über
PowerShell – irgenwie alles sch… aber allem Anschein nach fehlen dir die elementarsten Grundlagen“. Der Fragesteller gab dann auch später zu, dass er noch sehr viel lesen, lesen und lesen müsste, aber das ist für mich weder die Lösung noch die Ursache der offenkunding vorhandenen Unzufriedenheit.

Das grundsätzliche Problem ist eine überzogene Erwartungshaltung („mit PowerShell soll ja alles einfacher werden“ – wird meines Wissens nirgendwo behauptet) und die (falsche) Annahme, dass Techniken, die z.B. bei VBScript seit 20 Jahren angewendet wurden, sich 1:1 auf PowerShell übertragen lassen. Und wenn dann noch eine gewisse Ungeduld hinzu kommt, ist die Unzufriedenheit groß. Und wenn dann der Unzufriendende eine Multiplikator-Funktion besitzt und sich in der Firma oder in Foren über die vermmeintlichen Schwächen der PowerShell auslässt….

Die PowerShell ist nicht perfekt, aber sie ist nicht nur enorm leistungsfähig (das hilft Anfängern im Allgemeinen wenig), sondern weitestgehend konsistent. Das Problem, sofern man es als solches betrachtet ist, dass die Syntax keine Rücksicht auf VBScript&Co genommen wurde, Bruce Payette (der Kopf der PowerShell-Spprache) vielleicht nicht ein ganz so großes Genie ist wie Guido van Rossum (Python) oder Larry Wall (Perl) und die Version 1.0 unter einem enormen Zeitdruck veröffentlicht wurde. Der Vater der PowerShell, Jeffrey Snover, hat es auf der PowerShell Konferenz 2017 in Hannover so umschrieben, dass der Vorgesetzte bei Microsoft das ganze Projekt am liebsten wieder eingestampt hätte und dem Team irgendwann ein Ultimatum gestellt hatte – entwweder ihr bringt jetzt eine Version 1.0 oder das Projekt ist tot. Keine ganz optimale Voraaussetzung und eventuell eine Erklärung für einige der Inkosistenzen.

Hier sind meine persönlichen Regeln/Empfehlungen für einen Einstieg, der sich gerade an Anwender richtet, die sehr viel Erfahrung mit VBScript und anderen formalen Skriptsprachen besitzen.

Regel 1: Variablen müssen nicht deklariert werden

Regel 2: Es gibt keine Notwendigkeit Write-Host zu benutzen

Regel 3: Der Umgang mit Arrays ist einfach, man darf nur nicht wie ein Programmierer denken

Regel 4: Der Umgang mit mehrdimensionalen Arrays ist inkosistent und ein Schwachpunkt der PowerShell-Syntax

Regel 5: Zweidimensionale Arrays werden im Allgemeinen nicht benötigt

Regel 6: Es gibt ein Pendant zu Option Explizit

Regel 7: Halte es einfach

Regel 8: Verwende die Eingabehilfen und vor allem PSREadline

Regel 9: Freunde Dich mit Subexpressions an – am besten sofort

Regel 10: Aktualisiere die Hilfe und schau Dir die Beispiele zu Cmdlets und PowerShell-Befehlen an

Regel 11: Schreibe immer zuerst einen Test

Ok, diese Regel ist nicht ganz ernst gemeint.

Ich werde zu allen Regeln in naher Zukunft noch einiges schhreiben. Ich wollte die Regel erst einmal los werden, da sie frustrierten PowerShell-Anfängern eventuell helfen können. Und noch etwas: Keine Panik und alles wird gut;)

Umgang mit generischen Listen (Teil 1)

Eine generische Collection ist der Fachbegriff für ein Array bzw. allgemein eine Liste, die nur eine bestimmte „Sorte“ von Werten aufnehmen kann. Zum Beispiel Zahlen (Int32), Zeichenketten (String) oder bestimmte Objekttypen. Der Vorteil ist, dass eine generische Liste immer nur eine Sorte von Werten besitzt. Einen zwigenden Grund gibt es für diesen Speziallfall im PowerShell-Alltag nicht. Dennoch ist es gut, dass man auch in PowerShell generische Listen anlegen kann, da es einige Methoden gibt, die diese Sorte von Parameterwert erwarten. Außerdem wäre es schade, wenn das Umsetzen von C#-Code auf PowerShell-Skript an einem solchen Detail scheitern würde.

Das Anlegen einer generischen Liste ist grundsätzlich einfach.

WTToken ist lediglich irgendein Typ, der z.B. als Klasse definiert wird.

Das Hinzufügen eines Elements geschieht per Add-Methode:

Das war einfach, jetzt wird es etwas anspruchsvoller und leider unnötig kompliziert. Der letzte Befehl fügt ein WTToken-Objekt zu einer Liste hinzu. Über den Konstruktor werden die Properties Typ und Name mit Werten belegt. Für die Property Wert gibt es keinen Konstruktorparameter, da diese Property nicht immer belegt werden soll. Möchte man der Property einen Wert zuweisen, müsste man formal zuerst eine Variable anlegen:

Das ist aber etwas umständlich. In C# gibt es dafür Objektinitialisierer mit einer einfachen Syntax:

Bei der PowerShell 6.0 gibt es diese Möglichkeit noch nicht („noch“ weil es ja nur eine Frage der Zeit ist, bis ein Vorschlag im Projektportal eingereicht bzw. eventuell sogar fertig als Pull Request eingereicht wird).

Eine eventuell naheliegende Schreibweise funktioniert leider nicht.

Der Grund ist, dass die Zuweisung zwar grundsätzlich funktioniert, dabei aber kein WTToken-Objekt resultiert, das der Add-Methode übergeben werden könnte. Auch ein weiteres in runde Klammern setzen bringt nichts, da in diesem Fall lediglich der zugewiesene Wert zurückgegeben wird. In diesem Punkt gibt es also noch Verbesserungsbedarf was das Thema Objektinitialisierer beim Anlegen eines Objekts über die statische New-Methode angeht.

Es gibt einen „Workaround“, doch leider ist dieser arg umständlich und damit keine echte Verbesserung. Dieser besteht darin, einen Scriptblock zu übergeben, in dem das Objekt angelegt wird. Da aber auch hier eine Variable benötigt wird, damit am Ende das Objekt zurückgegeben werden kann, ist das Ganze nicht besonders elegant. Im Folgenden geht es daher nur um das Prinzip bzw. ein Anschauungsbeispiel.

Wer bis hierhin mitgelesen hat (dafür erst einmal einen herzlichen Glückwunsch angesichts der etwas trockenen Thematik, es lief wohl gerade nichts Passendes im Fernsehen, auf Netflix oder irgendwo anders;), natürlich gibt es eine einfache Lösung: Das New-Object-Cmdlet und seinen Propert-Parameter, mit dessen Hilfe sich ein Objekt gleichzeitig anlegen und was einzelne Eigenschaften betrifft initialisieren lässt.

Vielleicht nicht ganz so elegant wie die moderne Schreibweise per New, aber auf alle Fälle nachvollziehbar und trotzdem alles in allem relativ einfach in der Umsetzung.

Tipp: Mehrdimensionale Arrays als Parameter übergeben

Grundsätzlich ist der Umgang mit mehrdimensionalen Arrays bei der PowerShell kein Problem, man muss sich allerdings an die etwas spezielle Schreibweise beim Anlegen eines mehrdimensionalen Arrays gewöhnen. Da hätten sich die Väter der PowerShell etwas überlegen können.

Der folgende Befehl legt ein leeres zweidimensionales Array vom Typ 2×10 an. Die erste Dimension ist damit 2, die zweite Dimension 10.

Update: Seit Version 5.0 kann auch ein zweidimensionales Array über die statische new-Methode angelegt werden.

Die Anzahl der Dimensionen gibt die Rank-Eigenschaft, die Größe der jeweiligen Dimension holt die GetLength-Methode.

Wird ein mehrdimensionales Array einer Function als Parameter übergeben, sieht die Datentyp-Deklaration fast genauso aus.

Http.sys Url Reservierungen per PowerShell und ein wenig „String-Vodoo“ löschen

Eine URL-Reservierung ist eine vorgegebene URL-Schreibweise, die z.B. für den Aufruf eines Webservice verwendet wird. URL-Servierungen spielen z.B. beim Aufruf eines WCF-Dienstes per HTTP/HTTPS eine Rolle. Möchte ich einen WCF-Dienst nicht über Port 80, sondern z.B. über Port 88 aufrufen, muss zuvor eine URL-Reservierung angelegt werden. Soll der Dienst per HTTPS aufrufbar sein, muss eine SSL-Bindung angelegt werden. Beides wird offiziell per Netsh durchgeführt.

Zu den wenigen Bereichen, für die es aktuell (Stand: Oktober 2017) nur wenige PowerShell-Commands gibt, gehören die Kommandos der Netsh-Shell. Ein Auflisten aller URL-Reservierungen geschieht per

Die Textausgabe ist relativ umfangreich und vor allem nicht sehr regelmäßig strukturiert. Grundsätzlich sollte man auch ohne einen Doktor in „Regex-Kunde“ zu haben, das Zerlegen des Ausgabetextes per Select-String, dem Match-Operator oder per [Regex] hinbekommen, da es lediglich darum geht, eine bestimmte Zeile herauszufischen.

Ein weniger einfacher und vor allem ganz ohne Regex-Zauber geht es unter Umständen mit dem mit der Version 5.0 eingeführten ConvertFrom-String-Cmdlet, wenngleich die folgende kleine Lösung auch nicht perfekt ist. Die Idee ist, dass der zu konvertierende Text anhand eines Musters in seine Bestandteile zerlegt wird. Das Muster besteht aus der ersten Zeilen des zu konvertierenden Textes, in dem die zu extrahierenden Bereiche einfach in geschweifte Klammern gesetzt werden. In dem in den geschweiften Klammern jeweils ein Name angegeben wird, kann der extrahierte Text später über diesen Namen angesprochen werden. Bei sich wiederholenden Bereichen folgt auf den Namen noch ein *.

Im Idealfall liefert ConvertFrom-String pro Übereinstimmung ein Objekt, bei dem der über eine Markierung markierte Text über die Eigenschaft geliert wird, die dem Namen der Markierung entspricht.

Das folgende Beispiel zerlegt den Output von netsh urlacl nach den Http-Adressen und löscht jede Reservierung. Vorsicht: Die Reservierungen werden tatsächlich gelöscht. Die Nutzung erfolgt daher auf eigenes Risiko.

Das kleine Beispiel versteht sich in erster Linie als Anschauungsbeispiel für das enorm leistungsfähige, leider aber auch immer noch recht kryptische wirkende ConvertFrom-String-Cmdlet.

Wer nur eine komfortable Möglichkeit sucht, URL-Reservierungen und SSL-Bindungen zu löschen ohne die Befehlszeile bemühen zu müssen, sollte den praktischen Http.sys-Manager von Nicolas Dorier verwenden:

https://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager
bzw.

http://httpsysmanager.codeplex.com/

Das kleine WPF-Tool verwendet .NET-Klassen aus dem Namespace HttpSysManager.Core und HttpSysManager.Native. Theoretisch ließen sich die Klassen direkt in einem PowerShell-Skript verwenden. Wer also viel Zeit hat, kann sich in dieser Nische einen Namen machen, den ein PowerShell-Command scheint es noch nicht zu geben.