Udostępnij za pośrednictwem


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 drugiego polecenia. Te dane wyjściowe mogą być wysyłane do kolejnego 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 elementu Command-2. Command-2 przetwarza obiekty i wysyła je do programu Command-3. 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 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 do 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, ponieważ jest ono 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 nounu. 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żna przekazać dane wyjściowe Get-Item polecenia 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ędzia, takich jak Get-Member, Where-Object, Sort-Object, Group-Objecti Measure-Object , jest używanych niemal wyłącznie w potokach. Do tych poleceń cmdlet można przekazać potoki dowolnego typu 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-Table, Export-Clixml, Export-CSVi 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.

Dzięki odrobinie praktyki przekonasz się, że łączenie prostych poleceń w potoki pozwala zaoszczędzić czas i wpisywanie tekstu oraz 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, 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 parametru akceptuje dane wejściowe potoku Start-Service według wartości. Może on akceptować obiekty lub obiekty ciągów, 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 potokiem 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 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 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ć 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 w Format-Table 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. 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 dowolny typ, który implementuje IEnumerable interfejs lub jego ogólny odpowiednik. Wyliczone elementy są wysyłane przez potok pojedynczo. Program PowerShell wylicza również typy System.Data.DataTable za pomocą Rows właściwości .

Istnieje kilka wyjątków od automatycznego wyliczenia.

  • Należy wywołać metodę GetEnumerator() dla tabel skrótów, typów implementujących IDictionary interfejs lub jego ogólny odpowiednik oraz System.Xml. Typy 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 w przypadku potoku wielu obiektów procesu z Get-Process polecenia cmdlet do Get-Member polecenia cmdlet program PowerShell wysyła każdy obiekt procesu po jednym naraz do polecenia 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żesz go użyć. Na przykład wszystkie obiekty tablicowe mają właściwość Count . Umożliwia to zliczenie liczby procesów uruchomionych na komputerze.

Na 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 natywnego programu, który generuje nieprzetworzone dane bajtowe konwertuje dane wyjściowe na ciągi platformy .NET. Ta konwersja może spowodować uszkodzenie danych wyjściowych danych pierwotnych.

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

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 potokowa 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ć ten problem Trace-Command , użyj 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 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-ItemPropertyDestination 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 ( Miejsce docelowe).

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

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 Ścieżka 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ść.

Na 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 na 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ą 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 interaktywnej pracy w powłoce wklejanie kodu z potokami na początku wiersza tylko w przypadku wklejania za pomocą klawiszy Ctrl+V . 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ż