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-Object
worden 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-File
Export-CSV
. Export-Clixml
Format-Table
Format-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 naarGet-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.
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 deIDictionary
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-Member
gebruikt, 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.