Zweites Treffen der PowerShell User Group Stuttgart am 23.02.17

Am 23.02.17 fand das zweite Treffen der PowerShell User Group Stuttgart statt. Der Gastgeber war dieses Mal die Firma Reddoxx (aka Die Netzwerker) in Kirchheim unter Tek.

Es war wieder ein netter und abwechslungsreicher Abend angefüllt mit vielen kleinen und größeren Details rund um die PowerShell. Das Motto des Abends Script Review oder „Bring your own Scripts“ (BYOS). Die Idee war, dass jeder seine PowerShell-Skripte hätte mitbringen können, die dann unter fachkundiger Begutachtung aller Anwensenden auf Schwachstellen und mögliche Verbesserungen hätten abgeklopft werden sollen. Das Fazit war, dass jeder wieder eine Menge lernt dazu mich eingeschlossen. So muss ich zugeben, dass ich bislang nicht wusste, dass man nicht nur Skripte, sondern auch Functions „dot sourced“ aufrufen kann. In diesem Fall werden die lokalen Variablen der Functions in die Ebene des Aufrufers gehoben und stehen dort nach Beendigung der Function noch zur Verfügung. Ich mir fällt zwar kein Anwendungsfall ein, interessant ist diese Technik aber in jedem Fall.

*** Weitere Details und ein Foto folgen in Kürze

Famous „Einzeiler“ in PowerShell

Es muss nicht immer gleich ein Skript sein, auch mit einem Einzeiler lässt sich bereits einiges bewerkstelligen. Auf Stackoverflow.com hat vor einigen Zeit eine Frage eine Vielzahl interessanter Einzeiler hervorgebracht:

http://stackoverflow.com/questions/615287/useful-powershell-one-liners?rq=1

Vergleichbar mit den „famous quotes“ gibt es natürlich auch ein paar „famous onliner“ in PowerShell. Hier ein paar Kostproben.

1) Auflisten aller Dateien, die ich heute geändert habe

2) Bei Visual Studio-Menüs die Großschreibung deaktivieren (11.0 steht für VS 2012)

3) Dateien auf den Desktop kopieren

Originell sind Beiträge wie „exit“ oder „gps programThatIsAnnoyingMe | kill“.

Ich habe natürlich selber auch jede Menge Einzeiler, die ich an dieser Stelle in naher Zukunft zusammenstellen werde (alleine in jeder Schulung fallen ein paar dieser Einzeiler an, die dann wieder in Vergessenheit geraten).

Tipp: Die Registry gekonnt durchsuchen

Der Umstand, dass die Registry-Hives wie HKey_Local_Machine als Laufwerk angesprochen werden, ist nur auf den ersten Blick eine Vereinfachung. Das wird spätestens dann deutlich, wenn man die Registry nach Einträgen (Names) eines Schlüssels und deren Werten (Values) durchsuchen möchte. Zwar zeigt ein dir hklm:\Software\Microsoft\Windows\CurrentVersion\Uninstall auch die Einträge der Schlüssel und ihre Werte an, liefert diese aber nicht zurück.

Der folgende Befehl funktioniert daher nicht.

Es gibt bei den zurückgegebenen Objekten ganz einfach keine Eigenschaft DisplayName. Bevor man jetzt allzu viel Zeit mit einer Suche nach einer Lösung verlierrt, was es gibt sind Methoden-Members wie GetValueNames und GetValue.

Der folgende Befehl gibt für alle installierten Anwendungen Anzeigename und Versionsnummer aus.

Weiß man nicht, welcher Schlüssel einen bestimmten Eintrag (Name) besitzen könnte, kommt die Methode GetValueNames in Frage.

Der folgende Befehl gibt alle Schlüssel aus, in denen eines Eintrag „ExecutionPolicy<" gibt.

Es stellt sich heraus, dass die Einstellung für die Ausführungsrichtlinie für den gesamten Computer unter HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell aufgehängt ist.

Der folgende Aufruf von Powershell.exe ändert die Einstellung z.B. auf „Restricted“.

Tipp: Zu welchem Namespace gehört ein Parametertyp?

Sobald man sich mit der PowerShell ein wenig besser auskennt (das kann unter Umständen ein paar Jahre dauern;) achtet man mehr auf die Feinheiten. Dazu gehört z.B. die Frage auf welchem (Daten-) Typ bestimmte Parameter basieren. Nehmen wir als Beispiel den Parameter ExecutionPolicy von Set-ExecutionPolicy. Ist sein Wert ein String oder eine Zahl? Weder noch, die Syntaxbeschreibung verrät, dass der Datentyp, große Überraschung, ExecutionPolicy ist. Da für den Parameter lediglich bestimmte Werte in Frage kommen, steht der Datentyp für eine Konstantenliste, eine Enum. Die Konstantenliste umfasst eine Reihe von Zahlenwerten, die durch Namen repräsentiert werden.

Es ist typisch für die PowerShell, dass eine automatische Typenkonvertierung durchgeführt wird. Übergebe ich für den Parameter z.B. „Unrestricted“, also einen String, wird dadurch automatisch die gleichnamige Konstante ausgewählt.

Was sicher nicht jeder weiß, es ist grundsätzlich sehr einfach die geladenen Assemblies nach einem bestimmten Typ zu durchsuchen, um sich z.B. den Namespace ausgeben zu lassen. Kennt man den Namespace, erfährt man alles über den Typ des Enum und kann sich z.B. alle Felder ausgeben lassen.

Der folgende Befehl führt eine Suche unter allen geladenen Typen durch.

Es stellt sich heraus, dass die vollständige Typenbezeichnung Microsoft.PowerShell.ExecutionPolicy ist.

Ein [Microsoft.PowerShell.ExecutionPolicy].GetFields().Name gibt z.B. die Namen der einzelnen Konstanten aus.

Da wir gerade dabei sind, wie erhalte ich den Zahlenwert einer Konstanten wie z.B. RemoteSigned? Ganz einfach per Typenkonvertierung z.B. in einen Int.

Also, keine „Angst“ vor speziellen PowerShell-Typen, sie lassen sich wie gezeigt sehr einfach in den geladenen Assemblies lokalisieren.

Endlich: Farbige Ausgaben (aber nur unter Windows 10 und Windows Server 2016)

Wenn die PowerShell in einem Punkt im Vergleich zu den Linux-Shells etwas blass aussieht, dann aufgrund der nüchternen Schwarz-Weiß-Optik. Es ist einfach nichts bunt. Klar, per Write-Host lässt sich jede Ausgabe farbig machen, aber wir wissen ja, dass wir Write-Host nicht verwenden sollen, da es die Ausgabe direkt in die Konsole schreibt – es ist in diesem Fall eine reine Textausgabe. Weiterverarbeitung nur sehr eingeschränkt möglich.

Seit Windows 10 und Windows Server 2016 und WMF 5.1 gibt es eine endlich eine Lösung. Sie besteht darin, dass das Konsolenfenster VT100-Escape-Sequenzen erkennt und entsprechend umsetzen kann. Unter anderem gibt es Esc-Seqenzen für eine farbige Ausgabe. Jetzt muss man nur noch eine Typenformatierungsdatei für den auszugebenden Typ anlegen, dort die Esc-Sequenzen einbauen und schon wird die Eigenschaft in einer anderen Farbe ausgegeben.

Ein Beispiel folgt in Kürze….

Praktisch: Dateien kopieren mit Fortschrittsanzeige

Das „Problem“ beim Kopieren von mehreren Dateien ist, dass die Anzahl der zu kopierenden Dateien am Anfang in der Regel nicht bekannt ist. Möchte man Dateien mit Hilfe einer Function pipelinebasierend kopieren, gibt es in der Regel keine Möglichkeit an die Anzahl der Dateien, die der Function übergeben werden, heranzukommen. Der „Trick“ mit $Input.Count funktioniert ab der Version 3.0 nicht in einer Pipeline-Function.

Eine einfache Lösung besteht darin, die zu kopierenden Dateien im Process-Block zu sammeln und die Dateien erst im End-Block zu kopieren. In dieser Aufteilung werden die Dateien im Process-Block lediglich gezählt, um dann im End-Block im Rahmen einer ForEach-Wiederholung kopiert zu werden.

Das folgende Beispiel veranschaulicht das Prinzip.

Aufgerufen werden kann die Function wie folgt:

Die DSC-Script-Ressource etwas flexibler einsetzen

Zu den knapp ein Dutzend DSC-Ressourcen, die bei der PowerShell 5.0 von Anfang an dabei sind, gehört auch die Script-Ressource. Mit ihrer Hilfe ist es möglich, auf einem Node bei der Anwendung der Ressource durch den LCM beliebige Skriptbefehle auszuführen. Das hört sich zunächst einmal gut an, etwas kniffliger ist es die Ressource so einzusetzen, dass sie wirklich etwas bringt. Das bedeutet konkret, Parameterwerte, die Teil der Konfigurationsdaten sind, in die per SetScript ausgeführten Befehle einzubauen.

Die Script-Ressource umfasst drei Eigenschaften: TestScript, GetScript und SetScript. Alle drei Eigenschaften sind vom Typ String, ihnen kann aber auch ein ScriptBlock zugewiesen werden was im Allgemeinen die etwas flexiblere Variante ist. TestScript enthält einen Befehl/Befehlsfolge, die einen $true/$false-Wert zurückgeben muss. Nur wenn der Wert $false ist, wird der Befehl ausgeführt, der über SetScript festgelegt wird. GetScript erfüllt keine echte Funktion. Die Befehlsfolge muss eine Hashtable mit einer Result-Eigenschaft zurückgeben, die einen beliebigen Wert besitzen kann.

Soweit, so gut. In der Regel sollen die per SetScript auszuführenden Befehle Werte verarbeiten, die Teil der Konfigurationsdaten sind. Dazu muss die Variable Node in die Befehlskette eingebaut werden. Am einfachsten geschieht dies, in dem der Node-Variablen ein „using:“ vorangestellt wird. Per Using kann auch eine Variable angesprochen werden, die außerhalb der Konfiguration definiert ist.

Im folgenden Beispiel soll eine Datei über das Web herunterladen und in einem lokalen Verzeichnis abgelegt werden. Die Url ist Teil der Konfigurationsdaten und wird daher über die Node-Variable angesprochen.

Der folgende Aufruf setzt die Konfiguration um.

Der folgende Aufruf überträgt die Konfiguration auf den über die Konfigurationsdaten festgelegten Computer (in diesem Beispiel ist es der lokale Computer).

StarWars Episode IV via Telnet als ASCII-Film

Auch wenn der Star Wars-Film im ASCII-Format vermutlich nichts Neues mehr ist, bin ich erst vor kurzem per Zufall darauf gestoßen und finde das Ganze einfach nur genial.

Einfach Telnet in PowerShell oder Cmd starten (der Telnet-Client gegebenenfalls noch als Feature hinzugefügt werden) und „telnet towel.blinkenlights.nl“ eingeben. Und schon geht es los.

Großes Kompliment an die Macher (ich möchte nicht wissen, wieviel Zeit, die man mit sinnvolleren Dingen hätte verbringen können, dafür geopfert werden musste – aber auf der anderen Seite, damit haben sie sich im Hacker- und Geek-Universum verewigt). Auf alle Fälle ist es ein gelungenes Beispiel dafür, wie Hacker die Welt ein klein wenig besser machen können, in dem sie etwas schaffen, dass einfach Freude macht und das zeigt was mit Bits, Programmierung und einer großen Portion Kreativität alles machbar ist. Der „Film“ ist erstaunlich „kompakt“ und macht schon Spaß alleine, um noch einmal die ganzen Zitate aus Episode IV mitlesen zu können („this are not the droids you are looking for“). Leider, und das ist ein großes Leider, ist der Film noch nicht fertig, sondern hört irgendwann im letzten Drittel einfach auf. Die Zerstörung des Todessterns, soviel verrate ich bereits, ist leider noch nicht umgesetzt. Ich denke, dass dies aufgrund der besonderen perspektivischen Darstellung auch eine echte Herausforderung sein dürfte. Der Autor Simon Jansen hat auf seiner Wbeseite aber in Aussicht gestellt, dass er sein Projekt irgendwann fertigstellen wird.

Die ersten Schritte mit den AWS-Cmdlets (inkl. Problemlösung)

Amazon stellt für die Nutzung ihrer inzwischen sehr umfangreichen Amazon Webservices (AWS) ein sehr umfangreiches Modul (über 2.500 Cmdlets!) zur Verfügung. Die AWS Tools for Windows PowerShell stehen u.a. über die PowerShell Gallery zur Verfügung.

Eine ausführliche Übersicht gibt es unter der folgenden Adresse: https://aws.amazon.com/de/powershell/. Dort gibt es auch einen Button für den direkten Download einer Msi-Datei, über die das .NET SDK und die Cmdlets installiert werden.

Die Dokumentation ist, typisch für AWS, vorbildlich mit ein paar kleineren Abstrichen.

Das Modul muss direkt per Import-Module geladen werden.

Ein kleiner „Trick“ zählt die Anzahl der Cmdlets, in dem die Verbose-Ausgabe auf den Standardausgabekanal umgeleitet und damit in die Pipeline gelegt wird.

Die Authentifizierung erfolgt über einen Access Key und einen Secret Key, die man zuvor in der AWS-Konsole im Browser anlegen muss. Der Secret Key wird nur einmalig beim Anlegen eines neuen Key angezeigt und kann als Csv-Datei heruntergeladen werden.

Mit den beiden Zutaten wird per Set-AWSCredentials ein Profil angelegt.

Hier kam es bei mir zu einer Fehlermeldung, die besagte, dass der Pfad %userprofile%\.asws\credentials nicht gefunden werden konnte. Dieser Fehler muss wohl mit der Version der AWS-Tools (3.3.45.0) und anderen Faktoren zu tun haben. Der Fehler trat nicht mehr auf, nachdem ich im Benutzerprofil ein Verzeichnis mit dem Namen .aws angelegt hatte.

Interessant ist, dass die Keys aber nicht in diesem Verzeichnis, sondern als Json-Datei RegisteredAccounts.json unter %userprofile%\AppData\Local\AWSToolkit abgelegt werden.

Anschließend wurde das Profil per Get-AWSCredentials -ListStoredCredentials aufgelistet. Per Clear-AWSCredentials kann ein Profil wieder gelöscht werden.

Die weitere Vorgehensweise ist dann sehr einfach. Bei allen Cmdlets wie z.B. Get-S3Bucket erfolgt die Authentizierung über das Profil, das per ProfileName-Parameter angegeben wird.

WMF 5.1 offiziell verfügbar

Seit Mitte Januar 2017 gibt es offiziell die Version 5.1 der Powershell und des Windows Management Framework (WMF) für alle windows-versionen ab Windows Server 2008 R2 und Windows 7.

Die Download-Adresse ist:

http://www.microsoft.com/en-us/download/details.aspx?id=54616

Viele Neuerungen sind es natürlich nicht, aber es gibt Neuerungen. Eine davon sind signierte Module. Eine andere ein Satz an Cmdlets für die Verwaltung lokaler Benutzer und Gruppen.

Die immer lesenswerten Release-Notes gibt es hier:

https://msdn.microsoft.com/en-us/powershell/wmf/5.1/release-notes