about_Pipelines

Krótki opis

Łączenie poleceń w potokach w programie PowerShell

Długi opis

Potok to seria poleceń połączonych przez operatory potoku (|) (ASCII 124). Każdy operator potoku wysyła wyniki poprzedniego polecenia do następnego polecenia.

Dane wyjściowe pierwszego polecenia można wysłać do przetwarzania jako dane wejściowe do drugiego polecenia. I te dane wyjściowe mogą być wysyłane do jeszcze innego polecenia. Wynikiem jest złożony łańcuch poleceń lub potok składający się z serii prostych poleceń.

Przykład:

Command-1 | Command-2 | Command-3

W tym przykładzie obiekty emitujące Command-1 są wysyłane do Command-2obiektu . Command-2 przetwarza obiekty i wysyła je do Command-3programu . Command-3 przetwarza obiekty i wysyła je w dół potoku. Ponieważ w potoku nie ma więcej poleceń, wyniki są wyświetlane w konsoli programu .

W potoku polecenia są przetwarzane w kolejności od lewej do prawej. Przetwarzanie jest obsługiwane jako pojedyncza operacja, a dane wyjściowe są wyświetlane podczas jego generowania.

Oto prosty przykład. Następujące polecenie pobiera proces Notatnik, a następnie zatrzymuje go.

Przykład:

Get-Process notepad | Stop-Process

Pierwsze polecenie używa Get-Process polecenia cmdlet do pobrania obiektu reprezentującego proces Notatnik. Używa operatora potoku (|) do wysyłania obiektu procesu do Stop-Process polecenia cmdlet, co zatrzymuje proces Notatnik. Zwróć uwagę, że Stop-Process polecenie nie ma parametru Name lub ID w celu określenia procesu, ponieważ określony proces jest przesyłany za pośrednictwem potoku.

Ten przykład potoku pobiera pliki tekstowe w bieżącym katalogu, wybiera tylko pliki, które mają więcej niż 10 000 bajtów długości, sortuje je według długości i wyświetla nazwę i długość każdego pliku w tabeli.

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

Ten potok składa się z czterech poleceń w określonej kolejności. Poniższa ilustracja przedstawia dane wyjściowe z każdego polecenia, które jest przekazywane do następnego polecenia w potoku.

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

Korzystanie z potoków

Większość poleceń cmdlet programu PowerShell jest przeznaczona do obsługi potoków. W większości przypadków można przekazać wyniki polecenia cmdlet Get do innego polecenia cmdlet tego samego rzędu. Możesz na przykład przekazać dane wyjściowe Get-Service polecenia cmdlet do Start-Service poleceń cmdlet lub Stop-Service .

Ten przykładowy potok uruchamia usługę WMI na komputerze:

Get-Service wmi | Start-Service

Na potrzeby innego przykładu możesz przekazać dane wyjściowe Get-Item lub Get-ChildItem w obrębie dostawcy rejestru programu PowerShell do New-ItemProperty polecenia cmdlet . W tym przykładzie dodano nowy wpis rejestru NoOfEmployees o wartości 8124 do klucza rejestru MyCompany.

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

Wiele poleceń cmdlet narzędzia, takich jak Get-Member, Where-Object, Sort-Object, Group-Objecti Measure-Object , jest używanych prawie wyłącznie w potokach. Do tych poleceń cmdlet można przekazać dowolny typ obiektu. W tym przykładzie pokazano, jak sortować wszystkie procesy na komputerze według liczby otwartych dojść w każdym procesie.

Get-Process | Sort-Object -Property handles

Obiekty można przesyłać potokami do poleceń cmdlet formatowania, eksportowania i danych wyjściowych, takich jak Format-List, , Format-TableExport-Clixml, Export-CSV, i Out-File.

W tym przykładzie Format-List pokazano, jak za pomocą polecenia cmdlet wyświetlić listę właściwości obiektu procesu.

Get-Process winlogon | Format-List -Property *

Możesz również przekazać dane wyjściowe poleceń natywnych do poleceń cmdlet programu PowerShell. Na przykład:

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

Ważne

Strumienie powodzenia i błędu są podobne do strumieni stdin i stderr innych powłok. Jednak stdin nie jest połączony z potokiem programu PowerShell dla danych wejściowych. Aby uzyskać więcej informacji, zobacz about_Redirection.

Z odrobiną praktyki przekonasz się, że łączenie prostych poleceń w potoki pozwala zaoszczędzić czas i wpisywanie i zwiększa wydajność wykonywania skryptów.

Jak działają potoki

W tej sekcji wyjaśniono, jak obiekty wejściowe są powiązane z parametrami polecenia cmdlet i przetwarzane podczas wykonywania potoku.

Akceptuje dane wejściowe potoku

Aby obsługiwać potokowanie, odbierające polecenie cmdlet musi mieć parametr, który akceptuje dane wejściowe potoku. Get-Help Użyj polecenia z opcjami Pełna lub Parametr, aby określić, które parametry polecenia cmdlet akceptują dane wejściowe potoku.

Aby na przykład określić, które parametry Start-Service polecenia cmdlet akceptują dane wejściowe potoku, wpisz:

Get-Help Start-Service -Full

lub

Get-Help Start-Service -Parameter *

Pomoc dla Start-Service polecenia cmdlet pokazuje, że tylko parametry InputObject i Name akceptują dane wejściowe potoku.

-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

Podczas wysyłania obiektów za pośrednictwem potoku do Start-Serviceprogramu Program PowerShell próbuje skojarzyć obiekty z parametrami InputObject i Name .

Metody akceptowania danych wejściowych potoku

Parametry poleceń cmdlet mogą akceptować dane wejściowe potoku na jeden z dwóch różnych sposobów:

  • ByValue: parametr akceptuje wartości zgodne z oczekiwanym typem platformy .NET lub, które można przekonwertować na ten typ.

    Na przykład parametr Name akceptowania danych wejściowych potoku Start-Service według wartości. Może on akceptować obiekty ciągów lub obiekty, które można przekonwertować na ciągi.

  • ByPropertyName: Parametr akceptuje dane wejściowe tylko wtedy, gdy obiekt wejściowy ma właściwość o tej samej nazwie co parametr.

    Na przykład parametr Start-Service Name obiektu może akceptować obiekty, które mają właściwość Name . Aby wyświetlić listę właściwości obiektu, należy przekazać go do Get-Memberelementu .

Niektóre parametry mogą akceptować obiekty według zarówno wartości, jak i nazwy właściwości, co ułatwia wprowadzanie danych wejściowych z potoku.

Powiązanie parametrów

Podczas potokowania obiektów z jednego polecenia do innego polecenia program PowerShell próbuje skojarzyć potokowe obiekty z parametrem odbierającego polecenia cmdlet.

Składnik powiązania parametrów programu PowerShell kojarzy obiekty wejściowe z parametrami polecenia cmdlet zgodnie z następującymi kryteriami:

  • Parametr musi akceptować dane wejściowe z potoku.
  • Parametr musi zaakceptować typ wysyłanego obiektu lub typ, który można przekonwertować na oczekiwany typ.
  • Parametr nie został użyty w poleceniu .

Na przykład Start-Service polecenie cmdlet ma wiele parametrów, ale tylko dwa z nich, Name i InputObject akceptują dane wejściowe potoku. Parametr Name przyjmuje ciągi, a parametr InputObject przyjmuje obiekty usługi. W związku z tym można potokować ciągi, obiekty usługi i obiekty z właściwościami, które można przekonwertować na ciąg lub obiekty usługi.

Program PowerShell zarządza powiązaniem parametrów tak wydajnie, jak to możliwe. Nie można sugerować ani wymuszać powiązania programu PowerShell z określonym parametrem. Polecenie kończy się niepowodzeniem, jeśli program PowerShell nie może powiązać potokowych obiektów.

Aby uzyskać więcej informacji na temat rozwiązywania problemów z błędami powiązań, zobacz Badanie błędów potoku w dalszej części tego artykułu.

Przetwarzanie jednorazowe

Potokowanie obiektów do polecenia jest podobne do użycia parametru polecenia w celu przesłania obiektów. Przyjrzyjmy się przykładowi potoku. W tym przykładzie używamy potoku do wyświetlania tabeli obiektów usługi.

Get-Service | Format-Table -Property Name, DependentServices

Funkcjonalnie jest to podobne do użycia parametru InputObject obiektu Format-Table w celu przesłania kolekcji obiektów.

Na przykład możemy zapisać kolekcję usług w zmiennej przekazanej przy użyciu parametru InputObject .

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Można też osadzić polecenie w parametrze InputObject .

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

Istnieje jednak ważna różnica. Podczas potoku wielu obiektów do polecenia program PowerShell wysyła obiekty do polecenia pojedynczo. Gdy używasz parametru polecenia, obiekty są wysyłane jako pojedynczy obiekt tablicy. Ta niewielka różnica ma znaczące konsekwencje.

Podczas wykonywania potoku program PowerShell automatycznie wylicza dowolny typ implementujący IEnumerable interfejs lub jego ogólny odpowiednik. Wyliczone elementy są wysyłane za pośrednictwem potoku pojedynczo. Program PowerShell wylicza również typy System.Data.DataTable za pomocą Rows właściwości .

Istnieje kilka wyjątków od automatycznego wyliczania.

  • Należy wywołać metodę GetEnumerator() tabel skrótów, typów implementujących IDictionary interfejs lub jego odpowiednik ogólny oraz typy System.Xml.XmlNode .
  • Klasa System.String implementuje IEnumerableelement , jednak program PowerShell nie wylicza obiektów ciągów.

W poniższych przykładach tablica i tabela skrótów są przesyłane potokiem do Measure-Object polecenia cmdlet w celu zliczenia liczby obiektów odebranych z potoku. Tablica ma wiele elementów członkowskich, a tabela skrótów ma wiele par klucz-wartość. Tylko tablica jest wyliczana pojedynczo.

@(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 :

Podobnie, jeśli potokujesz wiele obiektów procesów z Get-Process polecenia cmdlet do Get-Member polecenia cmdlet, program PowerShell wysyła każdy obiekt procesu, jeden naraz, do Get-Member. Get-Member wyświetla klasę .NET (typ) obiektów procesu oraz ich właściwości i metody.

Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Name      MemberType     Definition
----      ----------     ----------
Handles   AliasProperty  Handles = Handlecount
Name      AliasProperty  Name = ProcessName
NPM       AliasProperty  NPM = NonpagedSystemMemorySize
...

Uwaga

Get-Member eliminuje duplikaty, więc jeśli obiekty są tego samego typu, wyświetla tylko jeden typ obiektu.

Jeśli jednak używasz parametru InputObject klasy Get-Member, Get-Member otrzyma tablicę obiektów System.Diagnostics.Process jako pojedynczą jednostkę. Wyświetla właściwości tablicy obiektów. (Zanotuj symbol tablicy ([]) po nazwie typu System.Object .

Przykład:

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()
...

Ten wynik może nie być zamierzony. Ale po jego zrozumieniu możesz go użyć. Na przykład wszystkie obiekty tablicy mają właściwość Count . Można jej użyć do zliczenia liczby procesów uruchomionych na komputerze.

Przykład:

(Get-Process).count

Należy pamiętać, że obiekty wysyłane w potoku są dostarczane pojedynczo.

Używanie poleceń natywnych w potoku

Program PowerShell umożliwia dołączanie natywnych poleceń zewnętrznych do potoku. Należy jednak pamiętać, że potok programu PowerShell jest zorientowany obiektowo i nie obsługuje nieprzetworzonych danych bajtowych.

Potokowanie lub przekierowywanie danych wyjściowych z programu natywnego, który generuje nieprzetworzone dane bajtowe konwertuje dane wyjściowe na ciągi platformy .NET. Ta konwersja może spowodować uszkodzenie nieprzetworzonych danych wyjściowych.

Jednak program PowerShell 7.4 dodał funkcję eksperymentalną PSNativeCommandPreserveBytePipe , która zachowuje dane strumienia bajtów podczas przekierowywania strumienia stdout polecenia natywnego do pliku lub podczas potokowania danych strumienia bajtów do strumienia stdin polecenia natywnego.

Na przykład za pomocą natywnego polecenia curl można pobrać plik binarny i zapisać go na dysku przy użyciu przekierowania.

$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

Dane strumienia bajtowego można również przesłać potokowo do strumienia stdin innego natywnego polecenia. Poniższy przykład pobiera spakowany plik TAR przy użyciu polecenia curl. Pobrane dane pliku są przesyłane strumieniowo do tar polecenia w celu wyodrębnienia zawartości archiwum.

# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .

Możesz również przekazać potok danych wyjściowych strumienia bajtów polecenia programu PowerShell do danych wejściowych polecenia natywnego. W poniższych przykładach użyto Invoke-WebRequest metody , aby pobrać ten sam plik TAR co w poprzednim przykładzie.

# 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 .

Ta funkcja nie obsługuje danych strumienia bajtowego podczas przekierowywania danych wyjściowych stderr do stdout. Po połączeniu strumieni stderr i stdout połączone strumienie są traktowane jako dane ciągu.

Badanie błędów potoku

Jeśli program PowerShell nie może skojarzyć obiektów potokowych z parametrem odbierającego polecenia cmdlet, polecenie kończy się niepowodzeniem.

W poniższym przykładzie próbujemy przenieść wpis rejestru z jednego klucza rejestru do innego. Polecenie Get-Item cmdlet pobiera ścieżkę docelową, która jest następnie potokowana do Move-ItemProperty polecenia cmdlet. Polecenie Move-ItemProperty określa bieżącą ścieżkę i nazwę wpisu rejestru do przeniesienia.

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

Polecenie kończy się niepowodzeniem, a program PowerShell wyświetla następujący komunikat o błędzie:

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

Aby zbadać, użyj Trace-Command polecenia cmdlet , aby śledzić składnik powiązania parametrów programu PowerShell. Poniższy przykład śledzi powiązanie parametru podczas wykonywania potoku. Parametr PSHost wyświetla wyniki śledzenia w konsoli, a parametr FilePath wysyła wyniki śledzenia do pliku w celu późniejszego debug.txt odwołania.

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
}

Wyniki śledzenia są długie, ale pokazują wartości powiązane z Get-Item poleceniem cmdlet, a następnie nazwane wartości powiązane z Move-ItemProperty poleceniem cmdlet.

...
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`]
...

Na koniec pokazuje, że próba powiązania ścieżki z parametrem Move-ItemProperty Destination zakończyła się niepowodzeniem.

...
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
...

Get-Help Użyj polecenia cmdlet, aby wyświetlić atrybuty parametru Destination.

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

Wyniki pokazują, że miejsce docelowe przyjmuje dane wejściowe potoku tylko "według nazwy właściwości". W związku z tym obiekt potokowy musi mieć właściwość o nazwie Destination.

Użyj Get-Member polecenia , aby wyświetlić właściwości obiektu pochodzącego z Get-Itemobiektu .

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

Dane wyjściowe pokazują, że element jest obiektem Microsoft.Win32.RegistryKey , który nie ma właściwości Destination . Wyjaśnia to, dlaczego polecenie nie powiodło się.

Parametr Path akceptuje dane wejściowe potoku według nazwy lub wartości.

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

Aby naprawić polecenie, musimy określić miejsce docelowe w poleceniu Move-ItemProperty cmdlet i użyć Get-Item polecenia , aby uzyskać ścieżkę elementu, który chcemy przenieść.

Przykład:

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

Kontynuacja linii wewnętrznej

Jak już wspomniano, potok jest serią poleceń połączonych przez operatory potoku (|), zwykle napisanych w jednym wierszu. Jednak w celu zapewnienia czytelności program PowerShell umożliwia podzielenie potoku między wiele wierszy. Gdy operator potoku jest ostatnim tokenem w wierszu, analizator programu PowerShell łączy następny wiersz z bieżącym poleceniem, aby kontynuować konstruowanie potoku.

Na przykład następujący potok jednowierszowy:

Command-1 | Command-2 | Command-3

można napisać jako:

Command-1 |
    Command-2 |
    Command-3

Spacje wiodące w kolejnych wierszach nie są istotne. Wcięcie zwiększa czytelność.

Program PowerShell 7 dodaje obsługę kontynuacji potoków z znakiem potoku na początku wiersza. W poniższych przykładach pokazano, jak można użyć tej nowej funkcji.

# 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

Ważne

Podczas interaktywnej pracy w powłoce wklejanie kodu z potokami na początku wiersza tylko wtedy, gdy używasz klawiszy Ctrl+V do wklejania. Operacje wklejania prawym przyciskiem myszy wstawiają wiersze pojedynczo. Ponieważ wiersz nie kończy się znakiem potoku, program PowerShell uznaje dane wejściowe za ukończone i wykonuje ten wiersz zgodnie z wprowadzeniem.

Zobacz też