Om 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 dessa utdata kan skickas till ännu ett kommando. Resultatet är en komplex kommandokedja eller pipeline som består av en serie enkla kommandon.
Exempel:
Command-1 | Command-2 | Command-3
I det här exemplet skickas de objekt som Command-1
genererar 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.
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 de 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 formaterings-, export- och utdata-cmdletar, till exempel Format-List
, Format-Table
, Export-CSV
Export-Clixml
, 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 *
Med lite övning kommer du att märka att om du kombinerar enkla kommandon i pipelines sparar du tid och skriver, vilket gör skriptet mer effektivt.
Så här fungerar pipelines
I det här avsnittet beskrivs hur indataobjekt binds 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 för 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.
Till exempel accepterar name-parametern
Start-Service
för 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 name-parametern
Start-Service
för acceptera objekt som har en Namn-egenskap . Om du vill visa en lista över egenskaperna för ett objekt kan du 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 skickar objekt från ett kommando till ett annat kommando försöker PowerShell associera piped-objekten med en parameter för den mottagande cmdleten.
Parameterbindningskomponenten i PowerShell associerar indataobjekten med cmdlet-parametrar enligt följande kriterier:
- Parametern måste acceptera indata från en pipeline.
- Parametern måste acceptera den 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 bara två av dem, Name och InputObject accepterar pipelineindata. Parametern Name tar strängar och parametern InputObject tar tjänstobjekt. Därför kan du skicka strä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 de piped-objekten.
Mer information om felsökning av bindningsfel finns i Undersöka pipelinefel senare i den här artikeln.
En i taget-bearbetning
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 det som att använda parametern Format-Table
InputObject för för att skicka objektsamlingen.
Vi kan till exempel spara samlingen med tjänster till en variabel som skickas med hjälp av 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 enda 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 och skickar medlemmarna via pipelinen en i taget. Undantaget är [hashtable]
, som kräver ett anrop till GetEnumerator()
metoden .
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 :
På samma sätt, 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 (typen) 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
...
Anteckning
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 .)
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 förstår det kan du använda det. Alla matrisobjekt har till exempel egenskapen Antal . Du kan använda det för att räkna antalet processer som körs på datorn.
Exempel:
(Get-Process).count
Det är viktigt att komma ihåg att objekt som skickas ned i pipelinen levereras en i taget.
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
Undersök genom att använda cmdleten Trace-Command
för att spåra parameterbindningskomponenten i PowerShell. I följande exempel spåras parameterbindning medan pipelinen körs. PSHost-parametern visar spårningsresultaten i -konsolen och FilePath-parametern 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ångt, men de visar de värden 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 en 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 till det objekt som vi vill flytta.
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 har diskuterat ä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 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 byggandet av pipelinen.
Till exempel följande pipeline med en enda rad:
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.