Archiv für den Monat: Oktober 2016

Tipp: TimeSpan-Werte formatieren

Auch TimeSpan-Werte lassen sich per f-Operator formatiert ausgeben. Gewußt wie ist hier das Motto, denn die Formatbezeichner sind nur schwer zu finden, auch wenn sie eigentlich ganz logisch sind;)

Das folgende Beispiel formatiert ein TimeSpan-Objekt so, dass der Minuten-, Sekunden- und Millisekunden-Anteil ausgegeben wird.

Wem das zu umständlich ist, kann ein TimeSpan-Eigenschaft über seine Ticks-Eigenschaft in einen DateTime-Wert konvertieren, der auf vetraute Art und Weise formatiert wird.

Rekursive Functions in PowerShell

Eine rekursive Function ist eine Function, die sich selber aufruf. Warum sollte sie das tun? Damit ein Befehlsfolge eine beliebige Anzahl oft wiederholt werden kann. Im Unterschied zu seiner Schleife wiederholt sich die Befehlsfolge selber. Eine praktische Anwendung ist eine Verzeichnissuche – nicht immer gibt es einen Recurse-Parameter oder ein Cmdlet wie Get-ADuser, das eigentlich Find-ADUser heißen müsste, da es eine Suche in der gesamten (Verbund-) Verzeichnisstruktur durchführt.

Rekursive Functions sind grundsätzlich sehr einfach – das Problem liegt in erster Linie darin, sich eine Abbruchbedingung zu überlegen. Außerdem ist das Konzept vielen zu abstrakt, so dass sie lieber die „iterative“ Variante in Gestalt einer regulären Schleife bevorzugen.

Ein einfaches Beispiel zur Einstimmung ist die Berechnung der Fakultät einer ganzen Zahl, da hier lediglich bei der Zahl 1 beginnend eine Zahl mit der um eins größeren Zahl multipliziert wird.

Aufgerufen wird die Function wie folgt:

Etwas kniffliger ist die Berechnung einer Fibonacci-Zahlenfolge, bei der eine folgende Zahl aus der Summe ihrer beiden Vorgängerzahlen gebildet wird. Also die Reihenfolge 0 1 1 2 3 5 8 13 21 34 55 usw. entsteht. Offiziell lautet die Berechnungsformel fib(n-1) + fib(n-2), wobei die Zahl n >= 2 sein muss. Mit dieser Formel ist die Umsetzung relativ einfach im Gegensatz zum Hochzählen von n was mir auch nach längerem Herumprobieren nicht gelungen ist.

Hier ist die Umsetzung der „einfachen“ Variante mit Abbruchbedingung n = 0 und n = 1.

Bei z 0 und bei z = 1 bricht die Function jeweils mit den Werten 0 und 1 ab, die auf den Rückgabewert aufaddiert werden. Ungewohnt und für Jemanden, der mit der typischen „Programmierer-Logik“ noch nicht viel zu tun hat, auch reichlich verwirrend dürfte der Umstand sein, dass für den Rückgabewert keine Variable im Spiel ist und dieser einfach aus der Function selber entsteht. Der break-Befehl verlässt nicht die Function, sondern nur den switch-Befehl. Da in diesem Fall aber die Function nicht erneut aufgerufen wird, entspricht dies indirekt einem Abbruch der Function. Einfach und genial. Ein return-Befehl ist offiziell nicht erforderlich, wäre aber sinnvoll, damit die Function etwas besser nachvollziehbar wird.

Aufgerufen wird die Function wie folgt:

Es ist faszienierend wie lange die Berechnung bei etwas größeren Zahlen dauert. Bereits mit z = 100 dauert die Berechnung „ewig“ – und das auf einer halbwegs modernen 4-Kerne-CPU.

Ereignisse in einer Remote-Session weiterleiten

Die PowerShell bietet bereits seit der Version 2.0 einen leistungsfähigen Ereignismechanismus. Zum einen lassen sich relativ Events von Objekten auswerten, die auf vordefinierten Klassen wie System.Timer oder System.IO.FileWatcher basieren. Interessant wird es beim Thema Event-Weiterleitung („Forwarding“) aus einer Remoting-Session. Damit kann jedes im Rahmen der Remoting-Session entstandene Ereignis lokal ausgewertet werden. Zuständig ist der unscheinbare Forward-Parameter beim Register-ObjectEvent-Cmdlet. Da das Thema in der PowerShell-Hilfe etwas zu kurz kommt (das einzige Beispiel verwendet WMI-Events), habe ich im Folgenden ein kleines Beispiel zusammengestellt. Dabei wird per PS-Remoting ein FileSystemWatcher auf einem Remote-Computer eingerichtet. Wird ein Ereignis ausgelöst, z.B. weil in dem überwachten Verzeichnis eine Datei angelegt wurde, wird das Event an den lokalen Computer weitergeleitet und führt dort zur Ausgabe einer Meldung, in der u.a. der Name des betroffenen Verzeichnisses enthalten ist.

Im ersten Schritt wird die Remoting-Session angelegt. Die Befehlsfolge richtet den FileSystemWatcher für das Verzeichnis C:\Temp ein. Anschließend werden per Register-ObjectEvent-Cmdlet die Ereignisse „Created“ und „Deleted“ registriert. Es wird keine Aktion angegeben, da diese lokal ausgeführt werden soll. Stattdessen erhält jede Registrierung lediglich einen Source Identifier. Der wichtigste Parameter ist Forward. Er bewirkt, dass ein Ereignis an den lokalen Computer weitergereicht wird. Der Parameter MessageData ist optional. Über ihn lassen sich beliebige Daten mit dem Event übergeben. In diesem Beispiel ist es lediglich der Name des Remote-Computers.

Im zweiten Schritt werden die beiden Ereignisse mit den Source Identifiern „TempWatch1“ und „TempWatch2“ auch lokal registriert. Da es in diesem Fall kein Objekt mit einem Event gibt, wird das Ereignis nicht per Register-ObjectEvent, sondern per Register-EngineEvent registriert, da es hier keinen InputObject-Parameter gibt. Per Action-Parameter wird der Scriptblock festgelegt, der lokal ausgeführt wird, wenn aus der Remote-Session ein Ereignis gemeldet wird.

Im nächsten Schritt wird der Scriptblock definiert, der immer dann ausgeführt werden soll, wenn aus der Remote-Session ein Ereignis gemeldet wurde.

Im Unterschied zu einer rein lokalen Ereignisverarbeitung muss bei der EventArgs-Variablen die Eigenschaft SerializedRemoteEventArgs „zwischenschaltet werden, um an die Ereignisargumente heranzukommen. Bei der Variablen Event ist das nicht erforderlich.

Zum Schluss wird die PS-Remoting-Session gestartet. Da das Ereignis zu einem späteren Zeitpunkt eintritt, z.B. wenn irgendwann eine Datei in dem überwachten Verzeichnis angelegt oder gelöscht wird, wird die Remoting-Session explizit per New-PSSession angelegt und nicht implizit und der Scriptblock für das Einrichten des FileSystemWatchers wird per Invoke-Command gestartet.

Wird jetzt auf dem Remote-Computer im überwachten Verzeichnis eine Datei angelegt oder gelöscht, wird das resultierende Ereignis an den lokalen Computer weitergeleitet und führt zur Ausgabe einer Meldung, da der Scriptblock, der über die Variable SBAction festgelegt wird, ausgeführt wird.

Hier noch einmal das komplette Beispiel auf einen Blick.

Die About-Themen der Hilfe herunterladen

In letzter Zeit fällt mir immer wieder auf, dass die about-Themen der PowerShell-Hilfe nach einem Update auf die Version 5.0 und vor allem im Rahmen der Vorabversion des WMF 5.1, etwa bei Windows 10 AE, nicht zur Verfügung stehen.

Auf GitHub stellt PowerShell-MVP Ryan Yates ein kleines Skript zur Verfügung, das per Invoke-WebRequest die Txt-Dateien aus seinem Github-Verzeichnis lädt und im PowerShell-Hilfeverzeichnis en ablegt:

https://github.com/kilasuit/Install-AboutHelp

PowerShell und XLinq

XLinq ist die Kurzform für die Klassen im Namesapce System.Xml.Linq, die den Umgang mit XML-Daten etwas vereinfachen, in die API entwicklerfreundlicher ist. Auf wenn sich das im Rahmen der PowerShell nicht direkt auswirkt, da der Umgang mit XML-Daten bereits sehr komfortabel ist, die Klassen auch bei der PowerShell gewisse Vorteile.

*** Dies ist nur ein vorläufiger Text, den ich den näher Zukunft noch überarbeiten werde ***

Das erste Beispiel zeigt, wie per Parse-Methode aus einem XML-Text ein XElement-Objekt wird. Die Assembly System.Xml.Linq, die Teil der .NET-Laufzeit ist, muss explizit geladen werden.

Neu: Der PoshAdmin-Newsletter

In Kürze biete ich einen Newsletter mit Tipps rund um den Einsatz der PowerShell und aktuellen Infos an, etwa zu neuen Modulen oder aktuellen Neuerungen der PowerShell.

Als Newwsletter-Programm verwende ich MailChimp – da das Thema für mich absolutes „Neuland“ ist, kann es sein, dass das Ganze am Anfang noch etwas unrund läuft. Der erste Newsletter soll Anfang Dezember erscheinen.

Die Anmeldung zu dem Newsletter ist bereits über den Link in der Kopfleiste möglich. Der erste Anmelder erhält von mir mein PowerShell 4.0-Buch als kleines Dankeschön (der Rechtsweg ist natürlich ausgeschlossen;)

Tipp: Die Eigenschaften eines Array abfragen

Dies ist eine typische „Wie gut kennst Du die PowerShell-Frage“, die ich in einem PowerShell-Kurs für Fortgeschrittene gerne stelle:

Wie lassen sich eigentlich die Members eines Array ausgeben, wie z.B. die Length-Eigenschaft oder die Rank-Eigenschaft, die die Anzahl an Dimensionen liefert?

Ein $ArrayVariable | Get-Member liefert immer die Members der Elemente, die in dem Array enthalten sind und nicht die Members des Arrays selber.

Auf die Antwort kann man unmöglich von alleine kommen, auch wenn die Lösung sehr einfach ist. Man muss lediglich das Array dem InputObject-Parameter von Get-Member übergeben.

Da in dem Beispiel ein dreidimensionales Array angelegt wurde, liefert die Rank-Eigenschaft den Wert 3.

Von 2 auf 5 – PowerShell 5.0 unter Windows 7 installieren

Eigentlich sollte die Installation der PowerShell 5.0 unter Windows 7 bei vorinstallierter Version 2.0 und .NET 3.5.1 kein Problem sein. Eigentlich. Ich habe es aber bereits ein paar Mal erlebt, dass in einer Windows 7-VM (meine Windows 7-Version war jedes Mal nicht aktiviert und sie war natürlich nicht auf dem neusten Stand, was aber keine Rolle spielen sollte) das Installationprogramm nach dem Start beim Prüfen auf Updates in einer Endlosschleife hängen blieb.

Eine einfache, allerding auch etwas zeitintensive Lösung besteht aus insgesamt fünf einfachen Schritten:

1) Installation der .NET 4.5.1-Laufzeit (oder einer aktuelleren Version, wie z.B. 4.6.1). Bei dieser Installation tritt das Phänomen mit der Endlosschleife nicht auf.

2) Download der Msu-Datei mit dem WMF 5.0-Update. Der Dateiname für Windows 7 ist Win7AndW2K8R2-KB3134760-x64.msu.

3) Kopieren des Inhalts der Msu-Datei in ein zuvor angelegtes und damit leeres Verzeichnis mit Hilfe des Befehlszeilentools Expand (es ist unglaublich, wieviele Dateien eine solche Msu-Datei enthält).

5) Installieren der Cab-Datei Windows6.1-KB3134760-x64.cab über das Befehlszeilentool Pkgmgr. Damit wird die Update-Prüfung ausgelassen.

Das Ganze dauert eine Weile, in der scheinbar nichts passiert (der Prozess TrustedInstaller verrät, dass etwas passiert). Irgendwann kommt die Aufforderung zum Neustart. Nach dem Neustart wird die Installation noch etwas fortgesetzt und irgendwann bootet Windows 7 mit installiertem WMF 5.0. Der Zwischenschritt zur Version 4.0 war nicht erforderlich.