about_Pipelines
Kurze Beschreibung
Kombinieren von Befehlen in Pipelines in powerShell
Lange Beschreibung
Eine Pipeline ist eine Reihe von Befehlen, die von Pipelineoperatoren () (|
ASCII 124) verbunden sind. Jeder Pipelineoperator sendet die Ergebnisse des vorherigen Befehls an den nächsten Befehl.
Die Ausgabe des ersten Befehls kann zur Verarbeitung als Eingabe an den zweiten Befehl gesendet werden. Und diese Ausgabe kann an einen weiteren Befehl gesendet werden. Das Ergebnis ist eine komplexe Befehlskette oder Pipeline , die aus einer Reihe einfacher Befehle besteht.
Beispiel:
Command-1 | Command-2 | Command-3
In diesem Beispiel werden die objekte, die Command-1
ausgegeben werden, an Command-2
.
Command-2
verarbeitet die Objekte und sendet sie an Command-3
. Command-3
verarbeitet die Objekte und sendet sie an die Pipeline. Da in der Pipeline keine weiteren Befehle vorhanden sind, werden die Ergebnisse in der Konsole angezeigt.
In einer Pipeline werden die Befehle von links nach rechts verarbeitet. Die Verarbeitung wird als einzelner Vorgang behandelt und die Ausgabe wird angezeigt, während sie generiert wird.
Hier ist ein einfaches Beispiel. Der folgende Befehl ruft den Editor-Prozess ab und beendet ihn.
Beispiel:
Get-Process notepad | Stop-Process
Der erste Befehl verwendet das Get-Process
Cmdlet, um ein Objekt abzurufen, das den Editorprozess darstellt. Es verwendet einen Pipelineoperator (|
), um das Prozessobjekt an das Stop-Process
Cmdlet zu senden, wodurch der Editor-Prozess beendet wird. Beachten Sie, dass der Stop-Process
Befehl keinen Parameter "Name" oder "ID" enthält, um den Prozess anzugeben, da der angegebene Prozess über die Pipeline übermittelt wird.
Dieses Pipelinebeispiel ruft die Textdateien im aktuellen Verzeichnis ab, wählt nur die Dateien aus, die mehr als 10.000 Bytes lang sind, sortiert sie nach Länge und zeigt den Namen und die Länge jeder Datei in einer Tabelle an.
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. Die folgende Abbildung zeigt die Ausgabe jedes Befehls, während er an den nächsten Befehl in der Pipeline übergeben wird.
Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| ( Length > 10000 )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
| ( Formatted in a table )
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
Verwenden von Pipelines
Die meisten PowerShell-Cmdlets sind für die Unterstützung von Pipelines konzipiert. In den meisten Fällen können Sie die Ergebnisse eines Get-Cmdlets an ein anderes Cmdlet desselben Substantivs weiterleiten.
Sie können z. B. die Ausgabe des Get-Service
Cmdlets an die Start-Service
Cmdlets oder Stop-Service
Cmdlets weiterleiten.
Diese Beispielpipeline startet den WMI-Dienst auf dem Computer:
Get-Service wmi | Start-Service
Ein weiteres Beispiel: Sie können die Ausgabe des Oder Get-ChildItem
innerhalb des Get-Item
PowerShell-Registrierungsanbieters an das New-ItemProperty
Cmdlet weiterleiten. In diesem Beispiel wird dem Registrierungsschlüssel "MyCompany" ein neuer Registrierungseintrag "NoOfEmployees" mit dem Wert 8124 hinzugefügt.
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Viele der Hilfsprogramm-Cmdlets, z Get-Member
. B. , Where-Object
, Sort-Object
, Group-Object
und Measure-Object
werden fast ausschließlich in Pipelines verwendet. Sie können jeden Objekttyp an diese Cmdlets weiterleiten. In diesem Beispiel wird gezeigt, wie alle Prozesse auf dem Computer nach der Anzahl der geöffneten Handles in den einzelnen Prozessen sortiert werden.
Get-Process | Sort-Object -Property handles
Sie können Objekte an die Formatierungs-, Export- und Ausgabe-Cmdlets weiterleiten, z Format-List
. B. an , , Format-Table
, Export-Clixml
, Export-CSV
und Out-File
.
In diesem Beispiel wird gezeigt, wie Sie mithilfe des Format-List
Cmdlets eine Liste der Eigenschaften für ein Prozessobjekt anzeigen.
Get-Process winlogon | Format-List -Property *
Sie können auch die Ausgabe systemeigener Befehle an PowerShell-Cmdlets weiterleiten. Zum Beispiel:
PS> ipconfig.exe | Select-String -Pattern 'IPv4'
IPv4 Address. . . . . . . . . . . : 172.24.80.1
IPv4 Address. . . . . . . . . . . : 192.168.1.45
IPv4 Address. . . . . . . . . . . : 100.64.108.37
Wichtig
Die Datenströme "Success " und "Error " ähneln den Stdin- und Stderr-Streams anderer Shells. Stdin ist jedoch nicht mit der PowerShell-Pipeline für eingaben verbunden. Weitere Informationen finden Sie unter about_Redirection.
Mit etwas Übung werden Sie feststellen, dass das Kombinieren einfacher Befehle in Pipelines Zeit und Eingabe spart und macht Ihre Skripterstellung effizienter.
Funktionsweise von Pipelines
In diesem Abschnitt wird erläutert, wie Eingabeobjekte an Cmdlet-Parameter gebunden und während der Pipelineausführung verarbeitet werden.
Akzeptiert Pipelineeingaben
Zur Unterstützung der Pipelining muss das empfangende Cmdlet über einen Parameter verfügen, der Pipelineeingaben akzeptiert. Verwenden Sie den Get-Help
Befehl mit den Optionen "Vollständig " oder "Parameter ", um zu bestimmen, welche Parameter eines Cmdlets Pipelineeingaben akzeptieren.
Um beispielsweise zu bestimmen, welche Parameter des Start-Service
Cmdlets Pipelineeingaben akzeptiert, geben Sie Folgendes ein:
Get-Help Start-Service -Full
or
Get-Help Start-Service -Parameter *
Die Hilfe für das Start-Service
Cmdlet zeigt, dass nur die Parameter "InputObject " und "Name " Pipelineeingaben akzeptieren.
-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <String[]>
Specifies the service names for the service to be started.
The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
Wenn Sie Objekte über die Pipeline senden, Start-Service
versucht PowerShell, die Objekte den Parametern InputObject und Name zuzuordnen.
Methoden zum Akzeptieren von Pipelineeingaben
Cmdlets-Parameter können Pipelineeingaben auf eine von zwei verschiedenen Arten akzeptieren:
ByValue: Der Parameter akzeptiert Werte, die dem erwarteten .NET-Typ entsprechen oder in diesen Typ konvertiert werden können.
Beispielsweise akzeptiert der Name-Parameter der
Start-Service
Pipelineeingabe nach Wert. Sie kann Zeichenfolgenobjekte oder Objekte akzeptieren, die in Zeichenfolgen konvertiert werden können.ByPropertyName: Der Parameter akzeptiert eingabe nur, wenn das Eingabeobjekt über eine Eigenschaft mit demselben Namen wie der Parameter verfügt.
Der Name-Parameter
Start-Service
kann z. B. Objekte akzeptieren, die über eine Name-Eigenschaft verfügen. Um die Eigenschaften eines Objekts auflisten zu können, führen Sie es anGet-Member
.
Einige Parameter können Objekte sowohl nach Wert- als auch Eigenschaftsnamen akzeptieren, wodurch die Eingaben von der Pipeline einfacher werden können.
Parameterbindung
Wenn Sie Objekte von einem Befehl an einen anderen Befehl weiterleiten, versucht PowerShell, die weitergeleiteten Objekte einem Parameter des empfangenden Cmdlets zuzuordnen.
Die Parameterbindungskomponente von PowerShell ordnet die Eingabeobjekte den Cmdlet-Parametern gemäß den folgenden Kriterien zu:
- Der Parameter muss Eingaben aus einer Pipeline akzeptieren.
- Der Parameter muss den Typ des gesendeten Objekts oder einen Typ akzeptieren, der in den erwarteten Typ konvertiert werden kann.
- Der Parameter wurde nicht im Befehl verwendet.
Das Cmdlet verfügt beispielsweise Start-Service
über viele Parameter, aber nur zwei davon, Name und InputObject akzeptieren Pipelineeingaben. Der Parameter Name akzeptiert Zeichenfolgen, und der InputObject-Parameter akzeptiert Dienstobjekte. Daher können Sie Zeichenfolgen, Dienstobjekte und Objekte mit Eigenschaften übergeben, die in Zeichenfolgen- oder Dienstobjekte konvertiert werden können.
PowerShell verwaltet die Parameterbindung so effizient wie möglich. Sie können die PowerShell nicht vorschlagen oder erzwingen, eine Bindung an einen bestimmten Parameter durchzuführen. Der Befehl schlägt fehl, wenn PowerShell die weitergeleiteten Objekte nicht binden kann.
Weitere Informationen zur Problembehandlung von Bindungsfehlern finden Sie weiter unten in diesem Artikel unter "Untersuchen von Pipelinefehlern ".
Einmalige Verarbeitung
Das Anfügen von Objekten an einen Befehl ähnelt der Verwendung eines Parameters des Befehls zum Übermitteln der Objekte. Sehen wir uns ein Pipelinebeispiel an. In diesem Beispiel verwenden wir eine Pipeline, um eine Tabelle mit Dienstobjekten anzuzeigen.
Get-Service | Format-Table -Property Name, DependentServices
Funktionell ähnelt dies der Verwendung des InputObject-Parameters Format-Table
zum Übermitteln der Objektauflistung.
Beispielsweise können wir die Sammlung von Diensten in einer Variablen speichern, die mithilfe des InputObject-Parameters übergeben wird.
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
Oder wir können den Befehl in den InputObject-Parameter einbetten.
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Es gibt jedoch einen wichtigen Unterschied. Wenn Sie mehrere Objekte an einen Befehl senden, sendet PowerShell die Objekte nacheinander an den Befehl. Wenn Sie einen Befehlsparameter verwenden, werden die Objekte als einzelnes Arrayobjekt gesendet. Dieser geringfügige Unterschied hat erhebliche Folgen.
Bei der Ausführung einer Pipeline listet PowerShell automatisch alle Typen auf, die die IEnumerable
Schnittstelle oder ihr generisches Gegenstück implementieren. Aufgezählte Elemente werden jeweils einzeln über die Pipeline gesendet. PowerShell listet auch System.Data.DataTable-Typen über die Rows
Eigenschaft auf.
Es gibt einige Ausnahmen von der automatischen Aufzählung.
- Sie müssen die
GetEnumerator()
Methode für Hashtabellen, Typen, die dieIDictionary
Schnittstelle oder ihr generisches Gegenstück implementieren, und System.Xml.XmlNode-Typen aufrufen. - Die System.String-Klasse implementiert
IEnumerable
, powerShell führt jedoch keine Enumeration von Zeichenfolgenobjekten durch.
In den folgenden Beispielen werden ein Array und eine Hashtable an das Measure-Object
Cmdlet weitergeleitet, um die Anzahl der objekte zu zählen, die von der Pipeline empfangen wurden. Das Array verfügt über mehrere Elemente, und die Hashtable verfügt über mehrere Schlüsselwertpaare. Nur das Array wird einzeln aufgezählt.
@(1,2,3) | Measure-Object
Count : 3
Average :
Sum :
Maximum :
Minimum :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count : 1
Average :
Sum :
Maximum :
Minimum :
Property :
Wenn Sie mehrere Prozessobjekte vom Get-Process
Cmdlet an das Get-Member
Cmdlet weiterleiten, sendet PowerShell jedes Prozessobjekt nacheinander an Get-Member
. Get-Member
zeigt die .NET-Klasse (Typ) der Prozessobjekte sowie deren Eigenschaften und Methoden an.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Hinweis
Get-Member
entfernt Duplikate. Wenn die Objekte also alle denselben Typ aufweisen, wird nur ein Objekttyp angezeigt.
Wenn Sie jedoch den InputObject-Parameter verwenden Get-Member
, empfängt sie Get-Member
ein Array von System.Diagnostics.Process-Objekten als einzelne Einheit. Es zeigt die Eigenschaften eines Arrays von Objekten an. (Beachten Sie das Arraysymbol ([]
) nach dem Namen des System.Object-Typs .)
Beispiel:
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()
...
Dieses Ergebnis ist möglicherweise nicht das, was Sie beabsichtigt haben. Aber nachdem Sie es verstanden haben, können Sie es verwenden. Beispielsweise verfügen alle Arrayobjekte über eine Count-Eigenschaft . Sie können dies verwenden, um die Anzahl der auf dem Computer ausgeführten Prozesse zu zählen.
Beispiel:
(Get-Process).count
Es ist wichtig zu beachten, dass Objekte, die an die Pipeline gesendet wurden, jeweils einzeln übermittelt werden.
Verwenden systemeigener Befehle in der Pipeline
PowerShell ermöglicht es Ihnen, systemeigene externe Befehle in die Pipeline einzuschließen. Beachten Sie jedoch, dass die Pipeline von PowerShell objektorientiert ist und unformatierte Bytedaten nicht unterstützt.
Das Weiterleiten oder Umleiten von Ausgaben aus einem systemeigenen Programm, das unformatierte Bytedaten ausgibt, konvertiert die Ausgabe in .NET-Zeichenfolgen. Diese Konvertierung kann zu Beschädigungen der Rohdatenausgabe führen.
PowerShell 7.4 hat jedoch das PSNativeCommandPreserveBytePipe
experimentelle Feature hinzugefügt, das Bytestreamdaten beim Umleiten des Stdout-Datenstroms eines systemeigenen Befehls zu einer Datei oder beim Weiterleiten von Bytestreamdaten an den Stdin-Datenstrom eines systemeigenen Befehls beibehalten.
Mit dem nativen Befehl curl
können Sie beispielsweise eine Binärdatei herunterladen und mithilfe der Umleitung auf dem Datenträger speichern.
$uri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz'
# native command redirected to a file
curl -s -L $uri > powershell.tar.gz
Sie können die Bytestreamdaten auch an den stdin-Stream eines anderen nativen Befehls übergeben. Im folgenden Beispiel wird eine gezippte TAR-Datei mit curl
heruntergeladen. Die heruntergeladenen Dateidaten werden an den tar
-Befehl gestreamt, um den Inhalt des Archivs zu extrahieren.
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
Sie können auch die Bytestreamausgabe eines PowerShell-Befehls an die Eingabe eines nativen Befehls weiterleiten. Verwenden Sie in den folgenden Beispielen Invoke-WebRequest
, um die gleiche TAR-Datei wie im vorherigen Beispiel herunterzuladen.
# byte stream piped to a native command
(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
Dieses Feature unterstützt keine Bytestreamdaten beim Umleiten der stderr-Ausgabe an stdout. Wenn Sie die Streams stderr und stdout kombinieren, werden die kombinierten Streams als Zeichenfolgendaten behandelt.
Untersuchen von Pipelinefehlern
Wenn PowerShell die weitergeleiteten Objekte nicht einem Parameter des empfangenden Cmdlets zuordnen kann, schlägt der Befehl fehl.
Im folgenden Beispiel versuchen wir, einen Registrierungseintrag von einem Registrierungsschlüssel in einen anderen zu verschieben. Das Get-Item
Cmdlet ruft den Zielpfad ab, der dann an das Move-ItemProperty
Cmdlet weitergeleitet wird. Der Move-ItemProperty
Befehl gibt den aktuellen Pfad und den Namen des Registrierungseintrags an, der verschoben werden soll.
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
Der Befehl schlägt fehl, und PowerShell zeigt die folgende Fehlermeldung an:
Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<< -Path HKLM:\Software\MyCompany\design -Name p
Verwenden Sie zum Untersuchen das Trace-Command
Cmdlet, um die Parameterbindungskomponente von PowerShell nachzuverfolgen. Im folgenden Beispiel wird die Parameterbindung während der Ausführung der Pipeline verfolgt. Der PSHost-Parameter zeigt die Ablaufverfolgungsergebnisse in der Konsole an, und der FilePath-Parameter sendet die Ablaufverfolgungsergebnisse zur späteren Referenz an die debug.txt
Datei.
Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}
Die Ergebnisse der Ablaufverfolgung sind langwierig, zeigen aber die Werte an, die an das Get-Item
Cmdlet gebunden werden, und dann die benannten Werte, die an das Move-ItemProperty
Cmdlet gebunden werden.
...
BIND NAMED cmd line args [`Move-ItemProperty`]
BIND arg [HKLM:\Software\MyCompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
...
BIND POSITIONAL cmd line args [`Move-ItemProperty`]
...
Schließlich wird gezeigt, dass der Versuch, den Pfad an den Parameter "DestinationMove-ItemProperty
" zu binden, fehlgeschlagen ist.
...
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
...
Verwenden Sie das Get-Help
Cmdlet, um die Attribute des Destination-Parameters anzuzeigen.
Get-Help Move-ItemProperty -Parameter Destination
-Destination <String>
Specifies the path to the destination location.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
Die Ergebnisse zeigen, dass "Destination " nur "nach Eigenschaftsname" Pipelineeingaben verwendet. Daher muss das piped-Objekt eine Eigenschaft mit dem Namen Destination aufweisen.
Wird verwendet Get-Member
, um die Eigenschaften des Objekts anzuzeigen, das von Get-Item
.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
Die Ausgabe zeigt, dass das Element ein Microsoft.Win32.RegistryKey-Objekt ist, das keine Destination-Eigenschaft aufweist. Dies erklärt, warum der Befehl fehlgeschlagen ist.
Der Parameter Path akzeptiert pipelineeingaben nach Name oder Wert.
Get-Help Move-ItemProperty -Parameter Path
-Path <String[]>
Specifies the path to the current location of the property. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
Um den Befehl zu beheben, müssen wir das Ziel im Move-ItemProperty
Cmdlet angeben und verwenden Get-Item
, um den Pfad des Elements abzurufen, das verschoben werden soll.
Beispiel:
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Systeminterne Zeilenfortsetzung
Wie bereits erwähnt, handelt es sich bei einer Pipeline um eine Reihe von Befehlen, die von Pipelineoperatoren (|
), in der Regel in einer einzigen Zeile, verbunden sind. Aus Gründen der Lesbarkeit können Sie die Pipeline jedoch in PowerShell über mehrere Zeilen aufteilen. Wenn ein Pipeoperator das letzte Token in der Zeile ist, verknüpft der PowerShell-Parser die nächste Zeile mit dem aktuellen Befehl, um die Konstruktion der Pipeline fortzusetzen.
Beispielsweise die folgende einzeilige Pipeline:
Command-1 | Command-2 | Command-3
kann wie folgt geschrieben werden:
Command-1 |
Command-2 |
Command-3
Die führenden Leerzeichen in den nachfolgenden Zeilen sind nicht signifikant. Der Einzug verbessert die Lesbarkeit.
PowerShell 7 fügt Unterstützung für die Fortsetzung von Pipelines mit dem Pipelinezeichen am Anfang einer Zeile hinzu. Die folgenden Beispiele zeigen, wie Sie diese neue Funktionalität verwenden können.
# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
| Get-Item | Where-Object FullName -match "AppData"
| Sort-Object FullName -Unique
# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
|
Get-Item | Where-Object FullName -match "AppData"
|
Sort-Object FullName -Unique
Wichtig
Wenn Sie interaktiv in der Shell arbeiten, fügen Sie Code mit Pipelines am Anfang einer Zeile nur dann ein, wenn Sie STRG+V zum Einfügen verwenden. Klicken Sie mit der rechten Maustaste auf Einfügevorgänge, um die Zeilen einzeln einzufügen. Da die Zeile nicht mit einem Pipelinezeichen endet, berücksichtigt PowerShell, dass die Eingabe abgeschlossen ist und diese Zeile wie eingegeben ausgeführt wird.