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.3 změnil způsob analýzy příkazového řádku pro nativní příkazy.
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