Dela via


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-Objectoch 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-CSVExport-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-Servicefö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 till Get-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-TableInputObject 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-Membertar 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.

Se även

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach