Informace o kanálech
Stručný popis
Kombinování příkazů do kanálů v PowerShellu
Dlouhý popis
Kanál je řada příkazů propojený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 je možné odeslat do dalšího příkazu. Výsledkem je složitý řetězec příkazů nebo kanál , který se skládá z řady jednoduchých příkazů.
Třeba
Command-1 | Command-2 | Command-3
V tomto příkladu se objekty, které Command-1
vygenerují, odešlou 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. Protože kanál neobsahuje žádné další příkazy, zobrazí se výsledky v konzole nástroje .
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 zobrazuje při generování.
Tady je jednoduchý příklad. Následující příkaz získá proces Poznámkového bloku a pak ho zastaví.
Třeba
Get-Process notepad | Stop-Process
První příkaz použije rutinu Get-Process
k získání objektu představujícího proces Poznámkového bloku. K odeslání objektu procesu do Stop-Process
rutiny používá operátor kanálu (|
), který zastaví proces Poznámkového bloku. Všimněte si, že Stop-Process
příkaz nemá parametr Name nebo ID pro určení procesu, protože zadaný proces se odesílá prostřednictvím kanálu.
Tento příklad kanálu načte 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 každého příkazu, který se předává 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 Getpředvést do jiné rutiny se stejným podstatným názvem.
Výstup rutiny můžete například předvést Get-Service
do Start-Service
rutin nebo Stop-Service
.
Tento ukázkový kanál spustí službu WMI na počítači:
Get-Service wmi | Start-Service
V dalším příkladu můžete výstup zprostředkovatele registru PowerShellu Get-Item
nebo Get-ChildItem
v rámci tohoto zprostředkovatele předvést do rutiny New-ItemProperty
. 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
Mnohé rutiny nástrojů, jako Get-Member
jsou , , Where-Object
Sort-Object
, Group-Object
aMeasure-Object
, se používají téměř výhradně v kanálech. K těmto rutinám můžete připojit 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 předat do rutin formátování, exportu a výstupu, jako Format-List
jsou , 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 *
S trochou praxe zjistíte, že kombinování jednoduchých příkazů do kanálů šetří čas a zadávání a zefektivňuje skriptování.
Jak kanály fungují
Tato část vysvětluje, jak jsou vstupní objekty vázány na parametry rutiny a zpracovávány během provádění kanálu.
Přijímá vstup kanálu.
Pro podporu pipeliningu musí mít přijímající rutina parametr, který přijímá vstup kanálu. Get-Help
Pomocí příkazu s možnostmi Úplný nebo Parametr určete, které parametry rutiny přijímají vstup kanálu.
Pokud například chcete zjistit, které parametry rutiny Start-Service
přijímají 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 do 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é je možné na tento typ převést.
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 má vstupní objekt vlastnost se stejným názvem jako parametr.
Parametr Name
Start-Service
může například přijímat objekty, které mají vlastnost Name . Pokud chcete vypsat vlastnosti objektu, předáte ho doGet-Member
.
Některé parametry můžou přijímat objekty podle hodnoty nebo názvu vlastnosti, což usnadňuje přijímání vstupu z kanálu.
Vazby parametrů
Při předávání objektů z jednoho příkazu do jiného se PowerShell 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 vstup 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 se v příkazu nepoužil.
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ězit řetězce, objekty služby a objekty s vlastnostmi, které lze převést na objekty řetězce nebo služby.
PowerShell spravuje vazby parametrů co nejefektivněji. PowerShell nemůžete navrhnout ani vynutit vytvoření vazby na konkrétní parametr. Pokud PowerShell nemůže svázat objekty s kanálem, příkaz selže.
Další informace o řešení chyb vazeb najdete v části Zkoumání chyb kanálu dále v tomto článku.
Jednorázové zpracování
Propojení objektů do příkazu se podobá použití parametru příkazu k odeslání objektů. 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ě je to jako použití parametru InputObject k Format-Table
odeslání kolekce objektů.
Například můžeme uložit kolekci služeb do proměnné, která se předává pomocí parametru InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
Nebo můžeme vložit příkaz do parametru InputObject .
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Je tu ale důležitý rozdíl. Když do příkazu předáte více objektů, PowerShell odesílá objekty do příkazu jeden po druhém. Při použití parametru příkazu se objekty odesílají jako jeden objekt pole. Tento malý rozdíl má významné důsledky.
Při spouštění kanálu PowerShell automaticky vypisuje jakýkoli typ, který implementuje IEnumerable
rozhraní, a po jednom odesílá členy kanálem. Výjimkou je [hashtable]
, který vyžaduje volání GetEnumerator()
metody .
V následujících příkladech se pole a zatřiďovací tabulka předávají do Measure-Object
rutiny, aby se spočítal počet objektů přijatých z kanálu. Pole má více členů a zatřiďovací tabulka má několik párů klíč-hodnota. Pouze pole je výčtu 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ě platí, že pokud z Get-Process
rutiny do Get-Member
rutiny předáte více objektů procesu, PowerShell odesílá jednotlivé objekty procesu postupně do Get-Member
. Get-Member
zobrazí třídu .NET (typ) procesních objektů 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í se pouze jeden typ objektu.
Pokud však použijete parametr InputObject objektu Get-Member
, Get-Member
obdrží pole objektů System.Diagnostics.Process jako jednu jednotku. Zobrazuje vlastnosti pole objektů. (Poznamenejte si symbol pole ([]
) za názvem typu System.Object .)
Třeba
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 takový, jaký jste zamýšleli. Ale až tomu porozumíte, můžete ho použít. Například všechny objekty pole mají vlastnost Count . Můžete ho použít k určení počtu procesů spuštěných v počítači.
Třeba
(Get-Process).count
Je důležité si uvědomit, že objekty odeslané kanálem se doručují po jednom.
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á do rutiny 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 prozkoumání použijte rutinu Trace-Command
ke trasová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, které jsou vázány 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 s parametrem 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
...
Pomocí rutiny Get-Help
zobrazte 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 objekt s kanálem vlastnost s názvem Destination.
Slouží Get-Member
k zobrazení vlastností 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á vlastnost Destination . 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
Abychom tento příkaz opravili, musíme zadat cíl v rutině Move-ItemProperty
a použít Get-Item
k získání cesty k položce, kterou chceme přesunout.
Třeba
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Vnitřní pokračování řádku
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 na několik řádků.
Pokud je operátor potrubí posledním tokenem na řádku, parser PowerShellu připojí další řádek k aktuálnímu příkazu, aby pokračoval v sestavování kanálu.
Například následující jednořádkový kanál:
Command-1 | Command-2 | Command-3
lze napsat jako:
Command-1 |
Command-2 |
Command-3
Úvodní mezery na následujících řádcích nejsou významné. Odsazení zlepšuje čitelnost.