Tags: PowerShell
Gelegentlich besteht in einer PowerShell-Pipeline die Notwendigkeit, die Ausgabe eines Cmdlets aufzubewahren, um diese Daten in einem nachfolgenden Kommando zu verwenden. Für diesen Zweck verfügen alle Cmdlets über die Parameter OutVariable und PipelineVariable. Letztere ist nur temporär verfügbar.
Eine gängige Anforderung in einer PowerShell-Pipeline besteht darin, dass man ein Zwischenergebnis in eine Datei umleiten und zusätzlich an ein weiteres Cmdlet durchreichen möchte. In diesem Fall teilt das Cmdlet Tee-Object den Datenfluss auf zwei Output-Kanäle.
Wenn man jedoch das Zwischenergebnis im übernächsten Kommando oder nach dem Durchlaufen der Pipeline verwenden möchte, dann ist Tee-Object dafür nicht geeignet. Man könnte sich ein Szenario so vorstellen, dass man in der Pipeline
Befehl_1 | Befehl_2 | Befehl_3 | Befehl_4
die Ausgabe von Befehl_2 in Befehl_4 verarbeiten will.
Cmdlet-Ausgabe in OutVariable speichern
Die Lösung besteht im allgemeinen Parameter OutVariable.
Befehl_1 | Befehl_2 -OutVariable MyVar | Befehl_3 | Befehl_4 mit MyVar
Wie man sieht, verzichtet man beim Wert für den Parameter OutVariable (Alias "ov") auf das führende $-Zeichen im Variablennamen. Die in diesem Musteraufruf eingesetzte Variable $MyVar besteht auch nach dem Ende der Pipeline.
Das folgende Beispiel ermittelt alle PDF-Dateien im aktuellen Verzeichnis, filtert sie nach Größe und gibt deren Namen aus. Wenn man im Anschluss daran die aufsummierte Größe der Dateien anzeigen möchte, dann müsste man die ersten beiden Kommandos der Pipeline erneut aufrufen.
Wenn man jedoch das Ergebnis von Where-Object in einer Variablen speichert, dann kann man sich diesen Aufwand sparen:
Get-ChildItem *.pdf | where Length -lt 100000 -OutVariable PDF |
select name
$PDF | measure -Property Length -sum |
select @{n="Dateien";e={$_.count}}, `
@{n="Größe in MB";e={[math]::round($_.sum / 1MB, 2)}}
In $PDF befindet sich die komplette Ausgabe von Get-ChildItem für alle Dateien, die größer als 100K Byte sind. Die Variable ist vom .NET-Datentyp ArrayList, wie man mit
$PDF.GetType()
leicht feststellen kann.
Auf die einzelnen Elemente kann man über den Index zugreifen, also entweder in der Form
$PDF[0]
oder
$PDF.Item(0)
Nachdem OutVariable immer vom Typ ArrayList ist, eignet sich diese Variable nicht als genereller Ersatz für eine Zuweisung, weil dies zu unerwarteten Nebeneffekten führen kann. Man sollte also zum Beispiel
$cim = New-CimSession -ComputerName server1 -Credential contoso\user
nicht durch
New-CimSession -ComputerName server1 -Credential contoso\user -ov cim
ersetzen, nur weil man sich dadurch etwas Tipparbeit ersparen kann.
PipelineVariable
Der Parameter PipelineVariable (Alias "pv") erfüllt im Wesentlichen den gleichen Zweck wie OutVariable, hat aber einen eingeschränkten Gültigkeitsbereich. Sie ist, wie der Name vermuten lässt, nur innerhalb der Pipeline verfügbar.
Zum anderen ist sie nicht vom Typ ArrayList, sondern erhält den nativen Datentyp des Rückgabewerts eines Cmdlets.
Im folgenden Beispiel sollen der Nachname und die Gruppenmitgliedschaften eines AD-Users ausgegeben werden.
Nach der Ausführung von Select-Object mit dem Parameter ExpandProperty enthält die Pipeline nur mehr die Liste der AD-Gruppen als Strings, das Ergebnis von Get-ADUser ist zu diesem Zeitpunkt für eine weitere Verarbeitung nicht mehr verfügbar.
Hier hilft der Einsatz von PipelineVariable:
Get-ADUser -Filter 'name -like "b*"' -Properties * -pv u |
select -ExpandProperty MemberOf |
select @{n="Nachname";e={ $u.surname }}, @{n="Gruppen";e={ $_ }}
Die Variable $u enthält dann das Array mit den ADUSer-Objekten. Auf sie kann im abschließenden Aufruf von Select-Object zurückgreifen.
Zusammenfassung
Damit man im Datenstrom durch eine PowerShell-Pipeline auf ein vorheriges Zwischenergebnis zurückgreifen kann, unterstützen alle Cmdlets die Parameter OutVariable und PipelineVariable, um ihre Ausgabe in einer Variablen zu speichern. Beiden übergibt man einen Namen ohne das führende $-Zeichen.
OutVariable ist auch noch nach der Beendigung der Pipeline verfügbar und hat immer den Datentyp ArrayList. Der Gültigkeitsbereich von PipelineVariable beschränkt sich hingegen auf die Pipeline und die Variable behält den Datentyp des Cmdlet-Ergebnisses.
Täglich Know-how für IT-Pros mit unserem Newsletter
Verwandte Beiträge
Weitere Links