Udostępnij za pośrednictwem


about_Pipelines

Krótki opis

Łączenie poleceń z potokami 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 drugiego polecenia. Te dane wyjściowe można wysyłać do jeszcze innego polecenia. Wynikiem jest złożony łańcuch poleceń lub potok składający się z serii prostych poleceń.

Na 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-3obiektu . 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 generowania.

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

Na przykład

Get-Process notepad | Stop-Process

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

Ten przykład potoku pobiera pliki tekstowe w bieżącym katalogu, wybiera tylko pliki, które są dłuższe niż 10 000 bajtów, 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, ponieważ 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 wyniki polecenia cmdlet Get można przekazać 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

W innym przykładzie możesz przekazać dane wyjściowe Get-Item lub Get-ChildItem w ramach dostawcy rejestru programu PowerShell do New-ItemProperty polecenia cmdlet. W tym przykładzie dodano nowy wpis rejestru NoOfEmployees z wartością 8124 do klucza rejestru MyCompany .

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

Wiele poleceń cmdlet narzędzi, takich jak Get-Member, Where-Object, Sort-Object, Group-Objecti Measure-Object są używane niemal wyłącznie w potokach. Do tych poleceń 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 przesyłać potokami do poleceń cmdlet formatowania, eksportowania i danych wyjściowych, takich jak Format-List, , Format-TableExport-Clixml, , Export-CSVi 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 *

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.

Dzięki odrobinie praktyki dowiesz się, że łączenie prostych poleceń w potoki pozwala zaoszczędzić czas i wpisywanie i zwiększa wydajność 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, polecenie cmdlet odbierające 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 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 Start-ServiceName akceptuje dane wejściowe potoku 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, przejmij 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ć obiekty potokowe 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 zasugerować ani wymusić 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.

Jednorazowe przetwarzanie

Potokowanie obiektów do polecenia jest podobne do użycia parametru polecenia do przesył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 w Format-Table celu przesłania kolekcji obiektów.

Możemy na przykład zapisać kolekcję usług w 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. 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 i wysyła elementy członkowskie za pośrednictwem potoku pojedynczo. Wyjątek to [hashtable], który wymaga wywołania GetEnumerator() metody .

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

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ć zamierzony. Ale po jego zrozumieniu można go użyć. Na przykład wszystkie obiekty tablicowe mają właściwość Count . Można go użyć do zliczenia liczby procesów uruchomionych na komputerze.

Na przykład

(Get-Process).count

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

Używanie poleceń natywnych w potoku

Program PowerShell umożliwia dołączanie natywnych poleceń zewnętrznych w 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.

Aby obejść ten problem, wywołaj polecenia natywne przy użyciu cmd.exe /c lub sh -c i użyj | operatorów i > dostarczonych przez powłokę natywną.

Badanie błędów potoku

Gdy 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 parametrów 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 Get-Item z 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 pokazano, że próba powiązania ścieżki z parametrem Move-ItemPropertyDestination 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 polecenia cmdlet, Get-Help 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(Miejsce docelowe).

Użyj polecenia Get-Member , 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 rozwiązać ten problem, musimy określić miejsce docelowe w Move-ItemProperty poleceniu cmdlet i użyć polecenia Get-Item , aby uzyskać ścieżkę elementu, który chcemy przenieść.

Na przykład

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

Kontynuacja wiersza wewnętrznego

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 na wiele wierszy. Gdy operator potoku jest ostatnim tokenem w wierszu, analizator programu PowerShell łączy następny wiersz z bieżącym poleceniem w celu kontynuowania budowy 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ą znaczące. 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 pracy interakcyjnej w powłoce wklejanie kodu z potokami na początku wiersza tylko wtedy, gdy użyj klawiszy Ctrl+V do wklejenia. 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 wprowadzonym znakiem.

Zobacz też