about_Pipelines
Kort beskrivning
Kombinera kommandon till pipelines i PowerShell
Lång beskrivning
En pipeline är en serie kommandon som är anslutna av pipelineoperatorer (|
) (ASCII 124). Varje pipelineoperator skickar resultatet från föregående kommando till nästa kommando.
Utdata från det första kommandot kan skickas för bearbetning som indata till det andra kommandot. Och utdata kan skickas till ännu ett kommando. Resultatet är en komplex kommandokedja eller pipeline som består av en serie enkla kommandon.
Ett exempel:
Command-1 | Command-2 | Command-3
I det här exemplet skickas de objekt som Command-1
avger till Command-2
.
Command-2
bearbetar objekten och skickar dem till Command-3
. Command-3
bearbetar objekten och skickar dem nedåt i pipelinen. Eftersom det inte finns fler kommandon i pipelinen visas resultatet i konsolen.
I en pipeline bearbetas kommandona i ordning från vänster till höger. Bearbetningen hanteras som en enda åtgärd och utdata visas när den genereras.
Här är ett enkelt exempel. Följande kommando hämtar Anteckningar-processen och stoppar den sedan.
Ett exempel:
Get-Process notepad | Stop-Process
Det första kommandot använder cmdleten Get-Process
för att hämta ett objekt som representerar Anteckningar-processen. Den använder en pipelineoperator (|
) för att skicka processobjektet till cmdleten Stop-Process
, vilket stoppar Anteckningar-processen. Observera att Stop-Process
kommandot inte har någon namn- eller ID-parameter för att ange processen, eftersom den angivna processen skickas via pipelinen.
Det här pipelineexemplet hämtar textfilerna i den aktuella katalogen, väljer endast de filer som är mer än 10 000 byte långa, sorterar dem efter längd och visar namnet och längden på varje fil i en tabell.
Get-ChildItem -Path *.txt |
Where-Object {$_.length -gt 10000} |
Sort-Object -Property length |
Format-Table -Property name, length
Den här pipelinen består av fyra kommandon i den angivna ordningen. Följande bild visar utdata från varje kommando när det skickas till nästa kommando i pipelinen.
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
Använda pipelines
De flesta PowerShell-cmdletar är utformade för att stödja pipelines. I de flesta fall kan du skicka resultatet av en Get-cmdlet till en annan cmdlet med samma substantiv.
Du kan till exempel skicka utdata från cmdleten Get-Service
till cmdletarna Start-Service
eller Stop-Service
.
Den här exempelpipelinen startar WMI-tjänsten på datorn:
Get-Service wmi | Start-Service
Du kan till exempel skicka utdata Get-Item
från eller Get-ChildItem
inom PowerShell-registerprovidern till cmdleten New-ItemProperty
. I det här exemplet läggs en ny registerpost, NoOfEmployees, med värdet 8124, till registernyckeln MyCompany .
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Många av verktygs-cmdletarna, till exempel Get-Member
, Where-Object
, Sort-Object
, Group-Object
och Measure-Object
används nästan uteslutande i pipelines. Du kan skicka alla objekttyper till dessa cmdletar. Det här exemplet visar hur du sorterar alla processer på datorn efter antalet öppna referenser i varje process.
Get-Process | Sort-Object -Property handles
Du kan skicka objekt till cmdletar för formatering, export och utdata, till exempel Format-List
, Format-Table
, Export-Clixml
, Export-CSV
och Out-File
.
Det här exemplet visar hur du använder cmdleten Format-List
för att visa en lista med egenskaper för ett processobjekt.
Get-Process winlogon | Format-List -Property *
Du kan också skicka utdata från interna kommandon till PowerShell-cmdletar. Till exempel:
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
Viktigt!
Strömmarna Success och Error liknar stdin- och stderr-strömmarna för andra skal. Stdin är dock inte ansluten till PowerShell-pipelinen för indata. Mer information finns i about_Redirection.
Med lite övning kommer du att upptäcka att kombinera enkla kommandon i pipelines sparar tid och skriver, och gör skriptet mer effektivt.
Så här fungerar pipelines
I det här avsnittet beskrivs hur indataobjekt är bundna till cmdlet-parametrar och bearbetas under pipelinekörningen.
Accepterar pipelineindata
För att stödja pipelining måste den mottagande cmdleten ha en parameter som accepterar pipelineindata. Get-Help
Använd kommandot med alternativen Fullständig eller Parameter för att avgöra vilka parametrar för en cmdlet som accepterar pipelineindata.
Om du till exempel vill ta reda på vilka av parametrarna i cmdleten Start-Service
som accepterar pipelineindata skriver du:
Get-Help Start-Service -Full
eller
Get-Help Start-Service -Parameter *
Hjälpen för cmdleten Start-Service
visar att endast parametrarna InputObject och Name accepterar pipelineindata.
-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
När du skickar objekt via pipelinen till Start-Service
försöker PowerShell associera objekten med parametrarna InputObject och Name .
Metoder för att acceptera pipelineindata
Cmdletar-parametrar kan acceptera pipelineindata på något av två olika sätt:
ByValue: Parametern accepterar värden som matchar den förväntade .NET-typen eller som kan konverteras till den typen.
Parametern
Start-Service
Namn för accepterar till exempel pipelineindata efter värde. Den kan acceptera strängobjekt eller -objekt som kan konverteras till strängar.ByPropertyName: Parametern accepterar endast indata när indataobjektet har en egenskap med samma namn som parametern.
Till exempel kan parametern
Start-Service
Namn för acceptera objekt som har en namnegenskap . Ange egenskaperna för ett objekt genom att skicka det tillGet-Member
.
Vissa parametrar kan acceptera objekt med både värde- eller egenskapsnamn, vilket gör det enklare att ta indata från pipelinen.
Parameterbindning
När du dirigerar objekt från ett kommando till ett annat kommando försöker PowerShell associera piped-objekten med en parameter för den mottagande cmdleten.
PowerShells parameterbindningskomponent associerar indataobjekten med cmdlet-parametrar enligt följande villkor:
- Parametern måste acceptera indata från en pipeline.
- Parametern måste acceptera vilken typ av objekt som skickas eller en typ som kan konverteras till den förväntade typen.
- Parametern användes inte i kommandot .
Cmdleten Start-Service
har till exempel många parametrar, men endast två av dem, Name och InputObject accepterar pipelineindata. Parametern Namn tar strängar och parametern InputObject tar tjänstobjekt. Därför kan du skicka rörsträngar, tjänstobjekt och objekt med egenskaper som kan konverteras till sträng- eller tjänstobjekt.
PowerShell hanterar parameterbindning så effektivt som möjligt. Du kan inte föreslå eller tvinga PowerShell att binda till en specifik parameter. Kommandot misslyckas om PowerShell inte kan binda piped-objekten.
Mer information om hur du felsöker bindningsfel finns i Undersöka pipelinefel senare i den här artikeln.
Bearbetning en i taget
Att skicka objekt till ett kommando är ungefär som att använda en parameter i kommandot för att skicka objekten. Nu ska vi titta på ett pipelineexempel. I det här exemplet använder vi en pipeline för att visa en tabell med tjänstobjekt.
Get-Service | Format-Table -Property Name, DependentServices
Funktionellt är detta som att använda parametern Format-Table
InputObject för för att skicka objektsamlingen.
Vi kan till exempel spara samlingen av tjänster till en variabel som skickas med parametern InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
Eller så kan vi bädda in kommandot i parametern InputObject .
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Det finns dock en viktig skillnad. När du skickar flera objekt till ett kommando skickar PowerShell objekten till kommandot ett i taget. När du använder en kommandoparameter skickas objekten som ett enskilt matrisobjekt. Denna mindre skillnad har betydande konsekvenser.
När du kör en pipeline räknar PowerShell automatiskt upp alla typer som implementerar IEnumerable
gränssnittet eller dess generiska motsvarighet. Uppräknade objekt skickas via pipelinen en i taget. PowerShell räknar också upp System.Data.DataTable-typer via egenskapen Rows
.
Det finns några undantag för automatisk uppräkning.
- Du måste anropa
GetEnumerator()
metoden för hash-tabeller, typer som implementerarIDictionary
gränssnittet eller dess generiska motsvarighet och System.Xml.XmlNode-typer . - Klassen System.String implementerar
IEnumerable
, men PowerShell räknar inte upp strängobjekt.
I följande exempel skickas en matris och en hashtable till cmdleten Measure-Object
för att räkna antalet objekt som tas emot från pipelinen. Matrisen har flera medlemmar och hashtabellen har flera nyckel/värde-par. Endast matrisen räknas upp en i taget.
@(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 :
Om du skickar flera processobjekt från cmdleten Get-Process
till cmdleten Get-Member
skickar PowerShell varje processobjekt, ett i taget, till Get-Member
. Get-Member
visar .NET-klassen (typ) för processobjekten och deras egenskaper och metoder.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Kommentar
Get-Member
eliminerar dubbletter, så om objekten är av samma typ visas bara en objekttyp.
Men om du använder parametern InputObject för Get-Member
tar du Get-Member
emot en matris med System.Diagnostics.Process-objekt som en enda enhet. Den visar egenskaperna för en matris med objekt. (Observera matrissymbolen ([]
) efter namnet på System.Object-typen .)
Ett exempel:
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()
...
Det här resultatet kanske inte är det du avsåg. Men när du har förstått det kan du använda det. Till exempel har alla matrisobjekt en count-egenskap . Du kan använda det för att räkna antalet processer som körs på datorn.
Ett exempel:
(Get-Process).count
Det är viktigt att komma ihåg att objekt som skickas ned i pipelinen levereras en i taget.
Använda interna kommandon i pipelinen
Med PowerShell kan du inkludera interna externa kommandon i pipelinen. Det är dock viktigt att observera att PowerShells pipeline är objektorienterad och inte stöder rådata.
Rördragning eller omdirigering av utdata från ett internt program som matar ut rådata konverterar utdata till .NET-strängar. Den här konverteringen kan orsaka skadade rådatautdata.
PowerShell 7.4 lade dock till den PSNativeCommandPreserveBytePipe
experimentella funktionen som bevarar byteströmsdata vid omdirigering av stdout-strömmen för ett inbyggt kommando till en fil eller när byteströmdata skickas till stdin-strömmen för ett internt kommando.
Med det interna kommandot curl
kan du till exempel ladda ned en binär fil och spara den på disk med hjälp av omdirigering.
$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
Du kan också skicka byteströmdata till stdin-strömmen för ett annat inbyggt kommando. I följande exempel hämtas en zippad TAR-fil med .curl
De nedladdade fildata strömmas till tar
kommandot för att extrahera innehållet i arkivet.
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
Du kan också skicka byteströmutdata från ett PowerShell-kommando till indata från det interna kommandot. I följande exempel används Invoke-WebRequest
för att ladda ned samma TAR-fil som i föregående exempel.
# 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 .
Den här funktionen stöder inte byteströmsdata vid omdirigering av stderr-utdata till stdout. När du kombinerar stderr - och stdout-strömmarna behandlas de kombinerade strömmarna som strängdata.
Undersöka pipelinefel
När PowerShell inte kan associera piped-objekten med en parameter för den mottagande cmdleten misslyckas kommandot.
I följande exempel försöker vi flytta en registerpost från en registernyckel till en annan. Cmdleten Get-Item
hämtar målsökvägen, som sedan skickas till cmdleten Move-ItemProperty
. Kommandot Move-ItemProperty
anger den aktuella sökvägen och namnet på registerposten som ska flyttas.
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
Kommandot misslyckas och PowerShell visar följande felmeddelande:
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
Om du vill undersöka det använder du cmdleten Trace-Command
för att spåra parameterbindningskomponenten i PowerShell. I följande exempel spåras parameterbindning medan pipelinen körs. Parametern PSHost visar spårningsresultaten i konsolen och parametern FilePath skickar spårningsresultatet debug.txt
till filen för senare referens.
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
}
Resultatet av spårningen är långa, men de visar värdena som är bundna till cmdleten Get-Item
och sedan de namngivna värden som är bundna till cmdleten Move-ItemProperty
.
...
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`]
...
Slutligen visar den att försöket att binda sökvägen till målparametern Move-ItemProperty
misslyckades.
...
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
...
Använd cmdleten Get-Help
för att visa attributen för målparametern.
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
Resultatet visar att Målet endast tar pipelineindata "efter egenskapsnamn". Därför måste piped-objektet ha en egenskap med namnet Destination.
Använd Get-Member
för att se egenskaperna för objektet som kommer från Get-Item
.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
Utdata visar att objektet är ett Microsoft.Win32.RegistryKey-objekt som inte har någon målegenskap . Det förklarar varför kommandot misslyckades.
Parametern Path accepterar pipelineindata efter namn eller värde.
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
För att åtgärda kommandot måste vi ange målet i cmdleten Move-ItemProperty
och använda Get-Item
för att hämta sökvägen för det objekt som vi vill flytta.
Ett exempel:
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Fortsättning på inbyggda linjer
Som vi redan nämnt är en pipeline en serie kommandon som är anslutna av pipelineoperatorer (|
), vanligtvis skrivna på en enda rad. För läsbarhet kan du dock dela upp pipelinen över flera rader i PowerShell. När en pipe-operator är den sista token på raden ansluter PowerShell-parsern nästa rad till det aktuella kommandot för att fortsätta konstruktionen av pipelinen.
Till exempel följande enradspipeline:
Command-1 | Command-2 | Command-3
kan skrivas som:
Command-1 |
Command-2 |
Command-3
De inledande blankstegen på efterföljande linjer är inte signifikanta. Indraget förbättrar läsbarheten.
PowerShell 7 lägger till stöd för fortsättning av pipelines med pipelinetecknet i början av en rad. I följande exempel visas hur du kan använda den här nya funktionen.
# 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
Viktigt!
När du arbetar interaktivt i gränssnittet klistrar du in kod med pipelines i början av en rad endast när du använder Ctrl+V för att klistra in. Högerklicka på inklistringsåtgärder för att infoga raderna en i taget. Eftersom raden inte slutar med ett pipelinetecken anser PowerShell att indata är fullständiga och kör raden som angiven.