Delen via


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 voor de tweede opdracht. En die uitvoer kan worden verzonden naar nog een andere opdracht. Het resultaat is een complexe opdrachtketen of pijplijn die bestaat uit een reeks eenvoudige opdrachten.

Bijvoorbeeld:

Command-1 | Command-2 | Command-3

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

In een pijplijn worden de opdrachten van links naar rechts verwerkt. 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.

Bijvoorbeeld:

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 via de pijplijn wordt verzonden.

In dit pijplijnvoorbeeld worden de tekstbestanden in de huidige map opgehaald, worden alleen de bestanden geselecteerd die meer dan 10.000 bytes lang zijn, 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 wanneer 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-cmdletdoorsnijden naar een andere cmdlet van hetzelfde zelfstandig naamwoord. U kunt bijvoorbeeld de uitvoer van de Get-Service cmdlet doorsluizen naar de Start-Service cmdlets of Stop-Service .

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

Get-Service wmi | Start-Service

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

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

Veel van de cmdlets voor hulpprogramma's, zoals Get-Member, Where-Object, Sort-Object, Group-Object, en Measure-Object worden 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 sorteert op het aantal geopende ingangen in elk proces.

Get-Process | Sort-Object -Property handles

U kunt objecten doorsluizen naar de cmdlets voor opmaak, export en uitvoer, zoals Format-List, Format-Table, Export-Clixml, Export-CSVen Out-File.

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 doorsluizen naar PowerShell-cmdlets. Bijvoorbeeld:

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 stromen Success en Error zijn vergelijkbaar met de stromen stdin en stderr 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 worden gebonden aan cmdlet-parameters en worden verwerkt tijdens het uitvoeren van de pijplijn.

Accepteert pijplijninvoer

Als u pipelining wilt ondersteunen, 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

of

Get-Help Start-Service -Parameter *

De Help voor de Start-Service cmdlet laat zien 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 naar Start-Serviceverzendt, 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 kunnen worden geconverteerd naar dat type.

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

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

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

Sommige parameters kunnen objecten accepteren op basis van zowel de waarde als de 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 doorgesluisde objecten te koppelen aan een parameter van de ontvangende cmdlet.

Het onderdeel parameterbinding van PowerShell koppelt de invoerobjecten aan cmdlet-parameters op basis van 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 cmdlet heeft bijvoorbeeld Start-Service veel parameters, maar slechts twee van hen, Name en InputObject accepteren pijplijninvoer. De parameter Name gebruikt tekenreeksen en de parameter InputObject neemt serviceobjecten. Daarom kunt u tekenreeksen, serviceobjecten en objecten doorsluizen met eigenschappen die kunnen worden geconverteerd naar tekenreeks- of serviceobjecten.

PowerShell beheert parameterbinding zo efficiënt mogelijk. U kunt powershell niet voorstellen of dwingen om een binding met een specifieke parameter aan te gaan. De opdracht mislukt als PowerShell de objecten met pijpen niet kan binden.

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

Een-voor-een-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 voorbeeld van een pijplijn. 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 InputObject-parameter van Format-Table om de objectverzameling te verzenden.

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, worden de objecten door PowerShell één voor één naar de opdracht verzonden. 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ïnventareerde items worden één voor één via de pijplijn verzonden. PowerShell inventariseert ook System.Data.DataTable-typen via de Rows eigenschap .

Er zijn enkele uitzonderingen op automatische inventarisatie.

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

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 doorstuurt naar de Get-Member cmdlet, verzendt PowerShell elk procesobject één voor één naar Get-Member. Get-Member geeft de .NET-klasse (type) van de procesobjecten en hun 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 dubbele waarden, dus als de objecten allemaal van hetzelfde type zijn, wordt slechts één objecttype weergegeven.

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

Bijvoorbeeld:

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 als u het begrijpt, kunt u het gebruiken. Alle matrixobjecten hebben bijvoorbeeld de eigenschap Count . U kunt dit gebruiken om het aantal processen te tellen dat op de computer wordt uitgevoerd.

Bijvoorbeeld:

(Get-Process).count

Het is belangrijk om te onthouden dat objecten die door 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 te weten dat de pijplijn van PowerShell objectgeoriënteerd is en geen ondersteuning biedt voor onbewerkte bytegegevens.

Het doorsturen van uitvoer van 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.

Als tijdelijke oplossing roept u de systeemeigen opdrachten aan met behulp van cmd.exe /c of sh -c en het gebruik van de | operators en > van de systeemeigen shell.

Pijplijnfouten onderzoeken

Wanneer PowerShell de doorgesluisde 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 Move-ItemProperty de opdracht geeft u het huidige pad en de naam op 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

Als u dit wilt onderzoeken, gebruikt u de Trace-Command cmdlet om het parameterbindingsonderdeel van PowerShell te traceren. In het volgende voorbeeld wordt de parameterbinding bijhouden terwijl de pijplijn wordt uitgevoerd. De parameter PSHost 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 laten zien dat de waarden worden gebonden aan de Get-Item cmdlet en vervolgens de benoemde waarden worden gebonden aan de Move-ItemProperty cmdlet.

...
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 naar de doelparameter van Move-ItemProperty te binden, is mislukt.

...
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 doelparameter 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 laten zien dat doel alleen pijplijninvoer 'op eigenschapsnaam' gebruikt. Daarom moet het doorgesluisde object een eigenschap met de naam Bestemming hebben.

Gebruik Get-Member om de eigenschappen weer te geven van het object dat afkomstig is van Get-Item.

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

De uitvoer laat zien dat het item een Microsoft.Win32.RegistryKey-object is dat geen doeleigenschap heeft. Dit verklaart waarom de opdracht is mislukt.

De path parameter 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 opgeven in de Move-ItemProperty cmdlet en gebruiken Get-Item om het pad op te halen van het item dat we willen verplaatsen.

Bijvoorbeeld:

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 de leesbaarheid kunt u met PowerShell de pijplijn echter splitsen over meerdere regels. Wanneer een pipe-operator 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 regels 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

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

Zie ook