about_Parsing
Krátký popis
Popisuje, jak PowerShell analyzuje příkazy.
Dlouhý popis
Když zadáte příkaz na příkazovém řádku, PowerShell rozdělí text příkazu do řady segmentů, které se nazývají tokeny, a pak určí, jak interpretovat jednotlivé tokeny .
Pokud například zadáte:
Write-Host book
PowerShell rozdělí příkaz na dva tokeny a book
interpretuje každý token nezávisle pomocí jednoho ze dvou hlavních režimů analýzy: režim výrazu Write-Host
a režim argumentu.
Poznámka:
Když PowerShell analyzuje vstup příkazu, pokusí se přeložit názvy příkazů na rutiny nebo nativní spustitelné soubory. Pokud název příkazu nemá přesnou shodu, PowerShell se k příkazu předpovědí Get-
jako výchozí příkaz. PowerShell například parsuje Service
jako Get-Service
. Tuto funkci nedoporučujeme používat z následujících důvodů:
- Je neefektivní. To způsobí, že PowerShell bude prohledávat vícekrát.
- Externí programy se stejným názvem se nejprve přeloží, takže zamýšlenou rutinu nemusíte spustit.
Get-Help
aGet-Command
nerozpoznávejte názvy bez sloves.- Název příkazu může být vyhrazené slovo nebo klíčové slovo jazyka.
Process
je obojí a nelze je vyřešit naGet-Process
.
Režim výrazu
Režim výrazů je určený ke kombinování výrazů, které jsou vyžadovány pro manipulaci s hodnotami ve skriptovacím jazyce. Výrazy představují reprezentaci hodnot v syntaxi PowerShellu a můžou být jednoduché nebo složené, například:
Literální výrazy představují přímé vyjádření jejich hodnot:
'hello'
32
Výrazy proměnných mají hodnotu proměnné, na kterou odkazují:
$x
$script:path
Operátory kombinují další výrazy pro vyhodnocení:
-12
-not $Quiet
3 + 7
$input.Length -gt 1
- Řetězcové literály znaků musí být obsaženy v uvozovkách.
- Čísla se považují za číselné hodnoty, nikoli jako řadu znaků (pokud nejsou uchycené).
- Operátory, včetně unárních operátorů, jako
-
jsou a-not
binární operátory+
jako a-gt
, jsou interpretovány jako operátory a aplikují jejich příslušné operace na argumenty (operandy). - Výrazy atributů a převodu se analyzují jako výrazy a použijí se u podřízených výrazů. Například:
[int] '7'
. - Odkazy na proměnné se vyhodnocují na jejich hodnoty, ale splatting je zakázáno a způsobí chybu analyzátoru.
- Cokoli jiného se považuje za příkaz, který se má vyvolat.
Režim argumentu
Při analýze powershell nejprve interpretuje vstup jako výraz. Při vyvolání příkazu ale probíhá analýza v režimu argumentu. Pokud máte argumenty, které obsahují mezery, například cesty, musíte tyto hodnoty argumentů uzavřít do uvozovek.
Režim argumentů je určený pro analýzu argumentů a parametrů pro příkazy v prostředí prostředí. Veškerý vstup se považuje za rozbalitelný řetězec, pokud nepoužívá jednu z následujících syntaxí:
Znak dolaru (
$
) následovaný názvem proměnné začíná odkaz na proměnnou, jinak se interpretuje jako součást rozbalitelného řetězce. Odkaz na proměnnou může zahrnovat přístup ke členům nebo indexování.- Další znaky, které následují po jednoduchých odkazech na proměnné, jako
$HOME
například , jsou považovány za součást stejného argumentu. Uzavřete název proměnné do složených závorek () a{}
oddělte ho od dalších znaků. Například${HOME}
. - Pokud odkaz na proměnnou obsahuje přístup člena, první z dalších znaků se považuje za začátek nového argumentu. Výsledkem jsou například
$HOME.Length-more
dva argumenty: hodnota řetězcového$HOME.Length
literálu-more
.
- Další znaky, které následují po jednoduchých odkazech na proměnné, jako
Uvozovky (
'
a"
) počáteční řetězceSložené závorky (
{}
) začínají novým blokem skriptu.Čárky (
,
) představují seznamy předané jako pole, pokud není volaný příkaz nativní aplikací, v takovém případě jsou interpretovány jako součást rozbalitelného řetězce. Počáteční, po sobě jdoucí nebo koncové čárky se nepodporují.Závorky (
()
) začínají novým výrazemOperátor dílčího výrazu (
$()
) začíná vložený výraz.Počáteční znak (
@
) začíná syntaxe výrazů, jako jsou splatting (@args
), matice (@(1,2,3)
) a literály hashovací tabulky (@{a=1;b=2}
).()
@()
a$()
na začátku tokenu vytvořte nový kontext analýzy, který může obsahovat výrazy nebo vnořené příkazy.- Když následuje další znaky, první další znak se považuje za začátek nového samostatného argumentu.
- Když předchází necitovaný literál
$()
, funguje jako rozbalitelný řetězec,()
spustí nový argument, který je výrazem, a@()
použije se jako literál@
při()
spuštění nového argumentu, který je výrazem.
Všechno ostatní je považováno za rozbalitelný řetězec, s výjimkou metacharacterů, které stále potřebují utéct. Viz Zpracování speciálních znaků.
- Metacharaktery v režimu argumentu (znaky se speciálním syntaktickým významem) jsou:
<space> ' " ` , ; ( ) { } | & < > @ #
. Z nich< > @ #
jsou pouze speciální na začátku tokenu.
- Metacharaktery v režimu argumentu (znaky se speciálním syntaktickým významem) jsou:
Token zastavení parsování (
--%
) změní interpretaci všech zbývajících argumentů. Další informace najdete v části zastavení analýzy tokenu níže.
Příklady
Následující tabulka obsahuje několik příkladů tokenů zpracovaných v režimu výrazů a v režimu argumentů a vyhodnocení těchto tokenů. V těchto příkladech je 4
hodnota proměnné $a
.
Příklad | Režim | Výsledek |
---|---|---|
2 |
Výraz | 2 (celé číslo) |
`2 |
Výraz | "2" (příkaz) |
Write-Output 2 |
Výraz | 2 (celé číslo) |
2+2 |
Výraz | 4 (celé číslo) |
Write-Output 2+2 |
Argument | "2+2" (řetězec) |
Write-Output(2+2) |
Výraz | 4 (celé číslo) |
$a |
Výraz | 4 (celé číslo) |
Write-Output $a |
Výraz | 4 (celé číslo) |
$a+2 |
Výraz | 6 (celé číslo) |
Write-Output $a+2 |
Argument | "4+2" (řetězec) |
$- |
Argument | "$-" (příkaz) |
Write-Output $- |
Argument | "$-" (řetězec) |
a$a |
Výraz | "a$a" (příkaz) |
Write-Output a$a |
Argument | "a4" (řetězec) |
a'$a' |
Výraz | "a$a" (příkaz) |
Write-Output a'$a' |
Argument | "a$a" (řetězec) |
a"$a" |
Výraz | "a$a" (příkaz) |
Write-Output a"$a" |
Argument | "a4" (řetězec) |
a$(2) |
Výraz | "a$(2)" (příkaz) |
Write-Output a$(2) |
Argument | "a2" (řetězec) |
Každý token lze interpretovat jako určitý druh typu objektu, například logická hodnota nebo řetězec. PowerShell se pokusí určit typ objektu z výrazu. Typ objektu závisí na typu parametru, který příkaz očekává, a na tom, jestli PowerShell ví, jak převést argument na správný typ. Následující tabulka uvádí několik příkladů typů přiřazených hodnotám vráceným výrazy.
Příklad | Režim | Výsledek |
---|---|---|
Write-Output !1 |
argument | "!1" (řetězec) |
Write-Output (!1) |
výraz | False (logická hodnota) |
Write-Output (2) |
výraz | 2 (celé číslo) |
Set-Variable AB A,B |
argument | "A", "B" (pole) |
CMD /CECHO A,B |
argument | "A,B" (řetězec) |
CMD /CECHO $AB |
výraz | A B (matice) |
CMD /CECHO :$AB |
argument | ':A B' (řetězec) |
Zpracování speciálních znaků
Zpětný znak (`
) lze použít k řídicímu znaku libovolného speciálního znaku ve výrazu. To je nejužitečnější pro odstranění metacharakterů v režimu argumentů, které chcete použít jako literální znaky, nikoli jako metacharakter. Pokud chcete například použít znak dolaru ($
) jako literál v rozbalitelném řetězci:
"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.
Pokračování řádku
Znak backtick lze také použít na konci řádku, abyste mohli pokračovat ve vstupu na dalším řádku. To zlepšuje čitelnost příkazu, který trvá několik parametrů s dlouhými názvy a hodnotami argumentů. Příklad:
New-AzVm `
-ResourceGroupName "myResourceGroupVM" `
-Name "myVM" `
-Location "EastUS" `
-VirtualNetworkName "myVnet" `
-SubnetName "mySubnet" `
-SecurityGroupName "myNetworkSecurityGroup" `
-PublicIpAddressName "myPublicIpAddress" `
-Credential $cred
Měli byste se však vyhnout použití pokračování řádku.
- Zpětné znaky mohou být obtížně vidět a snadno zapomenout.
- Nadbytečné mezery po zpětném návazci přeruší pokračování řádku. Vzhledem k tomu, že je místo obtížně vidět, může být obtížné najít chybu.
PowerShell nabízí několik způsobů, jak zalomit čáry v přirozeném bodě syntaxe.
- Za znaky svislé znaky (
|
) - Za binárními operátory (
+
,-
,-eq
atd.) - Za čárkou (
,
) v poli - Po otevření znaků, například
[
,{
(
Pro velkou sadu parametrů použijte místo toho splatting. Příklad:
$parameters = @{
ResourceGroupName = "myResourceGroupVM"
Name = "myVM"
Location = "EastUS"
VirtualNetworkName = "myVnet"
SubnetName = "mySubnet"
SecurityGroupName = "myNetworkSecurityGroup"
PublicIpAddressName = "myPublicIpAddress"
Credential = $cred
}
New-AzVm @parameters
Předávání argumentů nativním příkazům
Při spouštění nativních příkazů z PowerShellu se argumenty nejprve parsují pomocí PowerShellu. Analyzované argumenty se pak spojí do jednoho řetězce s každým parametrem odděleným mezerou.
Například následující příkaz volá icacls.exe
program.
icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
Pokud chcete tento příkaz spustit v PowerShellu 2.0, musíte použít řídicí znaky, abyste zabránili chybné interpretaci závorek v PowerShellu.
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
Token zastavení analýzy
Počínaje PowerShellem 3.0 můžete pomocí tokenu stop-parsing (--%
) zastavit interpretovat vstup jako powershellové příkazy nebo výrazy.
Poznámka:
Token stop-parsing je určen pouze pro použití nativních příkazů na platformách Windows.
Při volání nativního příkazu před argumenty programu umístěte token stop-parsing. Tato technika je mnohem jednodušší než použití řídicích znaků, aby se zabránilo nesprávné interpretaci.
Když dojde k zastavení parsování tokenu, PowerShell považuje zbývající znaky na řádku za literál. Jedinou interpretací, kterou provádí, je nahradit hodnoty proměnných prostředí, které používají standardní notaci systému Windows, například %USERPROFILE%
.
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
PowerShell odešle do icacls.exe
programu následující příkazový řetězec:
X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
Token zastavení parsování je efektivní jenom do dalšího znaku nového řádku nebo kanálu. Znak pokračování řádku (`
) nelze použít k rozšíření jeho efektu nebo k ukončení jeho efektu použijte oddělovač příkazů (;
).
%variable%
Kromě odkazů na proměnné prostředí nemůžete do příkazu vložit žádné další dynamické prvky. Escaping a %
character as %%
, the way you can do inside batch files, isn't supported. %<name>%
tokeny se neustále rozšiřují. Pokud <name>
neodkazuje na definovanou proměnnou prostředí, token se předává tak, jak je.
Přesměrování datového proudu (například >file.txt
) nemůžete použít, protože se předávají doslovně jako argumenty cílovému příkazu.
V následujícím příkladu první krok spustí příkaz bez použití tokenu stop-parsing. PowerShell vyhodnotí řetězec v uvozovkách a předá hodnotu (bez uvozovek), což cmd.exe
způsobí chybu.
PS> cmd /c echo "a|b"
'b' is not recognized as an internal or external command,
operable program or batch file.
PS> cmd /c --% echo "a|b"
"a|b"
Poznámka:
Při použití rutin PowerShellu není token stop-parsing potřeba. Může ale být užitečné předat argumenty funkci PowerShellu, která je navržená k volání nativního příkazu s těmito argumenty.
Předávání argumentů obsahujících znaky uvozovek
Některé nativní příkazy očekávají argumenty, které obsahují znaky uvozovek. PowerShell 7.2 obsahuje experimentální funkci PSNativeCommandArgumentPassing , která mění způsob analýzy příkazového řádku pro nativní příkazy. Další informace najdete v tématu Použití experimentálních funkcí.
Upozornění
Nové chování je zásadní změnou chování prostředí Windows PowerShell 5.1. To může narušit skripty a automatizaci, které řeší různé problémy při vyvolání nativních aplikací. Pomocí tokenu stop-parsing (--%
) nebo Start-Process
rutiny se v případě potřeby vyhněte předávání nativních argumentů.
Toto chování řídí nová $PSNativeCommandArgumentPassing
proměnná předvoleb. Tato proměnná umožňuje vybrat chování za běhu. Platné hodnoty jsou Legacy
, Standard
a Windows
. Výchozí chování je specifické pro platformu. Na platformách Windows je Windows
výchozí nastavení a jiné platformy než Windows .Standard
Legacy
je historické chování. Chování Windows
a Standard
režim jsou stejné s výjimkou Windows
vyvolání následujících souborů v režimu automaticky používají Legacy
předávání argumentu stylu.
cmd.exe
cscript.exe
wscript.exe
- končící na
.bat
- končící na
.cmd
- končící na
.js
- končící na
.vbs
- končící na
.wsf
Pokud je tato možnost $PSNativeCommandArgumentPassing
nastavená na hodnotu Legacy
nebo Standard
, analyzátor tyto soubory nekontroluje.
Poznámka:
Následující příklady používají TestExe.exe
nástroj. Můžete sestavovat TestExe
ze zdrojového kódu. Viz TestExe ve zdrojovém úložišti PowerShellu.
Nové chování zpřístupněné touto změnou:
Literály nebo rozbalitelné řetězce s vloženými uvozovkami jsou nyní zachovány:
PS> $a = 'a" "b' PS> TestExe -echoargs $a 'c" "d' e" "f Arg 0 is <a" "b> Arg 1 is <c" "d> Arg 2 is <e f>
Prázdné řetězce jako argumenty se teď zachovají:
PS> TestExe -echoargs '' a b '' Arg 0 is <> Arg 1 is <a> Arg 2 is <b> Arg 3 is <>
Cílem těchto příkladů je předat cestu k adresáři (s mezerami a uvozovkami) "C:\Program Files (x86)\Microsoft\"
nativnímu příkazu, aby získal cestu jako řetězec v uvozovkách.
Následující příklady v Windows
nebo Standard
režimu vytvářejí očekávané výsledky:
TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'
Pokud chcete získat stejné výsledky v Legacy
režimu, musíte uvozovky uvozovky nebo použít token zastavení parsování (--%
):
TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% ""\""C:\Program Files (x86)\Microsoft\\"\"""
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""
Poznámka:
Zpětný lomítko (\
) není v PowerShellu rozpoznán jako řídicí znak. Jedná se o řídicí znak používaný podkladovým rozhraním API pro ProcessStartInfo.ArgumentList.
PowerShell 7.3 také přidal možnost trasovat vazbu parametrů pro nativní příkazy. Další informace naleznete v tématu Trace-Command.
Předávání argumentů příkazům PowerShellu
Počínaje PowerShellem 3.0 můžete pomocí tokenu koncového parametru (--
) zastavit interpretaci vstupu jako parametrů PowerShellu. Toto je konvence zadaná ve specifikaci prostředí POSIX a nástrojů.
Token koncového parametru
Token konce parametrů (--
) označuje, že všechny argumenty, které následují, mají být předány ve skutečné podobě, jako by se kolem nich umístily dvojité uvozovky. Když například použijete --
výstup řetězce -InputObject
bez použití uvozovek nebo ho interpretujete jako parametr:
Write-Output -- -InputObject
-InputObject
Na rozdíl od tokenu stop-parsing (--%
) je možné všechny hodnoty následující za --
tokenem interpretovat jako výrazy pomocí PowerShellu.
Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64
Toto chování platí jenom pro příkazy PowerShellu. Pokud token použijete --
při volání externího příkazu, --
řetězec se předá jako argument pro tento příkaz.
TestExe -echoargs -a -b -- -c
Výstup ukazuje, že --
se předává jako argument .TestExe
Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>
Tilda (~)
Znak tilda (~
) má v PowerShellu zvláštní význam. Když se používá s příkazy PowerShellu na začátku cesty, znak tilda se rozbalí do domovského adresáře uživatele. Pokud se znak tilda používá kdekoli jinde v cestě, považuje se za literální znak.
PS D:\temp> $PWD
Path
----
D:\temp
PS D:\temp> Set-Location ~
PS C:\Users\user2> $PWD
Path
----
C:\Users\user2
V tomto příkladu parametr New-Item
Name očekává řetězec. Znak tilda se považuje za literální znak. Pokud chcete přejít na nově vytvořený adresář, musíte kvalifikovat cestu znakem tildy.
PS D:\temp> Set-Location ~
PS C:\Users\user2> New-Item -Type Directory -Name ~
Directory: C:\Users\user2
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 5/6/2024 2:08 PM ~
PS C:\Users\user2> Set-Location ~
PS C:\Users\user2> Set-Location .\~
PS C:\Users\user2\~> $PWD
Path
----
C:\Users\user2\~
Pokud použijete znak tilda s nativními příkazy, PowerShell předá tilda jako literálový znak. Použití vlnovek v cestě způsobuje chyby nativních příkazů ve Windows, které nepodporují znak tilda.
PS D:\temp> $PWD
Path
----
D:\temp
PS D:\temp> Get-Item ~\repocache.clixml
Directory: C:\Users\user2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/29/2024 3:42 PM 88177 repocache.clixml
PS D:\temp> more.com ~\repocache.clixml
Cannot access file D:\temp\~\repocache.clixml