Mit Windows 10 und Server 2016 kommt automatisch auch PowerShell 5.0 auf die PCs. Bis Windows 7/Server 2008 ist es sogar einfach nachinstallierbar. Eine wichtige Neuerung ist der Information Stream bzw. Informationkanal, mit dem man umfangreiche Informationen transportieren kann.
Index
PowerShell Streams bis 4.0
Wie vielen bekannt, unterstützte PowerShell in den Versionen 1.0 bis 4.0 bisher fünf verschiedene Kanäle, die man mit unterschiedlichen CmdLets bedienen konnte:
Mit PowerShell 5.0 kommt ein sechster Kanal hinzu, der Information Stream. Schauen wir uns zunächst an, wie bis in Version 4.0 Skripte erstellt wurden.
In den meisten PowerShell-Skripten, die ich gesehen habe, werden so gut wie immer Stream 1 und 2 verwendet. Manchmal wird auch der dritte Kanal benutzt, aber so gut wie nie Nummer 4 und 5. Teilweise lassen diese sich auch nur umständlich verwenden.
Die Nummer 1, also Output/Success, ist dagegen meist wortwörtlich vollgestopft mit Informationen. So gut wie jede Ausgabe an die Oberfläche, wie zum Beispiel durch Write-Host, schreibt auf diesen Stream. Andere Streams können aber auch genutzt werden.
Write-Verbose
Nehmen wir zum Beispiel Write-Verbose. Probiert man das CmdLet aus, sieht man keine Ausgabe. Es sieht zunächst so aus, als ob es nicht funktionieren würde.
Das liegt daran, dass man PowerShell bei bestimmten Streams erst sagen muss, dass man die Information auch auf der Oberfläche sehen will. Bei Write-Verbose ist das die globale Variable $VerbosePreference. Diese steht standardmäßig auf „SilentlyContinue“. Damit man die Ausgabe sehen kann, muss sie zuerst auf „Continue“ gestellt werden.
Streams können aber auch umleitet werden. Dazu hängt man den >&-Operator an das CmdLet an und schreibt auf die linke Seite die Nummer des Streams, von dem man kommt und auf die rechte Seite die Nummer des Streams, auf den man weiterleiten möchte.
Zum Beispiel kann ich meine Nachricht von Write-Verbose (Stream 4) auf den Output/Success-Stream (Stream 1) weiterleiten. Meine Nachricht wird nun angezeigt, selbst wenn meine $VerbosePreference auf „SilentlyContinue“ steht.
So viel zu den Streams im Allgemeinen bis zur PowerShell Version 4.0.
In PowerShell 5.0 kommt nun ein neuer, sehr interessanter Stream an Platz Nummer 6 hinzu: Der Information Stream.
Der neue Information Stream / Write-Information
Microsoft hat anscheinend mitbekommen, dass die „Verschmutzung“ des Output-Streams ein Problem ist. Wahrscheinlich hat MS aus diesem Grund den Information Stream eingeführt.
Write-Host schreibt nun standardmäßig auch auf diesen Stream und nicht mehr auf Stream 1.
Zusätzlich verwendet Write-Host intern jetzt auch ein neues CmdLet: Write-Information. Dieses ist auch für die direkte Verwendung interessant. Der neue Stream hat nämlich nicht nur den Vorteil, dass er den Output-Stream entlastet. Mit Write-Information bietet er mir auch die Möglichkeit, komplette Objekte auf den Stream zu schreiben, die zusätzlich noch mit Metainformationen angereichert werden.
Im Grunde funktioniert das CmdLet erst einmal wie Write-Host. Der Unterschied ist jedoch, dass wie bei Write-Verbose, die Ausgabe auf der Oberfläche eingeschalten werden muss. Das geht entweder direkt mit einem Parameter beim Aufruf oder über die globale Variable $InformationPreference.
Neben einem normalen String ist es aber auch möglich, ganze Objekte auf den Information Stream zu schreiben:
Das sieht natürlich erst einmal wenig beeindruckend aus, schließlich kann ich mit Write-Host genau dasselbe erreichen. Hier kommt uns jetzt der Information Stream zugute: Write-Information schreibt die Objekte als InformationRecord auf den Stream und sie bleiben auf diesem verfügbar. Es muss nur eine Variable für das Write-Information CmdLet festgelegt werden, in dem der Record abgespeichert werden soll. Auf diesen kann ich dann ganz einfach zugreifen.
Auslesen des InformationRecord
In meiner InformationVariable $iv speichere ich die Informationen ab, die Write-Information von dem Objekt hat. Jetzt könnten Sie sagen: „Das ist doch aber genau dasselbe, wie der AD-User in $a!“
Ja und Nein – $iv ist ein InformationRecord. Wenn wir uns die Eigenschaften des Objekts näher anschauen, gibt es ein paar mehr Informationen preis.
Man sieht schnell: Wenn ich nur $iv ausgebe, gibt mir PowerShell standardmäßig die MessageData-Eigenschaft zurück, in der sich natürlich unser AD-User befindet. Der InformationRecord selbst allerdings bietet noch ein paar mehr Informationen, wie der ausführende Nutzer und Computer, einen Zeitstempel und Tags, die ich beim Schreiben der Information selbst festlegen kann. Das alles sind Informationen, die man natürlich wunderbar fürs Logging verwenden kann.
Nehmen wir zum Beispiel dieses einfache Skript, dass zwei AD-User ausliest und ihre Beschreibungen ändert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Function Change-Desciptions { [cmdletbinding()] Param() $InformationPreference = "Continue" #User A change description $userA = Get-ADUser hans.wurst -Properties Description Write-Information -MessageData $userA -Tags "UserRead" $userA.description = "This is Hans Wurst!" Set-ADUser $userA -Description $userA.description Write-Information $userA -Tags "UserWrite" #User B change description $userB = Get-ADUser albert.einstein -Properties Description Write-Information -MessageData $userB -Tags "UserRead" $userB.description = "This is Albert Einstein!" Set-ADUser $userB -Desciption $userB.description Write-Information $userB -Tags "UserWrite" } |
Ich habe alles in eine Funktion verpackt, der ich dank des CmdLet-Bindings meine Informationvariable für alle Write-Information-Aufrufe mitgeben kann. Am Ende habe ich dann ein Array in dieser Informationvariablen, dass genau vier InformationRecords von meinen vier Aufrufen an Write-Information enthalten wird.
Der Screenshot zeigt wie es aussieht, wenn ich das Skript einbinde und die Funktion aufrufe und mir anschließend meine Informationsvariable ausgeben lasse.
Auswerten des InformationRecords
Die Informationen kann ich jetzt nach Belieben herausfiltern. Ich könnte mir zum Beispiel alle Einträge mit einem bestimmten Tag ausgeben lassen.
Ich kann mir auch zeitlich sortiert ausgeben lassen, wie sich Beschreibungen meiner Nutzer geändert haben:
Da fällt natürlich gleich etwas auf: Überall stehen dieselben Descriptions. Das mag erst merkwürdig aussehen, ist aber recht einfach erklärt. Wir schreiben in der Funktion zwei Mal $userA und zwei Mal $userB mit Write-Information. PowerShell verhält sich hier, wie man es von einer .NET-basierenden Sprache erwartet: Dann sind keine Kopien von Objekten, sondern Referenzen, quasi Zeiger, die alle auf dasselbe Objekt zeigen. Das heißt natürlich, wenn man das Objekt an einer Stelle ändert, ändert es sich an allen anderen mit.
Man könnte, damit diese Auswertung funktioniert, eine echte Kopie an Write-Information übergeben oder nur den benötigten String anstatt des gesamten Objekts, wenn man nur die Description braucht. Zum Beispiel so:
Der Information Stream macht also genau das, was man namentlich vom ihm erwartet: Er stellt Informationen und Meta-Daten zu den Informationen zur Verfügung. Wertet man diese richtig aus, kann man sich individuell Nachrichten an den Nutzer zusammenbauen oder sinnvolle Einträge in ein Log ausgeben.
FirstAttribute AG – Ihr Microsoft Consulting Partner
Wir unterstützen Sie bei PowerShell Scripting Fragen
Nehmen Sie Kontakt zu uns auf, wir hören Ihnen gern zu.
Leave a Reply
<p>Danke für Ihre Anregungen, Fragen und Hinweise.<br/>Infos zum <a href="https://www.active-directory-faq.dekontakt/">Datenschutz</a></p>