Freigeben über


Informationen zu Pipelines

Kurzbeschreibung

Kombinieren von Befehlen zu 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 Command-1 emittiert, an Command-2gesendet. 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 Cmdlet Get-Process, um ein Objekt abzurufen, das den Notepad-Prozess darstellt. Es verwendet einen Pipelineoperator (|), um das Prozessobjekt an das Cmdlet Stop-Process zu senden, das den Notepad-Prozess stoppt. Beachten Sie, dass der befehl Stop-Process 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 jedes Befehls, wenn er an den nächsten Befehl in der Pipeline weitergegeben 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 Substantivsweiterleiten. Zum Beispiel können Sie die Ausgabe des Cmdlets Get-Service an die Cmdlets Start-Service oder Stop-Service weiterleiten.

Diese Beispielpipeline startet den WMI-Dienst auf dem Computer:

Get-Service wmi | Start-Service

Ein weiteres Beispiel: Sie können die Ausgabe von Get-Item oder Get-ChildItem innerhalb des PowerShell-Registrierungsanbieters an das cmdlet New-ItemProperty weiterleiten. In diesem Beispiel wird dem Registrierungsschlüssel MyCompany ein neuer Registrierungseintrag NoOfEmployeesmit dem Wert 8124hinzugefügt.

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

Viele der Hilfs-Cmdlets wie Get-Member, 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. B. Format-List, Format-Table, Export-Clixml, Export-CSVund Out-File.

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

Get-Process winlogon | Format-List -Property *

Mit etwas Übung werden Sie feststellen, dass das Kombinieren einfacher Befehle in Pipelines Zeit und Tastatureingaben spart und Ihre Skripterstellung effizienter macht.

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 des Pipelining muss das empfangende Cmdlet über einen Parameter verfügen, der Pipeline-Eingaben akzeptiert. Verwenden Sie den Befehl Get-Help mit den Optionen Vollständig oder Parameter, um zu bestimmen, welche Parameter eines Cmdlets Pipelineeingaben akzeptieren.

Um beispielsweise zu bestimmen, welche Parameter des Cmdlets Start-Service Pipelineeingabe akzeptiert, geben Sie Folgendes ein:

Get-Help Start-Service -Full

oder

Get-Help Start-Service -Parameter *

Die Hilfe für das Cmdlet Start-Service zeigt, dass nur der Parameter InputObject und Name Pipelineeingaben akzeptiert.

-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 Parametern 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 Parameter Name von Start-Service die 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.

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

Einige Parameter können Objekte sowohl nach Wert als auch nach Eigenschaftsname akzeptieren, was die Eingabe durch die Pipeline erleichtert.

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 Start-Service verfügt beispielsweise über viele Parameter, aber nur zwei parameter, Name und InputObject Pipelineeingaben akzeptieren. Der parameter Name akzeptiert Zeichenfolgen, und der parameter InputObject nimmt Dienstobjekte an. 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 unter Untersuchen von Pipelinefehlern weiter unten in diesem Artikel.

Einzelverarbeitung

Das Weiterleiten von Objekten an einen Befehl ist vergleichbar mit der Nutzung eines Befehlsparameters, um die Objekte zu übermitteln. 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 ist dies wie die Verwendung des InputObject- Parameters von Format-Table zum Übermitteln der Objektauflistung.

Zum Beispiel können wir die Sammlung von Diensten 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 parameter InputObject 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.

Beim Ausführen einer Pipeline listet PowerShell automatisch jeden Typ auf, der die IEnumerable Schnittstelle implementiert, und sendet die Member nacheinander durch die Pipeline. Die Ausnahme ist [hashtable], die einen Aufruf der GetEnumerator() Methode erfordert.

In den folgenden Beispielen werden ein Array und eine Hashtabelle an das cmdlet Measure-Object 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 aus dem Cmdlet Get-Process an das Cmdlet Get-Member 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 eliminiert Duplikate, sodass, wenn die Objekte alle vom gleichen Typ sind, nur ein Objekttyp angezeigt wird.

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

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 durch die Pipeline gesendet werden, jeweils einzeln übermittelt werden.

Fehler in der Pipeline untersuchen

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 Cmdlet Get-Item ruft den Zielpfad ab, der dann an das Cmdlet Move-ItemProperty weitergeleitet wird. Der Befehl Move-ItemProperty 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 Cmdlet Trace-Command, 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 parameter FilePath 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 ausführlich, zeigen jedoch, dass die Werte an das Get-Item-Cmdlet gebunden und anschließend die benannten Werte an das Cmdlet Move-ItemProperty 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 Destination Parameter von Move-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 cmdlet Get-Help, um die Attribute des parameters Destination 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 das Ziel Pipelineneingaben nur „nach Eigenschaftsnamen” akzeptiert. Daher muss das weitergeleitete Objekt eine Eigenschaft mit dem Namen Destinationaufweisen.

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 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 Cmdlet Move-ItemProperty angeben und Get-Item verwenden, um die 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, ist eine Pipeline eine Reihe von Befehlen, die von Pipeline-Operatoren (|) verbunden sind und normalerweise in einer einzigen Zeile geschrieben werden. Aus Gründen der Lesbarkeit können Sie die Pipeline jedoch in PowerShell über mehrere Zeilen aufteilen. Wenn ein Pipe-Operator das letzte Token in der Zeile ist, verbindet der PowerShell-Parser die nächste Zeile mit dem aktuellen Befehl, um die Pipeline-Konstruktion fortzusetzen.

Beispielsweise kann die folgende einzeilige Pipeline

Command-1 | Command-2 | Command-3

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.

Siehe auch

about_PSReadLine

about_Objects

about_Parameters

über_Befehlssyntax

about_ForEach