Freigeben über


about_Pipelines

Kurze Beschreibung

Kombinieren von Befehlen in Pipelines in powerShell

Lange Beschreibung

Eine Pipeline ist eine Reihe von Befehlen, die durch 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 ausgegeben werden, Command-1 an Command-2gesendet. Command-2 verarbeitet die -Objekte und sendet sie an Command-3. Command-3 verarbeitet die Objekte und sendet sie in die Pipeline. Da es keine weiteren Befehle in der Pipeline gibt, werden die Ergebnisse in der Konsole angezeigt.

In einer Pipeline werden die Befehle in der Reihenfolge 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. Mit dem folgenden Befehl wird der Editor-Prozess abgerufen und dann beendet.

Beispiel:

Get-Process notepad | Stop-Process

Der erste Befehl verwendet das Get-Process Cmdlet, um ein Objekt abzurufen, das den Editor-Prozess darstellt. Es verwendet einen Pipelineoperator (|), um das Prozessobjekt an das Stop-Process Cmdlet zu senden, das den Editor-Prozess beendet. Beachten Sie, dass der Stop-Process Befehl keinen Name - oder ID-Parameter zum Angeben des Prozesses enthält, 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 der einzelnen Befehle, die 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 Cmdlets Get an ein anderes Cmdlet mit demselben Substantiv weiterleiten. Beispielsweise können Sie die Ausgabe des Get-Service Cmdlets an die Start-Service Cmdlets oder Stop-Service weiterleiten.

Mit dieser Beispielpipeline wird der WMI-Dienst auf dem Computer gestartet:

Get-Service wmi | Start-Service

In einem anderen Beispiel können Sie die Ausgabe von oder Get-ChildItem innerhalb des Get-Item PowerShell-Registrierungsanbieters an das New-ItemProperty Cmdlet weiterleiten. In diesem Beispiel wird dem Registrierungsschlüssel MyCompany der neue Registrierungseintrag NoOfEmployees mit dem Wert 8124 hinzugefügt.

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

Viele der Hilfsprogramm-Cmdlets wie Get-Member, Where-Object, Sort-Object, Group-Objectund Measure-Object werden fast ausschließlich in Pipelines verwendet. Sie können einen beliebigen Objekttyp an diese Cmdlets weiterleiten. In diesem Beispiel wird gezeigt, wie alle Prozesse auf dem Computer nach der Anzahl der geöffneten Handles in jedem Prozess sortiert werden.

Get-Process | Sort-Object -Property handles

Sie können Objekte an die Formatierungs-, Export- und Ausgabe-Cmdlets übergeben, zFormat-List. B. , Format-Table, , Export-ClixmlExport-CSVund Out-File.

In diesem Beispiel wird gezeigt, wie Sie das Format-List Cmdlet verwenden, um eine Liste der Eigenschaften für ein Prozessobjekt anzuzeigen.

Get-Process winlogon | Format-List -Property *

Sie können die Ausgabe nativer Befehle auch an PowerShell-Cmdlets weiterleiten. 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 Erfolgs- und Fehlerdatenströme ähneln den Stdin- und stderr-Streams anderer Shells. Stdin ist jedoch nicht für die Eingabe mit der PowerShell-Pipeline verbunden. Weitere Informationen finden Sie unter about_Redirection.

Mit ein wenig Übung werden Sie feststellen, dass die Kombination einfacher Befehle in Pipelines Zeit und Eingabe spart und Ihre Skripterstellung effizienter macht.

Funktionsweise von Pipelines

In diesem Abschnitt wird erläutert, wie Eingabeobjekte an Cmdletparameter gebunden und während der Pipelineausführung verarbeitet werden.

Akzeptiert Pipelineeingaben

Um das Pipelining zu unterstützen, muss das empfangende Cmdlet über einen Parameter verfügen, der pipelineeingaben akzeptiert. Verwenden Sie den Get-Help Befehl mit den Optionen Full oder Parameter , um zu bestimmen, welche Parameter eines Cmdlets pipelineeingaben akzeptieren.

Geben Sie beispielsweise Folgendes ein, um zu bestimmen, welcher der Parameter des Cmdlets die Start-Service Pipelineeingabe akzeptiert:

Get-Help Start-Service -Full

oder

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 an Start-Servicesenden, versucht PowerShell, die Objekte den Parametern InputObject und Name zuzuordnen.

Methoden zum Akzeptieren von Pipelineeingaben

Cmdlets-Parameter können Pipelineeingaben auf zwei verschiedene Arten akzeptieren:

  • ByValue: Der Parameter akzeptiert Werte, die dem erwarteten .NET-Typ entsprechen oder in diesen Typ konvertiert werden können.

    Der Name-Parameter von Start-Service akzeptiert beispielsweise die Pipelineeingabe nach Wert. Sie kann Zeichenfolgenobjekte oder -objekte akzeptieren, die in Zeichenfolgen konvertiert werden können.

  • ByPropertyName: Der Parameter akzeptiert eingaben nur, wenn das Eingabeobjekt über eine Eigenschaft mit demselben Namen wie der Parameter verfügt.

    Der Name-Parameter von Start-Service kann beispielsweise Objekte akzeptieren, die über eine Name-Eigenschaft verfügen. Um die Eigenschaften eines -Objekts aufzulisten, leiten Sie es an eine Pipe an Get-Member.

Einige Parameter können Objekte sowohl anhand des Werts als auch des Eigenschaftennamens akzeptieren, sodass Es einfacher ist, Eingaben aus der Pipeline zu übernehmen.

Parameterbindung

Wenn Sie Objekte von einem Befehl an einen anderen übergeben, versucht PowerShell, die piped-Objekte einem Parameter des empfangenden Cmdlets zuzuordnen.

Die PowerShell-Parameterbindungskomponente verknüpft die Eingabeobjekte mit Cmdletparametern gemäß den folgenden Kriterien:

  • 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 im Befehl nicht verwendet.

Das Cmdlet verfügt beispielsweise Start-Service über viele Parameter, aber nur zwei davon, Name und InputObject , akzeptieren pipelineeingaben. Der Name-Parameter nimmt Zeichenfolgen an, und der InputObject-Parameter übernimmt 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 Bindung der PowerShell an einen bestimmten Parameter nicht vorschlagen oder erzwingen. Der Befehl schlägt fehl, wenn PowerShell die übergebenen Objekte nicht binden kann.

Weitere Informationen zur Problembehandlung bei Bindungsfehlern finden Sie weiter unten in diesem Artikel unter Untersuchen von Pipelinefehlern .

Einmalige Verarbeitung

Das Piping 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 von Format-Table , um die Objektauflistung zu übermitteln.

Beispielsweise können wir die Auflistung der Dienste in einer Variablen speichern, die mit dem InputObject-Parameter ü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 übergeben, sendet PowerShell die Objekte einzeln an den Befehl. Wenn Sie einen Befehlsparameter verwenden, werden die Objekte als einzelnes Arrayobjekt gesendet. Dieser geringfügige Unterschied hat erhebliche Folgen.

Beim Ausführen einer Pipeline listet PowerShell automatisch jeden Typ auf, der die Schnittstelle oder ihre IEnumerable generische Entsprechung implementiert. Aufgezählte Elemente werden einzeln über die Pipeline gesendet. PowerShell listet auch System.Data.DataTable-Typen über die Rows -Eigenschaft auf.

Es gibt einige Ausnahmen für die automatische Enumeration.

  • Sie müssen die GetEnumerator() Methode für Hashtabellen, Typen, die die Schnittstelle oder ihre IDictionary generische Entsprechung implementieren, und System.Xml aufrufen. XmlNode-Typen .
  • Die System.String-Klasse implementiert IEnumerable, aber PowerShell listet keine Zeichenfolgenobjekte auf.

In den folgenden Beispielen werden ein Array und eine Hashtabelle an das Measure-Object Cmdlet weitergeleitet, um die Anzahl der von der Pipeline empfangenen Objekte zu zählen. Das Array verfügt über mehrere Member, und die Hashtabelle verfügt über mehrere Schlüssel-Wert-Paare. Nur das Array wird einzeln aufgelistet.

@(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 aus dem Cmdlet an das Get-ProcessGet-Member Cmdlet weiterleiten, sendet PowerShell jedes Prozessobjekt einzeln 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 beseitigt Duplikate. Wenn die Objekte also alle denselben Typ aufweisen, wird nur ein Objekttyp angezeigt.

Wenn Sie jedoch den InputObject-Parameter von Get-Memberverwenden, Get-Member empfängt ein Array von System.Diagnostics.Process-Objekten als einzelne Einheit. Sie zeigt die Eigenschaften eines Arrays von Objekten an. (Beachten Sie das Arraysymbol ([]) hinter dem System.Object-Typnamen .)

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 . Damit können Sie die Anzahl der auf dem Computer ausgeführten Prozesse zählen.

Beispiel:

(Get-Process).count

Es ist wichtig zu beachten, dass Objekte, die über die Pipeline gesendet werden, einzeln übermittelt werden.

Verwenden nativer Befehle in der Pipeline

Mit PowerShell können Sie native externe Befehle in die Pipeline einschließen. Beachten Sie jedoch, dass die PowerShell-Pipeline objektorientiert ist und keine unformatierten Bytedaten unterstützt.

Durch Das Weiterleiten oder Umleiten einer Ausgabe aus einem nativen Programm, das unformatierte Bytedaten ausgibt, wird die Ausgabe in .NET-Zeichenfolgen konvertiert. Diese Konvertierung kann zu einer Beschädigung der Rohdatenausgabe führen.

Rufen Sie als Problemumgehung die nativen Befehle mit cmd.exe /c oder sh -c auf, und verwenden Sie die | operatoren und > , die von der nativen Shell bereitgestellt werden.

Untersuchen von Pipelinefehlern

Wenn PowerShell die piped-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 zu verschiebenden Registrierungseintrags an.

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 lang, aber sie zeigen 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 zeigt es, dass der Versuch, den Pfad an den ZielparameterMove-ItemProperty von 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 Zielparameters 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 die Pipelineeingabe nur "by property name" akzeptiert. Daher muss das übergebene Objekt über eine Eigenschaft namens Destination verfügen.

Verwenden Sie Get-Member , um die Eigenschaften des -Objekts anzuzeigen, das von Get-Itemstammt.

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 beim Befehl ein Fehler aufgetreten ist.

Der Path-Parameter akzeptiert die Pipelineeingabe 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 wir verschieben möchten.

Beispiel:

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Intrinsische Zeilenfortführung

Wie bereits erwähnt, ist eine Pipeline eine Reihe von Befehlen, die von Pipelineoperatoren (|) verbunden sind, die normalerweise auf einer einzelnen Zeile geschrieben werden. Aus Gründen der Lesbarkeit können Sie mit PowerShell die Pipeline jedoch auf 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 den Bau 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 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, betrachtet PowerShell die Eingabe als abgeschlossen und führt diese Zeile wie eingegeben aus.

Weitere Informationen