about_Pipelines

Krótki opis

Łączenie poleceń w potoki 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 mogą być wysyłane do przetwarzania jako dane wejściowe drugiego polecenia. Te dane wyjściowe można wysłać do jeszcze innego polecenia. Wynikiem jest złożony łańcuch poleceń lub potok, który składa się z serii prostych poleceń.

Na przykład

Command-1 | Command-2 | Command-3

W tym przykładzie emitowane obiekty Command-1 są wysyłane do obiektu Command-2 . Command-2 Przetwarza obiekty i wysyła je do Command-3 . Command-3 przetwarza obiekty i wysyła je do potoku. Ponieważ potok nie ma już żadnych 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 ich generowania.

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

Na przykład

Get-Process notepad | Stop-Process

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

Ten przykładowy potok pobiera pliki tekstowe w bieżącym katalogu, wybiera tylko pliki o długości większej niż 10 000 bajtów, sortuje je według długości oraz 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. Na poniższej ilustracji przedstawiono dane wyjściowe z każdego polecenia 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 potokować wyniki get polecenia cmdlet do innego polecenia cmdlet tego samego rzeczownika. Można na przykład potokować dane wyjściowe Get-Service polecenia cmdlet do polecenia Start-Service Stop-Service cmdlet lub .

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

Get-Service wmi | Start-Service

Innym przykładem jest możliwość potoku danych wyjściowych polecenia lub w obrębie dostawcy Get-Item rejestru programu Get-ChildItem PowerShell do polecenia New-ItemProperty 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 z narzędzi cmdlet, takich jak , , , i , jest używanych Get-Member Where-Object prawie wyłącznie w Sort-Object Group-Object Measure-Object potokach. Do tych cmdlet można potokować 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 potokować do cmdlet formatowania, eksportu i danych wyjściowych, takich jak Format-List , , , i Format-Table Export-Clixml Export-CSV Out-File .

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

Get-Process winlogon | Format-List -Property *

Dane wyjściowe poleceń natywnych można również potokować 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 Sukces i Błąd są podobne do strumieni stdin i stderr innych powłok. Jednak stdin nie jest połączony z potokiem programu PowerShell w celu wprowadzania danych. Aby uzyskać więcej informacji, zobacz about_Redirection.

W praktyce połączenie prostych poleceń w potoki oszczędza czas i pozwala na wpisywanie oraz sprawia, że wykonywanie skryptów jest bardziej wydajne.

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 akceptujący dane wejściowe potoku. Użyj polecenia Get-Help z opcjami Pełne lub Parametr, aby określić, które parametry polecenia cmdlet akceptują dane wejściowe potoku.

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

Get-Help Start-Service -Full

lub

Get-Help Start-Service -Parameter *

Pomoc dla polecenia Start-Service 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 programu program PowerShell próbuje skojarzyć obiekty z parametrami Start-Service InputObject i Name.

Metody akceptowania danych wejściowych potoku

Parametry polecenia 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 .NET lub które można przekonwertować na ten typ.

    Na przykład parametr Name parametru Start-Service akceptuje dane wejściowe potoku według wartości. Może 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 takiej samej nazwie jak parametr.

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

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

Powiązanie parametru

W przypadku potoku obiektów z jednego polecenia do innego program PowerShell próbuje skojarzyć obiekty potokowe z parametrem odbierających poleceń 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 akceptować typ wysyłanego obiektu lub typ, który można przekonwertować na oczekiwany typ.
  • Parametr nie został użyty w poleceniu .

Na przykład polecenie cmdlet ma wiele parametrów, ale tylko dwa z Start-Service 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 obiekty ciągu lub usługi.

Program PowerShell zarządza powiązaniem parametrów tak efektywnie, 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ć obiektów potokowych.

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 jeden na raz

Przesyłanie pipingu obiektów do polecenia przypomina użycie parametru polecenia w celu przesyłania obiektów. Przyjrzyjmy się przykładowi potoku. W tym przykładzie używamy potoku do wyświetlenia tabeli obiektów usługi.

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

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

Na przykład możemy zapisać kolekcję usług do zmiennej, która jest przekazywana przy użyciu parametru InputObject.

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

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

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

Istnieje jednak ważna różnica. W przypadku potoku wielu obiektów do polecenia program PowerShell wysyła obiekty do polecenia po jednym na raz. W przypadku użycia 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 każdy typ, który implementuje interfejs i wysyła elementy członkowskie za pośrednictwem potoku IEnumerable po jednym na raz. Wyjątek to [hashtable] , który wymaga wywołania metody GetEnumerator() .

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

@(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 w przypadku potoku wielu obiektów procesu z polecenia cmdlet do polecenia Get-Process cmdlet program PowerShell wysyła każdy obiekt procesu, po jednym Get-Member na raz, 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żyjemy parametru InputObject obiektu , program odbierze tablicę obiektów Get-Member Get-Member System.Diagnostics.Process jako pojedynczą jednostkę. Wyświetla właściwości tablicy obiektów. (Zanotuj symbol tablicy ( [] ) po nazwie typu System.Object.

Na 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ć zgodnie z zamierzony. Jednak po zrozumieniu tego można go użyć. Na przykład wszystkie obiekty tablicy mają właściwość Count. Za jego pomocą można zliczyć liczbę procesów uruchomionych na komputerze.

Na przykład

(Get-Process).count

Należy pamiętać, że obiekty wysyłane do potoku są dostarczane po jednym na raz.

Badanie błędów potoku

Gdy program PowerShell nie może skojarzyć obiektów potokowych z parametrem odbierających poleceń 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, który ma zostać przeniesiony.

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

Polecenie kończy się niepowodzeniem i 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ć ten temat, użyj Trace-Command polecenia cmdlet do śledzenia składnika 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 debug.txt celu późniejszego 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 poleceniem cmdlet, a następnie nazwane wartości powiązane z Get-Item 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 Destination Move-ItemProperty parametru nie powiodła się.

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

Użyj Get-Help 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 obiekt docelowy 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 , aby wyświetlić właściwości obiektu pochodzące z . Get-Item

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. To wyjaśnia, 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ć to polecenie, musimy określić miejsce docelowe w poleceniu cmdlet i użyć polecenia , aby pobrać ścieżkę Move-ItemProperty Get-Item elementu, który chcemy przenieść.

Na przykład

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

Wewnętrzna kontynuacja linii

Jak już mówiono, potok to seria poleceń połączonych za pomocą operatorów potoku ( | ), zwykle zapisywanych w jednym wierszu. Jednak w celu czytelności program PowerShell umożliwia dzielenie potoku na wiele wierszy. Gdy operator potoku jest ostatnim tokenem w wierszu, parser programu PowerShell łączy następny wiersz z bieżącym poleceniem, aby kontynuować konstrukcję potoku.

Na przykład następujący potok jedno wierszowy:

Command-1 | Command-2 | Command-3

Można je zapisywać w następujący sposób:

Command-1 |
  Command-2 |
    Command-3

Wiodące spacje w kolejnych wierszach nie są znaczące. Wcięcie zwiększa czytelność.

W programie PowerShell 7 dodano obsługę kontynuacji potoków ze znakiem potoku na początku wiersza. Poniższe przykłady pokazują, 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 pracy interakcyjnej w powłokie wklejanie kodu z potokami na początku wiersza tylko w przypadku wklejania za pomocą klawisza Ctrl + V. Kliknięcie prawym przyciskiem myszy operacji wklejania powoduje wstawienie wierszy po jednym na raz. Ponieważ wiersz nie kończy się znakiem potoku, program PowerShell uznaje dane wejściowe za kompletne i wykonuje ten wiersz zgodnie z wprowadzonymi.

Zobacz też

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach