THEMA about_pipelines KURZBESCHREIBUNG Zusammenfassen von Befehlen in Pipelines in Windows PowerShell DETAILBESCHREIBUNG Eine Pipeline besteht aus einer Reihe von Befehlen, die durch Pipelineoperatoren (|, ASCII 124) verbunden sind. Jeder Pipelineoperator sendet die Ergebnisse des vorangehenden Befehls an den nächsten Befehl. Über Pipelines können Sie die von einem Befehl ausgegebenen Objekte zur Verarbeitung als Eingabe an einen anderen Befehl senden. Auch die Ausgabe dieses Befehls können Sie an einen weiteren Befehl senden. Auf diese Weise verfügen Sie über eine sehr leistungsstarke Befehlskette oder "Pipeline", die aus einer Reihe einfacher Befehle besteht. Beispiel: Befehl-1 | Befehl-2 | Befehl-3 In diesem Beispiel werden die von Befehl-1 ausgegebenen Objekte an Befehl-2 gesendet. Befehl-2 verarbeitet die Objekte und sendet sie an Befehl-3. Befehl-3 verarbeitet die Objekte und übergibt sie über die Pipeline. Da in der Pipeline keine weiteren Befehle enthalten sind, wird das Ergebnis an der Konsole angezeigt. In einer Pipeline werden die Befehle von links nach rechts in der Reihenfolge verarbeitet, in der sie angezeigt werden. Die Verarbeitung wird als einzelner Vorgang behandelt, und die Ausgabe wird angezeigt, sobald sie generiert wurde. Im Folgenden finden Sie ein einfaches Beispiel. Mit dem folgenden Befehl wird der Editor-Prozess ab und dann beendet. get-process notepad | stop-process Im ersten Befehl wird mit dem Cmdlet "Get-Process" ein Objekt abgerufen, das den Editor-Prozess darstellt. Mit einem Pipelineoperator (|) wird das Prozessobjekt an das Cmdlet "Stop-Process" gesendet, das den Editor-Prozess beendet. Der Befehl "Stop-Process" enthält keinen Namen oder ID-Parameter zum Angeben des Prozesses, da der angegebene Prozess über die Pipeline übergeben wird. Im Folgenden finden Sie ein praktisches Beispiel. Mit dieser Befehlspipeline werden die Textdateien im aktuellen Verzeichnis abgerufen, nur Dateien mit mehr als 10.000 Bytes Länge ausgewählt, diese nach Länge sortiert und anschließend der Name und die Länge jeder Datei in einer Tabelle angezeigt. Get-ChildItem -path *.txt | Where-Object {$_.length -gt 10000} | Sort-Object -property Length | Format-Table -property name, length Diese Pipeline besteht aus vier Befehlen in der angegebenen Reihenfolge. Der Befehl wird horizontal geschrieben, doch wird der Prozess in der folgenden Grafik vertikal dargestellt. Get-ChildItem -path *.txt | | ( FileInfo-Objekte ) | ( .txt ) | V Where-Object {$_.length -gt 10000} | | ( FileInfo-Objekte ) | ( .txt ) | ( Length > 10000 ) | V Sort-Object -property Length | | ( FileInfo-Objekte ) | ( .txt ) | ( Length > 10000 ) | ( Nach Länge sortiert ) | V Format-Table -property name, length | | ( FileInfo-Objekte ) | ( .txt ) | ( Length > 10000 ) | ( Nach Länge sortiert ) | (Als Tabelle formatiert) | V Name Length ---- ------ tmp1.txt 82920 tmp2.txt 114000 tmp3.txt 114000 VERWENDEN VON PIPELINES Die Windows PowerShell-Cmdlets wurden für die Verwendung in Pipelines entwickelt. Beispielsweise können Sie die Ergebnisse von Get-Cmdlet meist über die Pipeline an ein Aktions-Cmdlet (z. B. ein Set-, Start-, Stop- oder Rename-Cmdlet) mit demselben Substantiv übergeben. So können Sie über die Pipeline einen beliebigen Dienst vom Cmdlet "Get-Service" an das Cmdlet "Start-Service" oder "Stop-Service" übergeben (jedoch können Sie auf diese Weise keine deaktivierten Dienste erneut starten). Mit der folgenden Befehlspipeline wird der WMI-Dienst auf dem Computer gestartet: get-service wmi | start-service Die Cmdlets, mit denen Objekte der Windows PowerShell-Anbieter abgerufen und festgelegt werden, z. B. die Item-Cmdlets und ItemProperty-Cmdlets, wurden ebenfalls für die Verwendung in Pipelines entwickelt. Beispielsweise können Sie die Ergebnisse des Befehls "Get-Item" oder "Get-ChildItem" im Windows PowerShell-Registrierungsanbieter über die Pipeline an das Cmdlet "New-ItemProperty" übergeben. Mit dem folgenden Befehl wird dem Schlüssel "MeinUnternehmen" der neue Registrierungseintrag "AnzMitarbeiter" mit dem Wert 8214 hinzugefügt. get-item -path HKLM:\Software\MeinUnternehmen | new-Itemproperty -name AnzMitarbeiter -value 8124 Zahlreiche Dienstprogramm-Cmdlets, z. B. Get-Member, Where-Object, Sort-Object, Group-Object und Measure-Object, werden fast ausschließlich in Pipelines verwendet. An diese Cmdlets können Sie beliebige Objekte über die Pipeline übergeben. Sie können Sie z. B. alle Prozesse auf dem Computer über die Pipeline an den Befehl "Sort-Object" übergeben und sie nach der Anzahl der Handles im Prozess sortieren. get-process | sort-object -property handles Zudem können Sie sämtliche Objekte über die Pipeline an die Formatierungs-Cmdlets, z. B. Format-List und Format-Table, die Export-Cmdlets, z. B. Export-Clixml und Export-CSV, sowie die Out-Cmdlets, z. B. Out-Printer, übergeben. So können Sie den Prozess "Winlogon" über die Pipeline an das Cmdlet "Format-List" übergeben, um alle Eigenschaften des Prozesses in einer Liste anzuzeigen. get-process winlogon | format-list -property * Mit einem bisschen Übung werden Sie feststellen, dass Sie durch Kombination einfacher Befehle in Pipelines Zeit und Eingabeaufwand sparen und die Skripterstellung effizienter gestalten. FUNKTIONSWEISE VON PIPELINES Wenn Sie Objekte über die Pipeline übergeben, d. h., die Objekte in der Ausgabe eines Befehls an einen anderen Befehl senden, versucht Windows PowerShell, die über die Pipeline übergebenen Objekte einem der Parameter des empfangenden Cmdlets zuzuordnen. Dazu sucht die Parameterbindungskomponente von Windows PowerShell, mit der Eingabeobjekte Cmdlet-Parametern zuordnet werden, einen Parameter, der die folgenden Kriterien erfüllt: -- Der Parameter muss Eingaben von einer Pipeline akzeptieren (dies trifft nicht auf alle zu). -- Der Parameter muss den Typ des gesendeten Objekts oder einen Typ akzeptieren, in den das Objekt konvertiert werden kann. -- Der Parameter darf nicht bereits im Befehl verwendet werden. Das Cmdlet "Start-Service" beispielsweise verfügt über zahlreiche Parameter, doch nur zwei von diesen, Name und InputObject akzeptieren Pipelineeingaben. Der Name-Parameter akzeptiert Zeichenfolgen, und der InputObject-Parameter akzeptiert Dienstobjekte. Deshalb können Sie Zeichenfolgen und Dienstobjekte (sowie Objekte mit Eigenschaften, die in Zeichenfolgen- und Dienstobjekte konvertiert werden können) über die Pipeline an Start-Service übergeben. Wenn die Parameterbindungskomponente von Windows PowerShell die über die Pipeline übergebenen Objekte keinem Parameter des empfangenden Cmdlets zuordnen kann, kann der Befehl nicht ausgeführt werden, und Sie werden von Windows PowerShell aufgefordert, die fehlenden Parameterwerte einzugeben. Sie können nicht erzwingen, dass die Parameterbindungskomponente die über die Pipeline übergebenen Objekte einem bestimmten Parameter zuordnet, Sie können nicht einmal einen Parameter vorschlagen. Stattdessen verwaltet die Logik der Komponente den Pipelinevorgang so effizient wie möglich. EINZELVERARBEITUNG Das Übergeben von Objekten über die Pipeline an einen Befehl ähnelt dem Senden von Objekten mit einem Parameter des Befehls. Beispielsweise können Sie Objekte, die die Dienste auf dem Computer darstellen, über die Pipeline an den Befehl "Format-Table" übergeben: get-service | format-table -property name, dependentservices Dies ähnelt dem Speichern der Dienstobjekte in einer Variablen und dem Senden des Dienstobjekts mit dem InputObject-Parameter von Format-Table: $services = get-service format-table -inputobject $services -property name, dependentservices Es ähnelt auch dem Einbetten des Befehls im Parameterwert: format-table -inputobject (get-service wmi) -property name, dependentservices Jedoch besteht ein wichtiger Unterschied. Wenn Sie mehrere Objekte über die Pipeline an einen Befehl übergeben, sendet Windows PowerShell die Objekte einzeln an den Befehl. Wenn Sie einen Befehlsparameter verwenden, werden die Objekte als einzelnes Arrayobjekt gesendet. Dieser scheinbar technische Unterschied kann interessante und manchmal nützliche Folgen haben. Wenn Sie z. B. mehrere Prozessobjekte vom Cmdlet "Get-Process" über die Pipeline an das Cmdlet "Get-Member" übergeben, sendet Windows PowerShell jedes Prozessobjekt einzeln an Get-Member. Get-Member zeigt die .NET-Klasse (den Typ) der Prozessobjekte und deren Eigenschaften und Methoden an. (Get-Member entfernt Duplikate, wenn alle Objekte vom gleichen Typ sind, wird daher nur ein Objekttyp angezeigt.) In diesem Fall zeigt Get-Member die Eigenschaften und Methoden jedes Prozessobjekts an, d. h. ein System.Diagnostics.Process-Objekt. get-process | get-member TypeName: System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Handles AliasProperty Handles = Handlecount Name AliasProperty Name = ProcessName NPM AliasProperty NPM = NonpagedSystemMemorySize ... Wenn Sie jedoch den InputObject-Parameter von Get-Member verwenden, empfängt Get-Member ein Array von System.Diagnostics. Process-Objekten als einzelne Einheit, und es werden die Eigenschaften eines Objektarrays angezeigt. (Beachten Sie das Arraysymbol ([]) nach dem Typnamen von System.Object.) get-member -inputobject (get-process) TypeName: System.Object[] Name MemberType Definition ---- ---------- ---------- Count AliasProperty Count = Length Address Method System.Object& Address(Int32 ) Clone Method System.Object Clone() ... Dies stellt möglicherweise nicht das von Ihnen beabsichtigte Ergebnis dar, aber sobald Sie die Funktionsweise erkannt haben, können Sie es problemlos verwenden. Ein Array von Prozessobjekten verfügt beispielsweise über eine Count-Eigenschaft, mit der Sie die Anzahl der Prozesse auf dem Computer zählen können. (get-process).count Dieser Unterschied kann wichtig sein, vergessen Sie daher nicht, dass Objekte einzeln übermittelt werden, wenn Sie diese über die Pipeline an ein Cmdlet übergeben. PIPELINEEINGABEN AKZEPTIEREN Um Objekte in einer Pipeline zu empfangen, muss das empfangende Cmdlet einen Parameter aufweisen, der Pipelineeingaben akzeptiert. Sie können den Befehl "Get-Help" mit dem Full-Parameter oder dem Parameter-Parameter verwenden, um ggf. die Parameter eines Cmdlet zu bestimmen, die Pipelineeingaben akzeptieren. In der Standardanzeige von Get-Help wird das Element "Pipelineeingaben akzeptieren" in einer Tabelle von Parameterattributen angezeigt. Diese Tabelle wird nur angezeigt, wenn Sie den Full-Parameter oder den Parameter-Parameter des Cmdlet "Get-Help" verwenden. Wenn Sie z. B. bestimmen möchten, welcher Parameter des Cmdlet "Start-Service" Pipelineeingaben akzeptiert, geben Sie Folgendes ein: get-help start-service -full get-help start-service -parameter * In der Hilfe für das Cmdlet "Start-Service" wird z. B. angezeigt, dass der Name-Parameter und der InputObject-Parameter Pipelineeingaben akzeptieren. Alle anderen Parameter weisen in der Zeile "Pipelineeingaben akzeptieren?" den Wert "False" auf. -name <string[]> Gibt die Dienstnamen für die zu startenden Dienste an. Der Parametername ist optional. Sie können "-Name" oder den zugehörigen Alias "-ServiceName" verwenden oder aber den Parameternamen auslassen. Erforderlich? true Position? 1 Standardwert --> Pipelineeingaben akzeptieren? true (ByValue, ByPropertyName) Platzhalterzeichen akzeptieren? true -inputObject <ServiceController[]> Gibt ServiceController-Objekte an, die die zu startenden Dienste darstellen. Geben Sie eine Variable ein, die die Objekte enthält, oder geben Sie einen Befehl oder einen Ausdruck ein, mit dem die Objekte abgerufen werden. Erforderlich? false Position? benannt Standardwert --> Pipelineeingaben akzeptieren? true (ByValue) Platzhalterzeichen akzeptieren? false Dies bedeutet, dass Sie Objekte (PsObjects) über die Pipeline an das Cmdlet "Where-Object" übergeben können und dieses von Windows PowerShell dem InputObject-Parameter zugeordnet wird. METHODEN ZUM AKZEPTIEREN VON PIPELINEEINGABEN Parameter von Cmdlets können Pipelineeingaben mit zwei verschiedenen Methoden akzeptieren: -- ByValue: Parameter, die Eingaben "nach Wert" akzeptieren, können über die Pipeline übergebene Objekte mit dem gleichen .NET-Typ wie die entsprechenden Parameterwerte oder Objekte akzeptieren, die in diesen Typ konvertiert werden können. Der Name-Parameter von Start-Service akzeptiert z. B. Pipelineeingaben nach Wert. Er akzeptiert Zeichenfolgenobjekte oder Objekte, die in Zeichenfolgen konvertiert werden können. -- ByPropertyName: Parameter, die Eingaben "nach Eigenschaftenwert" akzeptieren, können über die Pipeline übergebene Objekte nur akzeptieren, wenn eine Eigenschaft des Objekts denselben Namen wie der Parameter besitzt. Der Name-Parameter von Start-Service akzeptiert z. B. Objekte mit einer Name-Eigenschaft. (Zum Auflisten der Eigenschaften eines Objekts übergeben Sie dieses über die Pipeline an das Cmdlet "Get-Member".) Einige Parameter akzeptieren Objekte nach Wert oder nach Eigenschaftennamen. Diese Parameter wurden so entworfen, dass sie Eingaben von der Pipeline problemlos akzeptieren. ERMITTELN VON PIPELINEFEHLERN Wenn ein Befehl aufgrund eines Pipelinefehlers nicht ordnungsgemäß ausgeführt wird, können Sie den Fehler untersuchen und den Befehl umschreiben. Mit dem folgenden Befehl wird z. B. versucht, einen Registrierungseintrag aus einem Registrierungsschlüssel in einen anderen zu verschieben, indem mit dem Cmdlet "Get-Item" der Zielpfad abgerufen und dann der Pfad über die Pipeline an das Cmdlet "Move-ItemProperty" übergeben wird. Genauer gesagt wird in diesem Befehl mit dem Cmdlet "Get-Item" der Zielpfad abgerufen. Das Ergebnis wird mit einem Pipelineoperator an das Cmdlet "Move-ItemProperty" gesendet. Mit dem Befehl "Move-ItemProperty" werden der aktuelle Pfad und der Name des zu verschiebenden Registrierungseintrags angegeben. get-item -path hklm:\software\meinunternehmen\vertrieb | move-itemproperty -path hklm:\software\meinunternehmen\design -name produkt Der Befehl wird nicht ordnungsgemäß ausgeführt, und von Windows PowerShell wird die folgende Fehlermeldung angezeigt: Move-ItemProperty: Das Eingabeobjekt kann nicht an die Parameter für den Befehl gebunden werden, da der Befehl keine Pipelineeingaben akzeptiert oder die Eingabe und deren Eigenschaften mit keinem Parameter übereinstimmen, der Pipelineeingaben akzeptiert. Bei Zeile:1 Zeichen:23 + $a | move-itemproperty <<<< -path hklm:\software\meinunternehmen\design -name produkt Wenn Sie eine Überprüfung ausführen möchten, verwenden Sie das Cmdlet "Trace-Command", um die Komponente ParameterBinding von Windows PowerShell nachzuverfolgen. Mit dem folgenden Befehl wird die Komponente "ParameterBinding" während der Befehlsverarbeitung nachverfolgt. Mit dem -phost-Parameter werden die Ergebnisse an der Konsole angezeigt, und mit dem -filepath-Parameter werden diese zur späteren Referenz an die Datei "debug.txt" gesendet. trace-command -name parameterbinding -expression {get-item -path hklm:\software\meinunternehmen\vertrieb | move-itemproperty -path hklm:\software\meinunternehmen\design -name produkt} -pshost -filepath debug.txt Die Ergebnisse der Ablaufverfolgung sind umfangreich, doch zeigen diese die an das Cmdlet "Get-Item" gebundenen Werte und dann die benannten Werte, die an das Cmdlet "Move-ItemProperty" gebunden sind. ... BIND NAMED cmd line args [Move-ItemProperty] BIND arg [hklm:\software\meinunternehmen\design] to parameter [Pfad] ... BIND arg [produkt] to parameter [Name] .... BIND POSITIONAL cmd line args [Move-ItemProperty] ... Schließlich wird gezeigt, dass der Versuch, den Pfad an den Destination-Parameter von Move-ItemProperty zu binden, nicht erfolgreich war. ... BIND PIPELINE object to parameters: [Move-ItemProperty] PIPELINE object TYPE = [Microsoft.Win32.RegistryKey] RESTORING pipeline parameter's original values Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION ... Zum Untersuchen des Fehlers zeigen Sie mit dem Cmdlet "Get-Help" die Attribute des Destination-Parameters an. Mit dem folgenden Befehl rufen Sie ausführliche Informationen zum Destination- Parameter ab. get-help move-itemproperty -parameter destination Die Ergebnisse zeigen, dass Destination Pipelineeingaben nur "nach Eigenschaftennamen" akzeptiert. Das über die Pipeline übergebene Objekt muss daher die Destination-Eigenschaft besitzen. -destination <Zeichenfolge> Gibt den Pfad zum Zielspeicherort an. Erforderlich? true Position? 2 Standardwert Pipelineeingaben akzeptieren? true (ByPropertyName) Platzhalterzeichen akzeptieren? true Um alle Eigenschaften des über die Pipeline an das Cmdlet "Move-ItemProperty" übergebenen Objekts anzuzeigen, übergeben Sie es über die Pipeline an das Cmdlet "Get-Member". Im folgenden Befehl werden die Ergebnisse des ersten Befehlsteils über die Pipeline an das Cmdlet "Get-Member" übergeben. get-item -path hklm:\software\meinunternehmen\vertrieb | get-member Die Ausgabe zeigt, dass es sich bei dem Element um ein Microsoft.Win32.RegistryKey handelt, der keine Destination-Eigen- schaft besitzt. Dies erklärt das Fehlschlagen des Befehls. Zum Korrigieren des Befehls muss das Ziel im Cmdlet "Move-ItemProperty" angegeben werden. Mit dem Befehl "Get-ItemProperty" können Sie den Pfad abrufen, jedoch müssen der Name und das Ziel im Move-ItemProperty-Teil des Befehls angegeben werden. get-item -path hklm:\software\meinunternehmen\design | move-itemproperty -dest hklm:\software\meinunternehmen\design -name produkt Um die ordnungsgemäße Funktion des Befehls zu überprüfen, verwenden Sie den Befehl "Get-ItemProperty": get-itemproperty hklm:\software\meinunternehmen\vertrieb Die Ergebnisse zeigen, dass der Registrierungseintrag "Produkt" in den Schlüssel "Vertrieb" verschoben wurde. PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\meinun ternehmen\vertrieb PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\meinun ternehmen PSChildName : vertrieb PSDrive : HKLM PSProvider : Microsoft.PowerShell.Core\Registry Produkt : 18 SIEHE AUCH about_objects about_parameters about_command_syntax about_foreach