about_Pipelines

Korte beschrijving

Opdrachten combineren in pijplijnen in PowerShell

Lange beschrijving

Een pijplijn is een reeks opdrachten die zijn verbonden door pijplijnoperators (|ASCII 124). Elke pijplijnoperator verzendt de resultaten van de voorgaande opdracht naar de volgende opdracht.

De uitvoer van de eerste opdracht kan worden verzonden voor verwerking als invoer naar de tweede opdracht. En die uitvoer kan naar nog een andere opdracht worden verzonden. Het resultaat is een complexe opdrachtketen of pijplijn die bestaat uit een reeks eenvoudige opdrachten.

Voorbeeld:

Command-1 | Command-2 | Command-3

In dit voorbeeld worden de objecten die Command-1 worden verzonden, verzonden naar Command-2. Command-2 verwerkt de objecten en verzendt ze naar Command-3. Command-3 verwerkt de objecten en verzendt ze omlaag in de pijplijn. Omdat er geen opdrachten meer in de pijplijn staan, worden de resultaten weergegeven in de console.

In een pijplijn worden de opdrachten verwerkt in volgorde van links naar rechts. De verwerking wordt verwerkt als één bewerking en de uitvoer wordt weergegeven terwijl deze wordt gegenereerd.

Hier volgt een eenvoudig voorbeeld. Met de volgende opdracht wordt het Kladblok proces ophaalt en vervolgens gestopt.

Voorbeeld:

Get-Process notepad | Stop-Process

De eerste opdracht gebruikt de Get-Process cmdlet om een object op te halen dat het Kladblok proces vertegenwoordigt. Er wordt een pijplijnoperator (|) gebruikt om het procesobject naar de Stop-Process cmdlet te verzenden, waardoor het Kladblok proces wordt gestopt. U ziet dat de Stop-Process opdracht geen naam- of id-parameter heeft om het proces op te geven, omdat het opgegeven proces wordt verzonden via de pijplijn.

In dit pijplijnvoorbeeld worden de tekstbestanden in de huidige map opgehaald, worden alleen de bestanden geselecteerd die langer zijn dan 10.000 bytes, worden ze gesorteerd op lengte en worden de naam en lengte van elk bestand in een tabel weergegeven.

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

Deze pijplijn bestaat uit vier opdrachten in de opgegeven volgorde. In de volgende afbeelding ziet u de uitvoer van elke opdracht terwijl deze wordt doorgegeven aan de volgende opdracht in de pijplijn.

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

Pijplijnen gebruiken

De meeste PowerShell-cmdlets zijn ontworpen ter ondersteuning van pijplijnen. In de meeste gevallen kunt u de resultaten van een Get-cmdlet doorsluisen naar een andere cmdlet van hetzelfde zelfstandig naamwoord. U kunt bijvoorbeeld de uitvoer van de Get-Service cmdlet doorsluisen naar de Start-Service of Stop-Service cmdlets.

Met deze voorbeeldpijplijn wordt de WMI-service op de computer gestart:

Get-Service wmi | Start-Service

U kunt bijvoorbeeld de uitvoer van Get-Item of Get-ChildItem binnen de PowerShell-registerprovider doorsluisen naar de New-ItemProperty cmdlet. In dit voorbeeld wordt een nieuwe registervermelding, NoOfEmployees, met een waarde van 8124, toegevoegd aan de registersleutel MyCompany .

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

Veel van de hulpprogramma-cmdlets, zoals Get-Member, Where-Object, Sort-Object, en Group-Objectworden Measure-Object bijna uitsluitend gebruikt in pijplijnen. U kunt elk objecttype doorsluizen naar deze cmdlets. In dit voorbeeld ziet u hoe u alle processen op de computer kunt sorteren op het aantal geopende ingangen in elk proces.

Get-Process | Sort-Object -Property handles

U kunt objecten doorsluisen naar de opmaak, export en uitvoer-cmdlets, zoals , , , en Out-FileExport-CSV. Export-ClixmlFormat-TableFormat-List

In dit voorbeeld ziet u hoe u de Format-List cmdlet gebruikt om een lijst met eigenschappen voor een procesobject weer te geven.

Get-Process winlogon | Format-List -Property *

U kunt ook de uitvoer van systeemeigen opdrachten doorsluisen naar PowerShell-cmdlets. Voorbeeld:

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

Belangrijk

De succes - en foutstromen zijn vergelijkbaar met de stdin- en stderr-stromen van andere shells. Stdin is echter niet verbonden met de PowerShell-pijplijn voor invoer. Zie about_Redirection voor meer informatie.

Met een beetje oefening zult u merken dat het combineren van eenvoudige opdrachten in pijplijnen tijd en typen bespaart en uw scripting efficiënter maakt.

Hoe pijplijnen werken

In deze sectie wordt uitgelegd hoe invoerobjecten afhankelijk zijn van cmdlet-parameters en worden verwerkt tijdens de uitvoering van de pijplijn.

Accepteert pijplijninvoer

Ter ondersteuning van pipelining moet de ontvangende cmdlet een parameter hebben die pijplijninvoer accepteert. Gebruik de Get-Help opdracht met de opties Volledig of Parameter om te bepalen welke parameters van een cmdlet pijplijninvoer accepteren.

Als u bijvoorbeeld wilt bepalen welke van de parameters van de Start-Service cmdlet pijplijninvoer accepteert, typt u:

Get-Help Start-Service -Full

or

Get-Help Start-Service -Parameter *

In de help voor de Start-Service cmdlet ziet u dat alleen de parameters InputObject en Name pijplijninvoer accepteren.

-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

Wanneer u objecten via de pijplijn verzendt Start-Service, probeert PowerShell de objecten te koppelen aan de parameters InputObject en Name .

Methoden voor het accepteren van pijplijninvoer

Cmdlets-parameters kunnen pijplijninvoer op twee verschillende manieren accepteren:

  • ByValue: De parameter accepteert waarden die overeenkomen met het verwachte .NET-type of die naar dat type kunnen worden geconverteerd.

    De parameter Name van Start-Service accepteert bijvoorbeeld pijplijninvoer op waarde. Hiermee kunnen tekenreeksobjecten of -objecten worden geaccepteerd die kunnen worden geconverteerd naar tekenreeksen.

  • ByPropertyName: De parameter accepteert alleen invoer wanneer het invoerobject een eigenschap van dezelfde naam heeft als de parameter.

    De parameter Name van Start-Service kan bijvoorbeeld objecten met een eigenschap Name accepteren. Als u de eigenschappen van een object wilt weergeven, sluist u het naar Get-Member.

Sommige parameters kunnen objecten accepteren op zowel waarde- als eigenschapsnaam, waardoor het gemakkelijker is om invoer uit de pijplijn te nemen.

Parameterbinding

Wanneer u objecten van de ene opdracht naar een andere opdracht doorsluist, probeert PowerShell de gesluisde objecten te koppelen aan een parameter van de ontvangende cmdlet.

Het parameterbindingsonderdeel van PowerShell koppelt de invoerobjecten aan cmdlet-parameters volgens de volgende criteria:

  • De parameter moet invoer van een pijplijn accepteren.
  • De parameter moet het type object accepteren dat wordt verzonden of een type dat kan worden geconverteerd naar het verwachte type.
  • De parameter is niet gebruikt in de opdracht.

De Start-Service cmdlet heeft bijvoorbeeld veel parameters, maar slechts twee parameters, naam en InputObject accepteren pijplijninvoer. De parameter Name neemt tekenreeksen en de parameter InputObject neemt serviceobjecten. Daarom kunt u tekenreeksen, serviceobjecten en objecten doorsluisen met eigenschappen die kunnen worden geconverteerd naar tekenreeks- of serviceobjecten.

PowerShell beheert parameterbinding zo efficiënt mogelijk. U kunt PowerShell niet voorstellen of forceren om verbinding te maken met een specifieke parameter. De opdracht mislukt als PowerShell de gesluisde objecten niet kan binden.

Zie Pijplijnfouten onderzoeken verderop in dit artikel voor meer informatie over het oplossen van bindingsfouten .

Eenmalige verwerking

Het doorsturen van objecten naar een opdracht is vergelijkbaar met het gebruik van een parameter van de opdracht om de objecten te verzenden. Laten we eens kijken naar een pijplijnvoorbeeld. In dit voorbeeld gebruiken we een pijplijn om een tabel met serviceobjecten weer te geven.

Get-Service | Format-Table -Property Name, DependentServices

Functioneel is dit vergelijkbaar met het gebruik van de parameter InputObject van het verzenden van Format-Table de objectverzameling.

We kunnen bijvoorbeeld de verzameling services opslaan in een variabele die wordt doorgegeven met behulp van de parameter InputObject .

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Of we kunnen de opdracht insluiten in de parameter InputObject .

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

Er is echter een belangrijk verschil. Wanneer u meerdere objecten doorstuurt naar een opdracht, verzendt PowerShell de objecten één voor één naar de opdracht. Wanneer u een opdrachtparameter gebruikt, worden de objecten verzonden als één matrixobject. Dit kleine verschil heeft aanzienlijke gevolgen.

Bij het uitvoeren van een pijplijn inventariseert PowerShell automatisch elk type dat de interface of de IEnumerable generieke tegenhanger implementeert. Geïnventariseerd items worden één voor één verzonden via de pijplijn. PowerShell inventariseert ook System.Data.DataTable-typen via de Rows eigenschap.

Er zijn enkele uitzonderingen op automatische opsomming.

  • U moet de GetEnumerator() methode aanroepen voor hash-tabellen, typen die de IDictionary interface of de generieke tegenhanger implementeren en System.Xml.XmlNode-typen .
  • De klasse System.String implementeert IEnumerable, maar PowerShell inventariseert geen tekenreeksobjecten.

In de volgende voorbeelden worden een matrix en een hashtabel doorgesluisd naar de Measure-Object cmdlet om het aantal objecten te tellen dat van de pijplijn is ontvangen. De matrix heeft meerdere leden en de hashtabel heeft meerdere sleutel-waardeparen. Alleen de matrix wordt één voor één geïnventariseerd.

@(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 :

Als u meerdere procesobjecten van de Get-Process cmdlet naar de Get-Member cmdlet doorstuurt, verzendt PowerShell elk procesobject, één voor één, naar Get-Member. Get-Member geeft de .NET-klasse (type) van de procesobjecten en de bijbehorende eigenschappen en methoden weer.

Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Name      MemberType     Definition
----      ----------     ----------
Handles   AliasProperty  Handles = Handlecount
Name      AliasProperty  Name = ProcessName
NPM       AliasProperty  NPM = NonpagedSystemMemorySize
...

Notitie

Get-Member elimineert duplicaten, dus als de objecten allemaal van hetzelfde type zijn, wordt slechts één objecttype weergegeven.

Als u echter de parameter InputObject van Get-Membergebruikt, ontvangt u Get-Member een matrix van System.Diagnostics.Process-objecten als één eenheid. Hiermee worden de eigenschappen van een matrix met objecten weergegeven. (Noteer het matrixsymbool ([]) na de naam van het type System.Object .)

Voorbeeld:

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()
...

Dit resultaat is mogelijk niet wat u bedoelde. Maar nadat u het begrijpt, kunt u het gebruiken. Alle matrixobjecten hebben bijvoorbeeld een eigenschap Count . U kunt dit gebruiken om het aantal processen te tellen dat op de computer wordt uitgevoerd.

Voorbeeld:

(Get-Process).count

Het is belangrijk om te onthouden dat objecten die via de pijplijn worden verzonden, één voor één worden geleverd.

Systeemeigen opdrachten gebruiken in de pijplijn

Met PowerShell kunt u systeemeigen externe opdrachten opnemen in de pijplijn. Het is echter belangrijk om te weten dat de pijplijn van PowerShell objectgeoriënteerd is en geen ondersteuning biedt voor onbewerkte bytegegevens.

Uitvoer doorsturen of omleiden vanuit een systeemeigen programma dat onbewerkte bytegegevens uitvoert, converteert de uitvoer naar .NET-tekenreeksen. Deze conversie kan leiden tot beschadiging van de uitvoer van onbewerkte gegevens.

PowerShell 7.4 heeft echter de PSNativeCommandPreserveBytePipe experimentele functie toegevoegd die bytestreamgegevens bewaart bij het omleiden van de stdout-stream van een systeemeigen opdracht naar een bestand of wanneer bytestreamgegevens worden gesluisd naar de stdin-stroom van een systeemeigen opdracht.

Met behulp van de systeemeigen opdracht curl kunt u bijvoorbeeld een binair bestand downloaden en opslaan op schijf met behulp van omleiding.

$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

U kunt de bytestreamgegevens ook doorsluisen naar de stdin-stroom van een andere systeemeigen opdracht. In het volgende voorbeeld wordt een gezipt TAR-bestand gedownload met behulp van curl. De gedownloade bestandsgegevens worden naar de tar opdracht gestreamd om de inhoud van het archief te extraheren.

# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .

U kunt ook de bytestream-uitvoer van een PowerShell-opdracht doorsluisen naar de invoer van de systeemeigen opdracht. In de volgende voorbeelden wordt Invoke-WebRequest hetzelfde TAR-bestand gedownload als in het vorige voorbeeld.

# 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 .

Deze functie biedt geen ondersteuning voor bytestreamgegevens bij het omleiden van stderr-uitvoer naar stdout. Wanneer u de stderr - en stdout-stromen combineert, worden de gecombineerde stromen behandeld als tekenreeksgegevens.

Pijplijnfouten onderzoeken

Wanneer PowerShell de gesluisde objecten niet kan koppelen aan een parameter van de ontvangende cmdlet, mislukt de opdracht.

In het volgende voorbeeld proberen we een registervermelding van de ene registersleutel naar de andere te verplaatsen. De Get-Item cmdlet haalt het doelpad op, dat vervolgens wordt doorgesluisd naar de Move-ItemProperty cmdlet. Met de Move-ItemProperty opdracht geeft u het huidige pad en de naam van de registervermelding die moet worden verplaatst.

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

De opdracht mislukt en PowerShell geeft het volgende foutbericht weer:

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

Gebruik de Trace-Command cmdlet om het parameterbindingsonderdeel van PowerShell te traceren. In het volgende voorbeeld wordt parameterbinding aangetroffen terwijl de pijplijn wordt uitgevoerd. De PSHost-parameter geeft de traceringsresultaten weer in de console en de FilePath-parameter verzendt de traceringsresultaten naar het debug.txt bestand voor later gebruik.

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
}

De resultaten van de tracering zijn lang, maar ze tonen de waarden die aan de Get-Item cmdlet zijn gebonden en vervolgens de benoemde waarden die aan de Move-ItemProperty cmdlet zijn gebonden.

...
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`]
...

Ten slotte ziet u dat de poging om het pad te binden aan de doelparameter mislukt Move-ItemProperty .

...
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
...

Gebruik de Get-Help cmdlet om de kenmerken van de parameter Destination weer te geven.

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

De resultaten tonen aan dat doel alleen pijplijninvoer op eigenschapsnaam gebruikt. Daarom moet het object met piped een eigenschap met de naam Destination hebben.

Gebruik Get-Member deze functie om de eigenschappen van het object te zien die afkomstig zijn van Get-Item.

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

In de uitvoer ziet u dat het item een Microsoft.Win32.RegistryKey-object is dat geen doeleigenschap heeft. Dit verklaart waarom de opdracht is mislukt.

De parameter Path accepteert pijplijninvoer op naam of op waarde.

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

Om de opdracht op te lossen, moeten we de bestemming in de Move-ItemProperty cmdlet opgeven en gebruiken Get-Item om het pad op te halen van het item dat we willen verplaatsen.

Voorbeeld:

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

Intrinsieke lijnvervolging

Zoals al is besproken, is een pijplijn een reeks opdrachten die zijn verbonden door pijplijnoperators (|), meestal geschreven op één regel. Voor leesbaarheid kunt u echter met PowerShell de pijplijn over meerdere lijnen splitsen. Wanneer een pijpoperator het laatste token op de regel is, voegt de PowerShell-parser de volgende regel toe aan de huidige opdracht om door te gaan met de constructie van de pijplijn.

Bijvoorbeeld de volgende pijplijn met één regel:

Command-1 | Command-2 | Command-3

kan worden geschreven als:

Command-1 |
    Command-2 |
    Command-3

De voorloopspaties op de volgende lijnen zijn niet significant. De inspringing verbetert de leesbaarheid.

PowerShell 7 voegt ondersteuning toe voor het vervolg van pijplijnen met het pijplijnteken aan het begin van een regel. In de volgende voorbeelden ziet u hoe u deze nieuwe functionaliteit kunt gebruiken.

# 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

Belangrijk

Als u interactief in de shell werkt, plakt u code met pijplijnen aan het begin van een regel alleen wanneer u Ctrl+V gebruikt om te plakken. Klik met de rechtermuisknop op plakbewerkingen om de regels één voor één in te voegen. Omdat de regel niet eindigt op een pijplijnteken, wordt in PowerShell van mening dat de invoer is voltooid en die regel wordt uitgevoerd zoals ingevoerd.

Zie ook