about_Pipelines
Krátký popis
Kombinování příkazů do kanálů v PowerShellu
Dlouhý popis
Kanál je řada příkazů připojených operátory kanálu () (|
ASCII 124). Každý operátor kanálu odešle výsledky předchozího příkazu do dalšího příkazu.
Výstup prvního příkazu lze odeslat ke zpracování jako vstup do druhého příkazu. A tento výstup lze odeslat do dalšího příkazu. Výsledkem je složitý řetězec příkazů nebo kanál složený z řady jednoduchých příkazů.
Příklad:
Command-1 | Command-2 | Command-3
V tomto příkladu jsou objekty, které Command-1
generuje, odeslány do Command-2
.
Command-2
zpracovává objekty a odesílá je do Command-3
. Command-3
zpracovává objekty a odesílá je do kanálu. Vzhledem k tomu, že kanál neobsahuje žádné další příkazy, zobrazí se v konzole výsledky.
V kanálu se příkazy zpracovávají v pořadí zleva doprava. Zpracování se zpracovává jako jedna operace a výstup se zobrazí při vygenerování.
Tady je jednoduchý příklad. Následující příkaz získá proces Poznámkového bloku a pak ho zastaví.
Příklad:
Get-Process notepad | Stop-Process
První příkaz pomocí rutiny Get-Process
získá objekt představující proces Poznámkového bloku. Používá operátor kanálu (|
) k odeslání objektu procesu do Stop-Process
rutiny, který zastaví proces Poznámkového bloku. Všimněte si, že Stop-Process
příkaz nemá parametr Name nebo ID k určení procesu, protože zadaný proces se odešle prostřednictvím kanálu.
Tento příklad kanálu získá textové soubory v aktuálním adresáři, vybere pouze soubory, které jsou delší než 10 000 bajtů, seřadí je podle délky a zobrazí název a délku každého souboru v tabulce.
Get-ChildItem -Path *.txt |
Where-Object {$_.length -gt 10000} |
Sort-Object -Property length |
Format-Table -Property name, length
Tento kanál se skládá ze čtyř příkazů v zadaném pořadí. Následující obrázek znázorňuje výstup z každého příkazu, který se předá dalšímu příkazu v kanálu.
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
Použití kanálů
Většina rutin PowerShellu je navržená tak, aby podporovala kanály. Ve většině případů můžete výsledky rutiny Get převést na jinou rutinu se stejným podstatným názvem.
Výstup rutiny můžete například přeskakovat Get-Service
do Start-Service
rutin nebo Stop-Service
rutin.
Tento ukázkový kanál spustí službu WMI v počítači:
Get-Service wmi | Start-Service
V jiném příkladu můžete do rutiny přeskakovat výstup poskytovatele Get-Item
registru PowerShellu nebo Get-ChildItem
v rámci tohoto New-ItemProperty
poskytovatele. Tento příklad přidá novou položku registru NoOfEmployees s hodnotou 8124 do klíče registru MyCompany.
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Mnoho rutin utility, například Get-Member
, Where-Object
, Group-Object
Sort-Object
a Measure-Object
jsou používány téměř výhradně v kanálech. Do těchto rutin můžete převést libovolný typ objektu. Tento příklad ukazuje, jak seřadit všechny procesy v počítači podle počtu otevřených popisovačů v každém procesu.
Get-Process | Sort-Object -Property handles
Objekty můžete pipetovat do rutin formátování, exportu a výstupu, například Format-List
, Format-Table
, Export-Clixml
, Export-CSV
a Out-File
.
Tento příklad ukazuje, jak pomocí rutiny Format-List
zobrazit seznam vlastností objektu procesu.
Get-Process winlogon | Format-List -Property *
Výstup nativních příkazů můžete také přeskakovat do rutin PowerShellu. Příklad:
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
Důležité
Datové proudy Success a Error jsou podobné streamům stdin a stderr jiných prostředí. Stdin se ale ke vstupnímu kanálu PowerShellu nepřipojí. Další informace najdete v tématu about_Redirection.
S trochou praxe zjistíte, že kombinování jednoduchých příkazů do kanálů šetří čas a psaní a zefektivňuje skriptování.
Jak fungují kanály
Tato část vysvětluje, jak jsou vstupní objekty svázány s parametry rutiny a zpracovány během provádění kanálu.
Přijímá vstup kanálu.
Aby bylo možné kanálování podporovat, musí mít přijímající rutina parametr, který přijímá vstup kanálu. Get-Help
Pomocí příkazu s možnostmi Full nebo Parameter určete, které parametry rutiny přijímají vstup kanálu.
Pokud chcete například určit, které parametry Start-Service
rutiny přijímá vstup kanálu, zadejte:
Get-Help Start-Service -Full
nebo
Get-Help Start-Service -Parameter *
Nápověda pro rutinu Start-Service
ukazuje, že vstup kanálu přijímají pouze parametry InputObject a Name .
-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
Když odesíláte objekty prostřednictvím kanálu, Start-Service
PowerShell se pokusí přidružit objekty k parametrům InputObject a Name .
Metody přijetí vstupu kanálu
Parametry rutin můžou přijímat vstup kanálu jedním ze dvou různých způsobů:
ByValue: Parametr přijímá hodnoty, které odpovídají očekávanému typu .NET nebo které lze převést na tento typ.
Například parametr Name přijímá
Start-Service
vstup kanálu podle hodnoty. Může přijímat objekty řetězců nebo objekty, které lze převést na řetězce.ByPropertyName: Parametr přijímá vstup pouze v případech, kdy vstupní objekt má vlastnost se stejným názvem jako parametr.
Například parametr
Start-Service
Name může přijímat objekty, které mají vlastnost Name . Chcete-li zobrazit seznam vlastností objektu, nasunout ho naGet-Member
.
Některé parametry mohou přijímat objekty podle hodnoty nebo názvu vlastnosti, což usnadňuje příjem vstupu z kanálu.
Vazba parametru
Když objekty předáte z jednoho příkazu do jiného příkazu, PowerShell se pokusí přidružit objekty s kanálem k parametru přijímající rutiny.
Komponenta vazby parametrů PowerShellu přidruží vstupní objekty k parametrům rutiny podle následujících kritérií:
- Parametr musí přijímat vstupy z kanálu.
- Parametr musí přijmout typ odesílaného objektu nebo typ, který lze převést na očekávaný typ.
- Parametr nebyl použit v příkazu.
Například rutina Start-Service
má mnoho parametrů, ale pouze dva z nich, Name a InputObject přijímají vstup kanálu. Parametr Name přebírá řetězce a parametr InputObject přebírá objekty služby. Proto můžete řetězce, objekty služby a objekty s vlastnostmi, které lze převést na objekty řetězce nebo služby.
PowerShell spravuje vazbu parametrů co nejefektivněji. PowerShell nemůže navrhnout nebo vynutit vytvoření vazby ke konkrétnímu parametru. Příkaz selže, pokud PowerShell nemůže svázat objekty s kanály.
Další informace o řešení chyb vazby najdete v části Zkoumání chyb kanálu dále v tomto článku.
Jednorázové zpracování
Piping objects to a command is like using a parameter of the command to submit the objects. Podívejme se na příklad kanálu. V tomto příkladu používáme kanál k zobrazení tabulky objektů služby.
Get-Service | Format-Table -Property Name, DependentServices
Funkčně se to podobá použití parametru Format-Table
InputObject pro odeslání kolekce objektů.
Kolekci služeb můžeme například uložit do proměnné, která se předává pomocí parametru InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
Nebo můžeme příkaz vložit do parametru InputObject .
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Je ale důležitý rozdíl. Když předáte více objektů do příkazu, PowerShell odešle objekty do příkazu po jednom. Při použití parametru příkazu se objekty odesílají jako jeden maticový objekt. Tento malý rozdíl má významné důsledky.
Při spouštění kanálu PowerShell automaticky vytvoří výčet libovolného typu, který implementuje IEnumerable
rozhraní nebo jeho obecný protějšek. Výčtové položky se posílají kanálem po jednom. PowerShell také vyčísluje Rows
typy System.Data.DataTable prostřednictvím vlastnosti.
Existuje několik výjimek automatického výčtu.
- Je nutné volat metodu
GetEnumerator()
pro hash tabulky, typy, které implementujíIDictionary
rozhraní nebo jeho obecný protějšek, a System.Xml.XmlNode typy. - System.String třída implementuje
IEnumerable
, ale PowerShell nevyčísluje objekty řetězce.
V následujících příkladech se pole a hashtable předávají rutině Measure-Object
, aby se spočítal počet objektů přijatých z kanálu. Pole má více členů a hashovatelná tabulka má několik párů klíč-hodnota. Pouze pole se vyčíslí po jednom.
@(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 :
Podobně pokud předáte více procesních objektů z Get-Process
rutiny do Get-Member
rutiny, PowerShell odešle každý objekt procesu jeden po druhém do Get-Member
. Get-Member
zobrazí třídu .NET (typ) objektů procesu a jejich vlastnosti a metody.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Poznámka:
Get-Member
eliminuje duplicity, takže pokud jsou všechny objekty stejného typu, zobrazí pouze jeden typ objektu.
Pokud však použijete inputObject parametr Get-Member
, pak Get-Member
obdrží pole System.Diagnostics.Process objekty jako jednu jednotku. Zobrazí vlastnosti pole objektů. (Poznamenejte si symbol pole ([]
) za názvem typu System.Object .)
Příklad:
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()
...
Tento výsledek nemusí být tím, co jste chtěli. Ale až to pochopíte, můžete ho použít. Například všechny objekty pole mají vlastnost Count . Můžete ho použít ke spočítání počtu procesů spuštěných v počítači.
Příklad:
(Get-Process).count
Je důležité si uvědomit, že objekty odeslané kanálem se doručují po jednom.
Použití nativních příkazů v kanálu
PowerShell umožňuje zahrnout do kanálu nativní externí příkazy. Je ale důležité si uvědomit, že kanál PowerShellu je objektově orientovaný a nepodporuje nezpracovaná bajtová data.
Piping or redirecting output from a native program that outputs raw byte data converts the outputs to .NET strings. Tento převod může způsobit poškození nezpracovaného výstupu dat.
PowerShell 7.4 ale přidal PSNativeCommandPreserveBytePipe
experimentální funkci, která při přesměrování streamu stdout nativního příkazu na soubor nebo při propojení dat bajtového streamu do datového proudu stdin nativního příkazu zachovala data bajtů.
Například pomocí nativního příkazu curl
můžete stáhnout binární soubor a uložit ho na disk pomocí přesměrování.
$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
Data bajtového streamu můžete také směrovat do datového proudu stdin jiného nativního příkazu. Následující příklad stáhne soubor ZIP TAR pomocí curl
. Stažená data souboru se streamují do tar
příkazu, který extrahuje obsah archivu.
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
Výstup bajtového streamu příkazu PowerShellu můžete také přeskakovat na vstup nativního příkazu. Následující příklady používají Invoke-WebRequest
ke stažení stejného souboru TAR jako v předchozím příkladu.
# 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 .
Tato funkce nepodporuje data bajtů-stream při přesměrování výstupu stderr na stdout. Při kombinování datových proudů stderr a stdout se kombinované datové proudy považují za řetězcová data.
Zkoumání chyb kanálu
Pokud PowerShell nemůže přidružit objekty s kanálem k parametru přijímající rutiny, příkaz selže.
V následujícím příkladu se pokusíme přesunout položku registru z jednoho klíče registru do jiného. Rutina Get-Item
získá cílovou cestu, která se pak předá rutině Move-ItemProperty
. Příkaz Move-ItemProperty
určuje aktuální cestu a název položky registru, která se má přesunout.
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
Příkaz selže a PowerShell zobrazí následující chybovou zprávu:
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
K prošetření použijte Trace-Command
rutinu ke sledování komponenty vazby parametrů PowerShellu. Následující příklad trasuje vazbu parametrů během provádění kanálu. Parametr PSHost zobrazí výsledky trasování v konzole a parametr FilePath odešle výsledky trasování do debug.txt
souboru pro pozdější referenci.
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
}
Výsledky trasování jsou zdlouhavé, ale zobrazují hodnoty vázané na rutinu Get-Item
a pak pojmenované hodnoty vázané na rutinu Move-ItemProperty
.
...
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`]
...
Nakonec ukazuje, že pokus o vytvoření vazby cesty k parametru Destination selhal Move-ItemProperty
.
...
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
Pomocí rutiny můžete zobrazit atributy 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
Výsledky ukazují, že cíl přijímá vstup kanálu pouze "podle názvu vlastnosti". Proto musí mít piped objekt vlastnost s názvem Cíl.
Umožňuje Get-Member
zobrazit vlastnosti objektu pocházejícího z Get-Item
.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
Výstup ukazuje, že položka je objekt Microsoft.Win32.RegistryKey , který nemá cílovou vlastnost. To vysvětluje, proč příkaz selhal.
Parametr Path přijímá vstup kanálu podle názvu nebo hodnoty.
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
Pokud chcete příkaz opravit, musíme v rutině Move-ItemProperty
zadat cíl a použít Get-Item
k získání cesty k položce, kterou chceme přesunout.
Příklad:
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Pokračování vnitřní čáry
Jak už bylo popsáno, kanál je řada příkazů propojených operátory kanálu (|
), obvykle napsané na jednom řádku. Kvůli čitelnosti ale PowerShell umožňuje rozdělit kanál mezi více řádků. Pokud je operátor kanálu posledním tokenem na řádku, analyzátor PowerShell připojí další řádek k aktuálnímu příkazu, aby pokračoval ve vytváření kanálu.
Například následující jednořádkový kanál:
Command-1 | Command-2 | Command-3
lze napsat takto:
Command-1 |
Command-2 |
Command-3
Úvodní mezery na následujících řádcích nejsou významné. Odsazení zlepšuje čitelnost.
PowerShell 7 přidává podporu pro pokračování kanálů s znakem kanálu na začátku řádku. Následující příklady ukazují, jak můžete tuto novou funkci použít.
# 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
Důležité
Při interaktivní práci v prostředí vložíte kód s kanály na začátku řádku, pouze když k vložení použijete ctrl+V. Operace vložení po kliknutí pravým tlačítkem myši vloží řádky po jednom. Vzhledem k tomu, že řádek nekončí znakem kanálu, PowerShell považuje vstup za dokončený a spustí tento řádek podle zadání.