Dela via


about_Parsing

Kort beskrivning

Beskriver hur PowerShell parsar kommandon.

Lång beskrivning

När du anger ett kommando i kommandotolken delar PowerShell upp kommandotexten i en serie segment som kallas token och bestämmer sedan hur varje token ska tolkas.

Om du till exempel skriver:

Write-Host book

PowerShell delar upp kommandot i två token och Write-Host book, och tolkar varje token oberoende av varandra med något av två huvudsakliga parsningslägen: uttrycksläge och argumentläge.

Kommentar

När PowerShell parsar kommandoindata försöker det matcha kommandonamnen till cmdletar eller inbyggda körbara filer. Om ett kommandonamn inte har någon exakt matchning förbereder Get- PowerShell kommandot som standardverb. PowerShell parsar Service till exempel som Get-Service. Vi rekommenderar inte att du använder den här funktionen av följande skäl:

  • Det är ineffektivt. Detta gör att PowerShell söker flera gånger.
  • Externa program med samma namn löses först, så du kanske inte kör den avsedda cmdleten.
  • Get-Help och Get-Command känner inte igen verblösa namn.
  • Kommandonamnet kan vara ett reserverat ord eller ett språknyckelord. Process är både och och kan inte matchas till Get-Process.

Uttrycksläge

Uttrycksläget är avsett för att kombinera uttryck som krävs för värdemanipulering på ett skriptspråk. Uttryck är representationer av värden i PowerShell-syntax och kan vara enkla eller sammansatta, till exempel:

Literaluttryck är direkta representationer av deras värden:

'hello'
32

Variabeluttryck har värdet för variabeln som de refererar till:

$x
$script:path

Operatorer kombinerar andra uttryck för utvärdering:

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • Teckensträngliteraler måste finnas inom citattecken.
  • Tal behandlas som numeriska värden i stället för som en serie tecken (om de inte är undantagna).
  • Operatorer, inklusive unary-operatorer som - och -not binära operatorer som + och -gt, tolkas som operatorer och tillämpar sina respektive åtgärder på sina argument (operander).
  • Attribut- och konverteringsuttryck parsas som uttryck och tillämpas på underordnade uttryck. Exempel: [int] '7'.
  • Variabelreferenser utvärderas till deras värden, men splatting är förbjudet och orsakar ett parserfel.
  • Allt annat behandlas som ett kommando som ska anropas.

Argumentläge

Vid parsning ser PowerShell först ut att tolka indata som ett uttryck. Men när ett kommandoanrop påträffas fortsätter parsningen i argumentläge. Om du har argument som innehåller blanksteg, till exempel sökvägar, måste du omsluta argumentvärdena med citattecken.

Argumentläget är utformat för att parsa argument och parametrar för kommandon i en gränssnittsmiljö. Alla indata behandlas som en expanderbar sträng om den inte använder någon av följande syntaxer:

  • Dollartecknet ($) följt av ett variabelnamn börjar en variabelreferens, annars tolkas det som en del av den expanderbara strängen. Variabelreferensen kan innehålla medlemsåtkomst eller indexering.

    • Ytterligare tecken som följer enkla variabelreferenser, till exempel $HOME, anses vara en del av samma argument. Omslut variabelnamnet i klammerparenteser ({}) för att skilja det från efterföljande tecken. Exempel: ${HOME}
    • När variabelreferensen innehåller medlemsåtkomst anses det första av ytterligare tecken vara början på ett nytt argument. Till exempel $HOME.Length-more resulterar i två argument: värdet $HOME.Length för och strängliteral -more.
  • Citattecken (' och ") börjar strängar

  • Klammerparenteser ({}) påbörjar ett nytt skriptblock

  • Kommatecken (,) introducerar listor som skickas som matriser, såvida inte kommandot som anropas är ett internt program, i vilket fall de tolkas som en del av den expanderbara strängen. Initiala, efterföljande eller avslutande kommatecken stöds inte.

  • Parenteser (()) påbörjar ett nytt uttryck

  • Underuttrycksoperatorn ($()) påbörjar ett inbäddat uttryck

  • Initial at sign (@) begins expression syntaxes such as splatting (@args), arrays (@(1,2,3)) and hash table literals (@{a=1;b=2}).

  • (), $(), och @() i början av en token skapar du en ny parsningskontext som kan innehålla uttryck eller kapslade kommandon.

    • När det följs av ytterligare tecken anses det första ytterligare tecknet vara början på ett nytt, separat argument.
    • När det föregås av en ociterad literal $() fungerar som en expanderbar sträng, () startar ett nytt argument som är ett uttryck och @() tas som literal @ med () att starta ett nytt argument som är ett uttryck.
  • Allt annat behandlas som en expanderbar sträng, förutom metakarakterare som fortfarande behöver fly. Se Hantera specialtecken.

    • Metakarakterarna för argumentläge (tecken med särskild syntaktisk betydelse) är: <space> ' " ` , ; ( ) { } | & < > @ #. Av dessa < > @ # är bara speciella i början av en token.
  • Token för stoppparsing (--%) ändrar tolkningen av alla återstående argument. Mer information finns i avsnittet stop-parsing token nedan.

Exempel

I följande tabell finns flera exempel på token som bearbetas i uttrycksläge och argumentläge samt utvärdering av dessa token. För dessa exempel är 4värdet för variabeln $a .

Exempel Läge Result
2 Uttryck 2 (heltal)
`2 Uttryck "2" (kommando)
Write-Output 2 Uttryck 2 (heltal)
2+2 Uttryck 4 (heltal)
Write-Output 2+2 Argument "2+2" (sträng)
Write-Output(2+2) Uttryck 4 (heltal)
$a Uttryck 4 (heltal)
Write-Output $a Uttryck 4 (heltal)
$a+2 Uttryck 6 (heltal)
Write-Output $a+2 Argument "4+2" (sträng)
$- Argument "$-" (kommando)
Write-Output $- Argument "$-" (sträng)
a$a Uttryck "a$a" (kommando)
Write-Output a$a Argument "a4" (sträng)
a'$a' Uttryck "a$a" (kommando)
Write-Output a'$a' Argument "a$a" (sträng)
a"$a" Uttryck "a$a" (kommando)
Write-Output a"$a" Argument "a4" (sträng)
a$(2) Uttryck "a$(2)" (kommando)
Write-Output a$(2) Argument "a2" (sträng)

Varje token kan tolkas som någon typ av objekttyp, till exempel boolesk eller sträng. PowerShell försöker fastställa objekttypen från uttrycket. Objekttypen beror på vilken typ av parameter ett kommando förväntar sig och om PowerShell vet hur argumentet ska konverteras till rätt typ. I följande tabell visas flera exempel på de typer som tilldelats värden som returneras av uttrycken.

Exempel Läge Result
Write-Output !1 argument "!1" (sträng)
Write-Output (!1) uttryck Falskt (booleskt)
Write-Output (2) uttryck 2 (heltal)
Set-Variable AB A,B argument 'A','B' (matris)
CMD /CECHO A,B argument 'A,B' (sträng)
CMD /CECHO $AB uttryck "A B" (matris)
CMD /CECHO :$AB argument ':A B' (sträng)

Hantering av specialtecken

Backtick-tecknet (`) kan användas för att undvika specialtecken i ett uttryck. Detta är mest användbart för att undvika de metakarakterare i argumentläge som du vill använda som literaltecken i stället för som metakarakterare. Om du till exempel vill använda dollartecknet ($) som en literal i en expanderbar sträng:

"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.

Radfortsättning

Backtick-tecknet kan också användas i slutet av en rad så att du kan fortsätta indata på nästa rad. Detta förbättrar läsbarheten för ett kommando som tar flera parametrar med långa namn och argumentvärden. Till exempel:

New-AzVm `
    -ResourceGroupName "myResourceGroupVM" `
    -Name "myVM" `
    -Location "EastUS" `
    -VirtualNetworkName "myVnet" `
    -SubnetName "mySubnet" `
    -SecurityGroupName "myNetworkSecurityGroup" `
    -PublicIpAddressName "myPublicIpAddress" `
    -Credential $cred

Du bör dock undvika att använda radfortsättning.

  • Backtick-tecknen kan vara svåra att se och lätta att glömma.
  • Ett extra utrymme efter att backticken bryter linjefortsättningen. Eftersom utrymmet är svårt att se kan det vara svårt att hitta felet.

PowerShell innehåller flera sätt att bryta linjer vid naturliga punkter i syntaxen.

  • Efter pipe tecken (|)
  • Efter binära operatorer (+, -, -eq, osv.)
  • Efter kommatecken (,) i en matris
  • När du har öppnat tecken som [, {, (

Använd splatting i stället för stora parameteruppsättningar. Till exempel:

$parameters = @{
    ResourceGroupName = "myResourceGroupVM"
    Name = "myVM"
    Location = "EastUS"
    VirtualNetworkName = "myVnet"
    SubnetName = "mySubnet"
    SecurityGroupName = "myNetworkSecurityGroup"
    PublicIpAddressName = "myPublicIpAddress"
    Credential = $cred
}
New-AzVm @parameters

Skicka argument till interna kommandon

När du kör interna kommandon från PowerShell parsas argumenten först av PowerShell. De parsade argumenten kopplas sedan till en enda sträng med varje parameter avgränsad med ett blanksteg.

Följande kommando anropar till exempel programmet icacls.exe .

icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

Om du vill köra det här kommandot i PowerShell 2.0 måste du använda escape-tecken för att förhindra att PowerShell feltolkar parenteserna.

icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F

Token för stoppparsning

Från och med PowerShell 3.0 kan du använda token för att stoppa parsning (--%) för att hindra PowerShell från att tolka indata som PowerShell-kommandon eller -uttryck.

Kommentar

Token för stoppparsning är endast avsedd för användning av interna kommandon på Windows-plattformar.

När du anropar ett internt kommando placerar du stop-parsing-token före programargumenten. Den här tekniken är mycket enklare än att använda escape-tecken för att förhindra feltolkning.

När den stöter på en stop-parsing-token behandlar PowerShell de återstående tecknen på raden som en literal. Den enda tolkning som utförs är att ersätta värden för miljövariabler som använder Standard Windows-notation, till exempel %USERPROFILE%.

icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F

PowerShell skickar följande kommandosträng till programmet icacls.exe :

X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

Token för stoppparsning gäller endast fram till nästa nya rad- eller pipelinetecken. Du kan inte använda radfortsättningstecknet (`) för att utöka dess effekt eller använda en kommandogränsare (;) för att avsluta dess effekt.

Förutom %variable% miljövariabelreferenser kan du inte bädda in några andra dynamiska element i kommandot. Det går inte att undvika ett % tecken som %%, som du kan göra i batchfiler. %<name>% token expanderas alltid. Om <name> inte refererar till en definierad miljövariabel skickas token som den är.

Du kan inte använda strömomdirigering (till exempel >file.txt) eftersom de skickas ordagrant som argument till målkommandot.

I följande exempel kör det första steget ett kommando utan att använda stop-parsing-token. PowerShell utvärderar den citerade strängen och skickar värdet (utan citattecken) till cmd.exe, vilket resulterar i ett fel.

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"

Kommentar

Token för stoppparsning behövs inte när du använder PowerShell-cmdletar. Det kan dock vara användbart att skicka argument till en PowerShell-funktion som är utformad för att anropa ett internt kommando med dessa argument.

Skicka argument som innehåller citattecken

Vissa interna kommandon förväntar sig argument som innehåller citattecken. PowerShell 7.3 ändrade hur kommandoraden parsas för interna kommandon.

Varning

Det nya beteendet är en icke-bakåtkompatibel ändring från Windows PowerShell 5.1-beteendet. Detta kan bryta skript och automatisering som kringgår de olika problemen när inbyggda program anropas. Använd stop-parsing-token (--%) eller cmdleten Start-Process för att undvika att det interna argumentet skickas vid behov.

Den nya $PSNativeCommandArgumentPassing inställningsvariabeln styr det här beteendet. Med den här variabeln kan du välja beteende vid körning. Giltiga värden är Legacy, Standardoch Windows. Standardbeteendet är plattformsspecifikt. På Windows-plattformar är Windows standardinställningen och icke-Windows-plattformar standardvärdet Standard.

Legacy är det historiska beteendet. Beteendet Windows för och Standard läget är detsamma förutom att Windows anrop av följande filer i läge automatiskt använder formatargumentet Legacy som skickas.

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • slutar med .bat
  • slutar med .cmd
  • slutar med .js
  • slutar med .vbs
  • slutar med .wsf

$PSNativeCommandArgumentPassing Om är inställt på antingen Legacy eller Standard, söker parsern inte efter dessa filer.

Kommentar

I följande exempel används TestExe.exe verktyget. Du kan skapa TestExe från källkoden. Se TestExe på PowerShell-källlagringsplatsen.

Nya beteenden som görs tillgängliga genom den här ändringen:

  • Literala eller expanderbara strängar med inbäddade citattecken bevaras nu:

    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>
    
  • Tomma strängar som argument bevaras nu:

    PS> TestExe -echoargs '' a b ''
    Arg 0 is <>
    Arg 1 is <a>
    Arg 2 is <b>
    Arg 3 is <>
    

Målet med dessa exempel är att skicka katalogsökvägen (med blanksteg och citattecken) "C:\Program Files (x86)\Microsoft\" till ett inbyggt kommando så att sökvägen tas emot som en citerad sträng.

I Windows eller Standard läge ger följande exempel förväntade resultat:

TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'

Om du vill få samma resultat i Legacy läge måste du undvika citattecknarna eller använda stop-parsing-token (--%):

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\\""

Kommentar

Omvänt snedstreck (\) känns inte igen som ett escape-tecken av PowerShell. Det är escape-tecknet som används av det underliggande API:et för ProcessStartInfo.ArgumentList.

PowerShell 7.3 har också lagt till möjligheten att spåra parameterbindning för interna kommandon. Mer information finns i Trace-Command.

Skicka argument till PowerShell-kommandon

Från och med PowerShell 3.0 kan du använda token för slutparametrar (--) för att hindra PowerShell från att tolka indata som PowerShell-parametrar. Detta är en konvention som anges i POSIX Shell- och Utilities-specifikationen.

Token för slutparametrar

Token för slutparametrar (--) anger att alla argument som följer den ska skickas i deras faktiska form som om dubbla citattecken placerades runt dem. Om du till exempel använder -- kan du mata ut strängen -InputObject utan att använda citattecken eller låta den tolkas som en parameter:

Write-Output -- -InputObject
-InputObject

Till skillnad från token för stop-parsning (--%) kan alla värden som följer -- token tolkas som uttryck av PowerShell.

Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64

Det här beteendet gäller endast för PowerShell-kommandon. Om du använder -- token när du anropar ett externt kommando skickas strängen -- som ett argument till kommandot.

TestExe -echoargs -a -b -- -c

Utdata visar att -- skickas som ett argument till TestExe.

Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>

Tilde (~)

Tilde-tecknet (~) har en särskild betydelse i PowerShell. När det används med PowerShell-kommandon i början av en sökväg expanderas tilde-tecknet till användarens hemkatalog. Om tilde-tecknet används någon annanstans i en sökväg behandlas det som ett literaltecken.

PS D:\temp> $PWD

Path
----
D:\temp

PS D:\temp> Set-Location ~
PS C:\Users\user2> $PWD

Path
----
C:\Users\user2

I det här exemplet förväntar sig parametern Namn för en New-Item sträng. Tilde-tecknet behandlas som ett literaltecken. Om du vill ändra till den nyligen skapade katalogen måste du kvalificera sökvägen med tilde-tecknet.

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\~

När du använder tilde-tecknet med interna kommandon skickar PowerShell tilde som ett literaltecken. Om du använder tilde i en sökväg uppstår fel för interna kommandon i Windows som inte stöder tilde-tecknet.

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

Se även