about_Pipelines

Kort beskrivning

Kombinera kommandon i pipelines i PowerShell

Lång beskrivning

En pipeline är en serie kommandon som är anslutna via pipelineoperatorer | ( ) (ASCII 124). Varje pipelineoperator skickar resultatet av 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 ytterligare 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 Command-1 objekt som skickar 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 några 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 Get-Process cmdleten för att hämta ett objekt som representerar Anteckningar-processen. Den använder en pipelineoperator ( | ) för att skicka processobjektet till Stop-Process cmdleten, vilket stoppar Anteckningar-processen. Observera att Stop-Process kommandot inte har någon name- eller ID-parameter för att ange processen, eftersom den angivna processen skickas via pipelinen.

Det här pipeline-exemplet 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 angiven ordning. 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-cmdlets är utformade för att stödja pipelines. I de flesta fall kan du skicka resultatet av en Get-cmdlet till en annan cmdlet av samma substantiv. Du kan till exempel skicka utdata från Get-Service cmdleten till Start-Service Stop-Service cmdletarna eller .

Den här exempelpipelinen startar WMI-tjänsten på datorn:

Get-Service wmi | Start-Service

Till ett annat exempel kan du skicka utdata från Get-Item eller Get-ChildItem inom PowerShell-registerprovidern till New-ItemProperty cmdleten . Det här exemplet lägger till en ny registerpost, NoOfEmployees, med värdet 8124 i registernyckeln MyCompany.

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

Många av verktygs-cmdletarna, till exempel Get-Member , , , och används nästan uteslutande i Where-Object Sort-Object Group-Object Measure-Object pipelines. Du kan skicka alla objekttyper till dessa cmdlets. 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-cmdletarna, till Format-List exempel , , och Format-Table Export-Clixml Export-CSV Out-File .

Det här exemplet visar hur du använder Format-List cmdleten för att visa en lista över egenskaper för ett processobjekt.

Get-Process winlogon | Format-List -Property *

Du kan också skicka utdata från interna kommandon till PowerShell-cmdlets. 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 i andra gränssnitt. Stdin är dock inte anslutet till PowerShell-pipelinen för indata. Mer information finns i about_Redirection.

Med lite övning kommer du att se att du sparar tid och skriver genom att kombinera enkla kommandon i pipelines och gör skripten mer effektiva.

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. Använd kommandot Get-Help 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 avgöra vilka av parametrarna för Start-Service cmdleten som accepterar pipeline-indata skriver du:

Get-Help Start-Service -Full

eller

Get-Help Start-Service -Parameter *

Hjälpen för Start-Service cmdleten 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 försöker PowerShell associera Start-Service objekten med parametrarna InputObject och Name.

Metoder för att acceptera pipelineindata

Cmdlets-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 pipeline-indata 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 ta emot objekt som har en Name-egenskap. Om du vill visa egenskaperna för ett objekt, så 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 kör 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 kriterier:

  • 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 har till exempel många parametrar, men bara två av Start-Service 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 parameterbindningen 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 felsökning av bindningsfel finns i Undersöka pipelinefel senare i den här artikeln.

Bearbetning en i taget

Att skicka objekt till ett kommando liknar 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 InputObject för Format-Table för att skicka objektsamlingen.

Vi kan till exempel spara samlingen med 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 en i taget. När du använder en kommandoparameter skickas objekten som ett enda matrisobjekt. Den här mindre skillnaden har betydande konsekvenser.

När du kör en pipeline räknar PowerShell automatiskt upp alla typer som implementerar gränssnittet och skickar medlemmarna via IEnumerable pipelinen en i taget. Undantaget är [hashtable] , som kräver ett anrop till metoden GetEnumerator() .

I följande exempel kommer en matris och en hash-tabell att ledas till cmdleten för att räkna antalet objekt Measure-Object som tagits emot från pipelinen. Matrisen har flera medlemmar och hash-tabellen 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 skickar PowerShell varje processobjekt, ett i taget, till om du skickar flera processobjekt från Get-Process Get-Member cmdleten till cmdleten 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
...

Anteckning

Get-Member eliminerar dubbletter, så om objekten är av samma typ visas bara en objekttyp.

Men om du använder parametern InputObject i tar emot en matris med Get-Member Get-Member System.Diagnostics.Process-objekt som en enda enhet. Den visar egenskaperna för en matris med objekt. (Observera matrissymbolen ( [] ) efter typnamnet System.Object.)

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 ett 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. Get-ItemCmdleten hämtar målsökvägen, som sedan kommer till Move-ItemProperty cmdleten . 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 detta använder Trace-Command du cmdleten för att spåra parameterbindningskomponenten i PowerShell. Följande exempel spårar parameterbindningen medan pipelinen körs. Parametern PSHost visar spårningsresultaten i konsolen och FilePath-parametern skickar spårningsresultaten till debug.txt 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 de värden som är bundna till cmdleten och sedan de namngivna värdena som binds Get-Item till Move-ItemProperty cmdleten.

...
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 det 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 Get-Help cmdleten 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ål 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 och använda för att hämta sökvägen för Move-ItemProperty det objekt som vi vill Get-Item flytta.

Exempel:

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Inbyggd linje fortsättning

Som vi redan nämnt är en pipeline en serie kommandon som är anslutna av pipelineoperatorer ( | ), som vanligtvis skrivs på en enda rad. Men för läsbarhet kan du med PowerShell dela upp pipelinen över flera rader. 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 bygget av pipelinen.

Till exempel följande pipeline med en rad:

Command-1 | Command-2 | Command-3

kan skrivas som:

Command-1 |
  Command-2 |
    Command-3

De inledande blankstegen på efterföljande rader är inte signifikanta. Indraget förbättrar läsbarheten.

PowerShell 7 lägger till stöd för fortsättning av pipelines med pipeline-tecknet 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 bara in kod med pipelines i början av en rad när du använder Ctrl + V för att klistra in. Högerklicka på klistra in åtgärder infoga raderna en i taget. Eftersom raden inte slutar med ett pipelinetecken betraktar PowerShell indata som slutförda och kör den raden enligt inmatningen.

Se även

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach