Flexible Typenkonvertierung dank PSTypeConverter – ein kleines Beispiel erklärt wie die Typenkonvertierung bei der PowerShell funktioniert

Die in diesem Blog-Eintrag vorgestellte Technik ist zwar unabhängig von einer bestimmten PowerShell-Version – für die Umsetzung des Beispiels wird die Version 3.0 vorausgesetzt, wenngleich es mit der Version 2.0 theoretisch auch funktionieren sollte

Eine der Stärken der PowerShell ist die flexible Typenkonvertierung und -erweitererung. Dazu gehört vor allem die Fähigkeit, durch Typenkonvertierung an Objekte weitere Members anzuhängen. Dies geschieht immer so, dass es der Anwender nicht mitbekommt, sofern er oder sie überhaupt mit dem etwas anspruchsvolleren Konzept der Typen vertraut ist und/oder sich überhaupt dafür interessiert.

Wer z.B. ein Get-Process-Cmdlet ausführt, erhält zwar Objekte vom Typ System.Diagnostics.Process zurück, doch in „Wirklichkeit“ basieren die Objekte auf einem dynamischen Typ, der aus dem PowerShell-Typensystem hervorgegangen ist und um zahlreiche Members erweitert wurde. Das „wahre“ Objekt stellt jedes PowerShell-Objekt über seine PsObject-Eigenschaft zur Verfügung. Die Grundlage für die Typenerweiterung beim Process-Objekt ist die Datei Types.ps1xml im PowerShell-Installationsverzeichnis, in der die nachträglich angehängten Members für den Typ System.Diagnostics.Process definiert werden. Ein Beispiel: Die Eigenschaft Ws wird als AliasProperty nachträglich angehängt, damit die Eigenschaft mit dem etwas sperrigen Namen Workingset64 (bzw. Workingset) über einen kurzen Namen abgesprochen werden kann.

Die Typenkonvertierung eines Objekts kann auch dynamisch erfolgen, also ohne, dass die zusätzlich hinzugefügten Members bereits festgelegt wurden. Ein Beispiel ist der Typ-Alias [Xml], der Text in ein System.Xml.XmlDocument-Objekt konvertiert, sofern es sich um wohlgeformtes XML handelt, und dabei die Elemente und Attribute als Eigenschaften anhängt.

Durch den Xml Typalias findet eine Typenkonvertierung statt. Aus Text vom Typ String wird ein XmlDocument-Objekt, das auf dem gleichnamigen Typ basiert. Die Grundlage für die Typenkonvertierung ist eine Klasse, die sich von der PSTypeConverter-Klasse im System.Management.Automation ableitet. Benötigt man einen eigenen Typenkonvertierer, muss man „nur“ eine .Net-Assembly erstellen, in der diese Klasse abgeleitet und die Typenkovnertierung in der überschriebenen ConvertFrom-Methode durchgeführt wird.

Beispiele für den praktischen Einsatz von PsTypeConverter sind etwas schwer zu finden. Ein sehr guter Blog-Eintrag von Glenn Sizemore macht das Prinzip der Umsetzung deutlich und hat mich dazu motiviert, das Thema ebenfalls endlich einmal aufzugreifen (eigentlich steht das seit jenem PowerShell Deep Dive aus, der 2010 in Frankfurt a.M. stattfand):

http://practical-admin.com/blog/powershell-custom-types-type-conversion-and-ets/

Dynamische Typenkonvertierung an einem Beispiel

Das folgende Beispiel zeigt die Umsetzung eines Typenkonverters, der aus einer Ini-Datei ein Objekt macht, über das die Sektionen der Datei und die Einträge innerhalb einer Sektion zur Verfügung gestellt werden. Das Objekt ist ebenfalls Teil des Projekts. Voraussetzung für die Umsetzung der kleinen Übung sind Visual Studio (es kann auch eine ältere Version sein). Ich empfehle die aktuelle Version Visual Studio 2015 Community Edition. Auch wenn es im Folgenden um richtige Programmierung in der Programmiersprache C+ geht, muss man kein Profi-Entwickler sein, um die Umsetzung selber durchführen zu können. Theoretisch könnte man das kleine Projekt auch komplett in der PowerShell ISE umsetzen, doch müsste man dann auf den wertvollen C#-Debugger verzichten.

Schritt 1: Erstellen der Typenkonverter-Assembly

Im ersten Schritt wird mit Visual Studio eine .Net-Assembly erstellt, in der eine Klasse sich von PSTypeConverter ableitet. Voraussetzung ist, dass ein Verweis auf System.Management.Automation eingebunden wurde was am einfachsten über den Paket-Manager geschieht. Dieser wird über das Tools-Menü und die Einträge Nuget Package Manager und Package Manager Console geöffnet. Ein Install-Package System.Management.Automation fügt die PowerShell-Assembly hinzu.

Die vorhandene Klassendatei Class1.cs wird in PSIniTypeConverter.cs umbenannt und der folgende Befehlscode eingefügt:

Die Klasse enthält relativ wenige Befehle, da die eigentliche Konvertierung in der Klasse IniObject erledigt wird. Die wichtigste Methode ist ConvertFrom, denn hier wird die Konvertierung angestoßen. Die Abfrage auf den Typ des Parameters destinationType wäre in diesem Beispiel nicht erforderlich. Ich habe sie eingebaut damit deutlich wird, dass sich auch mehrere Typen konvertieren lassen.

Schritt 2: Ein neuer Typ wird definiert

Im nächsten Schritt wird eine weitere Klasse eingefügt mit dem Namen IniObject.cs. Diese Klasse definiert den Typen, in den ein String konvertiert werden soll. Die Klasse besitzt den folgenden Inhalt.

Damit ist die Programmierung bereits abgeschlossen. Das Projekt sollte ich zum jetzigen Zeitpunkt ohne Fehler erstellen lassen. Das Ergebnis ist eine Assembly-Datei mit dem Namen PSIniTypeConverter.dll.

Schritt 3: Die Assembly soll in einem PowerShell-Skript geladen werden

Um die PowerShell-Typenkonvertierung per F5-Taste im Rahmen von Visual Studio testen zu können, wird in den Projekteigenschaften im Register Debug dafür gesorgt, dass mit dem Projektstart Powershell.exe gestartet wird. Dazu muss unter „Start external programm“ der vollständige Pfad von Powershell.exe eingetragen werden.

In den Projekteigenschaften wird eingestellt, dass mit dem Projektstart die PowerShell startet

In den Projekteigenschaften wird eingestellt, dass mit dem Projektstart die PowerShell startet

über die „Command line arguments“ wird ein kleines PowerShell-Skript mit dem Namen „Init.ps1“ gestartet, das dem Projekt hinzuzgefügt wurde (dank der genialen PowerShell Tools for Visual Studio von Doug Finke gibt es eine Vorlage für Ps1-Dateien mit Intellisense), und über das u.a. die Assembly geladen wird:

Per „-noexit“ wird erreicht, dass das Konsolenfenster geöffnet bleibt. Da in diesem Fall ein Profilskript ausgeführt werden soll, fehlt der Schalter „-Noprofile“ (in der Regel ist es sinnvoll, dass keine Profilskripte gestartet werden).

Das PowerShell-Skript ist wie folgt aufgebaut:

Zuerst wird die Assemblydatei und damit der Typenkonverter per Import-Module geladen. Anschließend werden der Typ, der eine Ini-Datei repräsentieren soll, und der Typenkonverter über eine Typendefinitionsdatei bekannt gemacht (mehr dazu gleich). Außerdem wird ein Typenalias mit dem Namen „IniObject“ definiert, damit bei der Typenkonvertierung nicht jedes Mal der Namespace vorangestellt werden muss. Außerdem wird für einen ersten Test eine Variable IniText vordefiniert, die den Inhalt einer Ini-Datei darstellen soll.

Schritt 4: Der Typenkonvertierer wird bekannt gemacht


Damit die Powershell sowohl den neuen Typ PSIniTypeConverter.IniObject als auch den Typenkonvertierer PSIniTypeConverter.IniTypeConverter kennt, werden diese über eine Typendefinitionsdatei bekannt gemacht. Diese heißt IniObject.Types.ps1xml, wird im Rahmen des Skripts über das Update-TypeData-Cmdlet geladen. Die Typendefinitionsdatei ist wie folgt aufgebaut:

Wird das Projekt jetzt per F5 gestartet, wird die PowerShell-Konsole gestartet und das Skript wird ausgeführt. Außerdem liegt bereits eine Variable IniText vor.

Das Visual Studio-Projekt wurde erfolgreich erstellt

Das Visual Studio-Projekt wurde erfolgreich erstellt

Der folgende Aufruf sollte eine Typenkonvertierung von String nach IniObject durchführen.

Das Beispielprojekt gibt es unter der folgenden Adresse: psinitypeconverter.

Zusammenfassung

PowerShell-Typenkonvertierer sind eine innovative Idee, die die Übernahme von Textdaten, die einem beliebigen Format vorliegen können, vereinfachen. Mit einem einzigen Typenalias kann eine komplette Textdatei in PowerShell-Objekte konvertiert werden. Ohne diese Option müsste man die Daten eventuell Zeile für Zeile einlesen, zerlegen und daraus Objekte machen. Ob sich der Aufwand für eigene Typenkonvertierer wirklich lohnt sei einmal dahin gestellt. Da es für wichtige Datentypen, etwa IP-Adressen, bereits Konvertierer gibt, dürfte sich die Anzahl der echten Anwendungsfälle in Grenzen halten.

Das kleine Beispiel, das ich in diesem Blogpost vorgestellt habe, soll in erster Linie dazu dienen ein wichtiges Merkmnal der PowerShell, das sie seit der Version 1.0 besitzt, die dynamische Typenkonvertierung, besser nachvollziehen zu können.

HAL ist IBM – der unwiederlegbare Beweis

In Stanley Kubriks Science Fiction-Klassiker „Odysee im Weltraum“ aus dem Jahr 1968 (!) heißt der emotional einfühlsame Supercomputer an Bord des Raumschiffs HAL 9000. Angeblich ist HAL eine Anspielung auf IBM, das zur Zeit der Entstehung des Films ein Codewort für allumfassende Computerintelligenz gewesen sein dürfte (so wie heute Facebook). Ich habe das bislang nicht geglaubt, bis ich, weil ich nichts Besseres zu tun hatte, den folgenden PowerShell-Befehl eingehackt hatte:

10 Jahre PowerShell – mein persönliches Fazit

10 Jahre PowerShell bedeuten für mich einen Rückblick auf einen wichtigen Teil der letzten 10 Jahre meiner beruflichen Tätigkeiten. Wie für viele Menschen in der Branche hat auch die PowerShell mir neue Möglichkeiten eröffnet. Auch wenn der Ausblick anlässlich der 10th Anniversary-Party zur Zukunft der PowerShell leider etwas unspezifisch waren (etwa zur künftigen Rolle von SSH), gehe ich davon aus, dass in den nächsten 10 Jahren noch viel passieren wird.

Da 10 Jahre PowerShell auch für mich persönlich ein Grund zur Freude und zum Feiern ist, hat mir meine Frau eine kleine „Pauerschell-Torte“ gebacken. Vielen Dank!

10 Jahre PowerShell sind auch für mich ein Grund für eine kleine Feier

10 Jahre PowerShell sind auch für mich ein Grund für eine kleine Feier

10 Jahre PowerShell – Zwischenbilanz und ein Blick in die Zukunft

Am 14. November 2016 wurde die PowerShell 1.0 offiziell als Download freigegeen – damals noch etwas unfertig mit gerade 139 Cmdlets, ohne (direkte) AD-Unterstützung, ohne Module, ohne PS-Remoting, aber mit einer vollständigen Hilfe. Es hat ein paar Jahre gedauert bis sie von den Administratoren angenommen wurde, heute hat sich sie als ein Allround-Werkzeug etabliert, das in einigen Bereichen (Exchange Server) sogar alternativlos ist. In den Jahren ist die Funktionbalität stark angewachsen – alleine von Microsoft dürften die verschiedenenen Produktteams einige Tausend Cmdlets und Functions entwickelt haben (es ist zudem erstaunlich, wie viele PowerShell-Skripte bereits bei Windows 7 dabei waren und unbemerkt von den meisten Anwendern in den tiefen vom System32-Verzeichnis ihr Schattendasein fristeten).

Natürlich ist Quantität nicht autommatisch gleich Qualität, aber bei der PowerShell stimmt das Verhältnis. Das bei den von Microosft produzierten Cmdlets nur sehr wenig „Füllmaterial“ dabei ist macht der Umstand deutlich, dass Cmdlets für das Ein- und Auspacken von Zip-Dateien erst mit der Version 5.0 dazu kamen.

Mit der PowerShell hat sich der geistige Vater Jeffrey Snover, der bei Microsoft inzwischen nicht nur zum „Distinguished Engineer“ ernannt wurde, sondern seit ein paar Jahren auch die Windows Server-Gruppe leitet, ein Denkmal geschaffen.

Ich erinnere mich noch ganz gut als ich mich sehr früh morgens zu eimem Vortrag aufmachte, der anläßlich des Microsoft IT Forums im November 2006 in Barcelona stattfand, nur um aus erster Hand etwas über die neue PowerShell zu erfahren. Anstelle eines typiscchen jung-dynamischen Microsoft-Sprechers stand da ein etwas älterer Typ mit einer Krawatte (!) in einem Raum, der eher an einem Hörsaal erinnerte, hinter einem Tisch und redete mit eher monotoner Stimme. Die kleine Enttäuschung legte sich jedoch schnell wieder. Seit Jahren sind seine Vorträge, etwa der Klassiker „PowerShell Unplugged“, für mich ein Highlight auf jeder Microsoft-Konferenz, ob TechEd (z.B. jene, die 2009 in Berlin stattand, die PowerShell 2.0 war gerade erschienen, so dass der Vortrag voller Neuerungen war, auf die man lange gewartet hatte), Build oder jetzt Ignite. Alle diese Vorträge gibt es kurz danach auf Channel 9, so dass man längst nicht mehr irgendwo hin reisen oder gar früh aufstehen muss.

Wer sich auf kleine Reise in die Vergangenheit begeben möchte, findet auf Channel 9 sogar noch ein Interview mit Jeffrey Snover aus dem Jahr 2006:

https://channel9.msdn.com/showpost.aspx?postid=256994

Heute am 14. November begeht das PowerShell-Team das Jubiläum mit einer ganztägigen Konferenz, die auf Channel 9 live übertragen wird, und die einige ausgefallene Vortragsthemen umfasst:

https://channel9.msdn.com/Events/PowerShell-Team/PowerShell-10-Year-Anniversary

Neben Mitgliedern des Entwicklerteams werden auch paar PowerShell-Promis wie Ex-Scripting Guy Ed Wilson, Don Jones und Chrissy Le Mare (u.a. bekannt für die SQL Server Dba Tools) mit dabei sein.

Dazu noch ein Buchtipp mit Nostalgie-Faktor: Das Buch „Introducing the MSH Command Shell and Language“ von Andy Oakley war das allererste Buch zur PowerShell. Es ist auch über 12 Jahre später immer noch lesenswert, u.a. beschreibt der Autor wie man es schafft eine Konsolenausgabe in verschiedenen Farben auszugeben. Das Buch gibt es bei Amazon bereits ab 1 Cent – für echte PowerShell-Fans eigentlich ein „Must have“.

Es ist bemerkenswert, dass der 14.11 auch der 300te Todestag des deutschen Philosophen Gottfried Wilhelm Leibniz ist. Was hat ein Philosoph mit der PowerShell zu tun? Als Codenamen für die spätere PowerShell wählte Jeffrey Snover das Wort „Monad“ als Referenz auf die Theorie der Monaden des großen deutschen Denkers. Demnach ist ein Monad das kleinste Element, aus dem alles Leben und alle Materie besteht. Von Leibniz wird auch überliefert, dass er über sich selbst sagte: „Beim Erwachen hatte ich schon so viele Einfälle, dass der Tag nicht ausreichte, um sie niederzuschreiben.“ Wäre da nicht das selbst auferlegte „To ship is to choose“-Mantra des PowerShell-Teams, würde das im übertragenen Sinne auch auf Jeffrey Snover und seine Entwickler zutreffen.

SQL Server 2016-Installation – nicht so einfach wie es sein könnte

Nach dem Motto „1000 Mal probiert und irgendwann hat es dann Zoom“ gemacht ist mir nach mehreren Anläufen, verteilt über mehrere Wochen, endlich die Installation eines SQL Server 2016 (Express bzw. Developer) unter Windows Server 2016 gelungen – bislang trat jedes Mal kurz Schluss der genauso nichtssagende wie ärgerliche Fehler „Wait on the Database Engine recovery handle failed“ bzw. in der deutschen Übersetzung auf. Der Fehler tritt auch bei älteren SQL Server-Versionen unter anderen Windows-Betriebssystemsversionen auf.

Leider wird man von Microsoft in diesem Punkt komplett allein gelassen. Die angegebene URL führt zur einer Microsoft-Webseite, die in erster Linie Werbung für das neue Surface-Gerät enthält, die Logdatei wiederholt im Wesentlichen die Fehlermeldung und im TechNet-Forum gibt es nur allgemeine Antworten (wobei ich auch nicht ausführlich gesucht habe, da ich die Technet-Foren nur noch in Ausnahmefällen aufrufe).

Hilfe gab es wie sooft auf StackOverflow. Die Lösung lag offenbar nur daran, dass anstelle des vorgeschlagenen Systemkontos NT Service\MSSQL$SQLEXPRESS das Netzwerkonto NT-AUTORITÄT\Netzwerkdienst (NT AUTHORITY\NETWORK SERVICE) eingetragen werden muss. Danach lief die Installation glatt durch. Happy (auch wenn es eigentlich selbstverständlich sein sollte, dass sich ein SQL Server ohne Internet-Recherche installieren lässt- bei einem SQL Server 2000 wäre so etwas undenkbar gewesen). Warum die Angabe des anderen Systemkontos die Lösung für die Fehlermeldung ist, und ob es überhaupt sinnvoll ist das Netzwerkdienst-Konto zu verwenden kann ich Moment leider nicht beurteilen:(

Eine Liste aller Systemkonto erhält man in der PoweShell durch ein gwmi Win32_SystemAccount.

PowerGUI Script Editor – leider etwas schwierig zu finden

Der PowerGUI Script Editor war schon immer der etwas bessere PowerShell-Editor, vor allem in der Anfangszeit als die PowerShell ISE noch sehr einfach gestrickt war (und es im Grunde immer noch ist, sofern man nicht ISE Steroids arbeitet). Ein kleines Highlight ist die Möglichkeit aus einem Skript eine Exe-Datei machen können.

Lange Jahre wurde das Projekt von der Firma Quest gesponsert. Leider scheint die Entwicklung nach der Übernahnme durch Dell entweder eingestellt worden zu sein oder man hat es absichtlich gut versteckt.

Beim Downloadportal Softpedia findet man noch eine relativ aktuelle Version:

http://www.softpedia.com/get/Programming/File-Editors/Quest-PowerGUI.shtml

Noch ein Tipp zur Installation: Unbedingt die Verknüpfung zu Ps1-Dateien abwählen, da ansonsten mit jedem Bearbeiten einer Ps1-Datei (!) der dann doch etwas träge Script Editor startet.

Bei der Installation von PowerGUI Script Editor sollte die Verknüpfung zu Ps1-Dateien abgewählt werden

Bei der Installation von PowerGUI Script Editor sollte die Verknüpfung zu Ps1-Dateien abgewählt werden

PowerShell im Zusammenspiel mit WinForms und WPF – ein umfangreicher Artikel verrät viele Details

Ein PowerShell-Skript mit einer auf WinForms oder WPF basierenden Oberfläche auszustatten ist grundsätzlich nicht schwer und eher eine Fleißarbeit als eine technische Herausforderung sobald man den „Bogen“ raus hat. Wer mehr machen möchte als einen Button und eine TextBox anzuzeigen findet sich aber schnell in den Tiefen des Internets wieder und durchstreift stundenlang einschlägige Fornen.

Per Zufall bin ich auf einen überaus umfangreichen Artikel von einem gewissen Sergueik auf CodePlex gestoßen, in dem der Autor nahezu alle Möglichkeiten beschreibt, die per WinForms und WPF zur Verfügung stehen (ein paar wichtige Themen wie Datenbindung und vor allem wie man es schafft, reaktionsfreudige Oberflächen zu erstellen fehlen soweit ich es beurteilen kann). Der gannze Artikel ähnelt eher einem Buch. Es gibt zudem unzählige Beispiele, die einzeln auf GitHub zur Verfügung stehen. Teilweise wird es etwas zu speziell, da auch viel C#-Code im Spiel ist, und am Ende geht der Autor ausführlich auf das Testen von Web-Anwendungen mit dem Selenium Framework per PowerShell ein, aber insgesamt es ein beeindrucker Überblick, in dem sehr viel Arbeit steckt:

http://www.codeproject.com/Articles/799161/Dealing-with-Powershell-Inputs-via-Basic-Windows-F

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.