about_Parsing
簡短描述
描述 PowerShell 如何剖析命令。
完整描述
當您在命令提示字元中輸入命令時,PowerShell 會將命令文字分成一系列稱為 Token 的區段,然後決定如何解譯每個令牌。
例如,如果您輸入:
Write-Host book
PowerShell 會將命令分成兩個令牌, Write-Host
並使用 book
兩個主要剖析模式之一獨立解譯每個令牌:表達式模式和自變數模式。
注意
當 PowerShell 剖析命令輸入時,它會嘗試將命令名稱解析為 Cmdlet 或原生可執行檔。 如果命令名稱沒有完全相符,PowerShell 會在命令前面加上 Get-
作為默認動詞。 例如,PowerShell 會 Service
剖析為 Get-Service
。 基於下列原因,不建議使用此功能:
- 效率不佳。 這會導致PowerShell多次搜尋。
- 系統會先解析具有相同名稱的外部程式,因此您可能不會執行預期的 Cmdlet。
Get-Help
和Get-Command
無法辨識無動詞名稱。- 命令名稱可能是保留字或語言關鍵詞。
Process
同時為 ,且無法解析為Get-Process
。
表達式模式
表達式模式是用於合併表示式,在腳本語言中操作值時需要。 表達式是PowerShell語法中值的表示法,而且可以是簡單或複合的,例如:
常值表達式是其值的直接表示法:
'hello'
32
變數表示式會包含其參考的變數值:
$x
$script:path
運算子結合其他運算式以進行評估:
-12
-not $Quiet
3 + 7
$input.Length -gt 1
- 字元字串常值 必須包含在引號中。
- 除非逸出) ,否則數位會視為數值,而不是一系列字元 (。
- 運算子,包括 和 之類的
-
一元運算符和-not
二元運算符+
-gt
,會解譯為運算符,並在其自變數上套用其個別的運算, (操作數) 。 - 屬性和轉換表達式 會剖析為表達式,並套用至次級表達式。 例如:
[int] '7'
。 - 變數參考 會評估其值,但 禁止展開 ,並造成剖析器錯誤。
- 任何其他項目都會被視為要叫用的命令。
自變數模式
剖析時,PowerShell 會先將輸入解譯為表達式。 但是遇到命令調用時,剖析會繼續處於自變數模式。 如果您有包含空格的自變數,例如路徑,則必須以引號括住這些自變數值。
自變數模式是專為剖析殼層環境中命令的自變數和參數所設計。 除非輸入使用下列其中一種語法,否則所有輸入都會視為可展開的字串:
貨幣符號 (
$
) 後面接著變數名稱會開始變數參考,否則它會解譯為可展開字串的一部分。 變數參考可以包含成員存取或編製索引。- 遵循簡單變數參考的其他字元,例如
$HOME
,會被視為相同自變數的一部分。 將變數名稱括在大括號 ({}
) ,以分隔它與後續字元。 例如:${HOME}
。 - 當變數參考包含成員存取權時,任何其他字元的第一個會被視為新自變數的開頭。 例如
$HOME.Length-more
,會產生兩個自變數:和字串常值$HOME.Length
-more
的值。
- 遵循簡單變數參考的其他字元,例如
引號 (
'
和"
) 開始字串大括弧 (
{}
) 開始新的腳本區塊逗號 (
,
) 引進以數位形式傳遞的清單,除非呼叫的命令是原生應用程式,在此情況下,它們會解譯為可展開字串的一部分。 不支援初始、連續或尾端逗號。括號 ()
()
開始新的表達式子表達式運算子 (
$()
) 開始內嵌表達式初始登入 ()
@
會開始表達式語法,例如 splatting@args
() 、陣列 (@(1,2,3)
) ,以及哈希表常值 (@{a=1;b=2}
) 。()
、$()
和@()
在令牌開頭建立可包含表達式或巢狀命令的新剖析內容。- 後面接著其他字元時,第一個額外的字元會被視為新、個別自變數的開頭。
- 在未加上引號的常值
$()
前面運作時,就像可展開的字串一樣,()
會啟動新的自變數做為表達式,並使用@()
開頭為表達式的新自變數做為常值@
()
。
其他所有專案都會被視為可展開的字串,但仍需要逸出的中繼字元除外。 請參閱 處理特殊字元。
- 自變數模式中繼字元 (具有特殊語法意義的字元) 為:
<space> ' " ` , ; ( ) { } | & < > @ #
。 在這些專案中,< > @ #
只有在令牌開始時才特別。
- 自變數模式中繼字元 (具有特殊語法意義的字元) 為:
停止剖析令牌 (
--%
) 會變更所有剩餘自變數的解譯。 如需詳細資訊,請參閱下方的 停止剖析令牌 一節。
範例
下表提供數個在表達式模式和自變數模式中處理的令牌範例,以及這些令牌的評估。 針對這些範例,變數 $a
的值是 4
。
範例 | 模式 | 結果 |
---|---|---|
2 |
運算是 | 2 (整數) |
`2 |
運算式 | “2” (命令) |
Write-Output 2 |
運算式 | 2 (整數) |
2+2 |
運算式 | 4 (整數) |
Write-Output 2+2 |
引數 | “2+2” (字串) |
Write-Output(2+2) |
運算式 | 4 (整數) |
$a |
運算式 | 4 (整數) |
Write-Output $a |
運算式 | 4 (整數) |
$a+2 |
運算式 | 6 (整數) |
Write-Output $a+2 |
引數 | “4+2” (字串) |
$- |
引數 | “$-” (命令) |
Write-Output $- |
引數 | “$-” (字串) |
a$a |
運算式 | “a$a” (命令) |
Write-Output a$a |
引數 | “a4” (字串) |
a'$a' |
運算式 | “a$a” (命令) |
Write-Output a'$a' |
引數 | “a$a” (字串) |
a"$a" |
運算式 | “a$a” (命令) |
Write-Output a"$a" |
引數 | “a4” (字串) |
a$(2) |
運算式 | “a$ (2) ” (命令) |
Write-Output a$(2) |
引數 | “a2” (字串) |
每個標記都可以解譯為某種物件類型,例如 布爾 值或 字串。 PowerShell 會嘗試從表達式判斷物件類型。 物件類型取決於命令預期的參數類型,以及 PowerShell 是否知道如何將自變數轉換成正確的類型。 下表顯示指派給表達式所傳回值的數個型別範例。
範例 | 模式 | 結果 |
---|---|---|
Write-Output !1 |
引數 | “!1” (字串) |
Write-Output (!1) |
expression | False (布爾值) |
Write-Output (2) |
expression | 2 (整數) |
Set-Variable AB A,B |
引數 | 'A','B' (陣列) |
CMD /CECHO A,B |
引數 | 'A,B' (字串) |
CMD /CECHO $AB |
expression | 'A B' (陣列) |
CMD /CECHO :$AB |
引數 | ':A B' (字串) |
處理特殊字元
反引號字元 (`
) 可用來逸出表達式中的任何特殊字元。 這最適合用來逸出您想要作為常值字元而非中繼字元的自變數模式中繼字元。 例如,若要使用貨幣符號 ($
) 做為可展開字串中的常值:
"The value of `$ErrorActionPreference is '$ErrorActionPreference'."
The value of $ErrorActionPreference is 'Continue'.
行接續
反引號字元也可以在行尾使用,讓您在下一行繼續輸入。 這可改善命令的可讀性,該命令會採用數個具有長名稱和自變數值的參數。 例如:
New-AzVm `
-ResourceGroupName "myResourceGroupVM" `
-Name "myVM" `
-Location "EastUS" `
-VirtualNetworkName "myVnet" `
-SubnetName "mySubnet" `
-SecurityGroupName "myNetworkSecurityGroup" `
-PublicIpAddressName "myPublicIpAddress" `
-Credential $cred
不過,您應該避免使用行接續。
- 反引號字元可能難以看到且容易忘記。
- 反引號后的額外空格會中斷行接續。 因為空間很難看到,所以很難找到錯誤。
PowerShell 在語法中的自然點提供數種方式斷行。
|
() 管道字元之後- 二元運算子 (
+
、-
、-eq
等 ) 之後 - 在陣列中 (
,
) 逗號之後 - 開啟字元之後,例如
[
、{
(
針對大型參數集,請改用展開。 例如:
$parameters = @{
ResourceGroupName = "myResourceGroupVM"
Name = "myVM"
Location = "EastUS"
VirtualNetworkName = "myVnet"
SubnetName = "mySubnet"
SecurityGroupName = "myNetworkSecurityGroup"
PublicIpAddressName = "myPublicIpAddress"
Credential = $cred
}
New-AzVm @parameters
將自變數傳遞至原生命令
從 PowerShell 執行原生命令時,PowerShell 會先剖析自變數。 剖析的自變數接著會聯結成單一字串,每個參數都以空格分隔。
例如,下列命令會呼叫 icacls.exe
程式。
icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
若要在PowerShell 2.0中執行此命令,您必須使用逸出字元來防止PowerShell誤譯括號。
icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F
停止剖析令牌
從 PowerShell 3.0 開始,您可以使用 停止剖 析 (--%
) 令牌來停止 PowerShell 將輸入解譯為 PowerShell 命令或表達式。
注意
停止剖析令牌僅適用於在 Windows 平臺上使用原生命令。
呼叫原生命令時,請將停止剖析令牌放在程式自變數之前。 這項技術比使用逸出字元來避免錯誤解譯更為容易。
當遇到停止剖析令牌時,PowerShell 會將行中的其餘字元視為常值。 它執行的唯一解譯是取代使用標準 Windows 表示法的環境變數值,例如 %USERPROFILE%
。
icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F
PowerShell 會將下列命令字串傳送至 icacls.exe
程式:
X:\VMS /grant Dom\HVAdmin:(CI)(OI)F
停止剖析令牌只有在下一個換行符或管線字元之後才會生效。 您無法使用行 `
接續字元 () 來擴充其效果,或使用命令分隔符 (;
) 終止其效果。
除了 %variable%
環境變數參考之外,您無法在 命令中內嵌任何其他動態元素。 不支援將 %
字元逸出為 %%
,您可以在批處理檔中執行的方式。 %<name>%
令牌會不可變地展開。 如果未 <name>
參考已定義的環境變數,令牌會依原狀傳遞。
您無法使用串流重新導向 (,例如 >file.txt
) ,因為它們會逐字傳遞為目標命令的自變數。
在下列範例中,第一個步驟會執行命令,而不使用停止剖析令牌。 PowerShell 會評估引號字串,並將值傳遞 (而不) 至 cmd.exe
,這會導致錯誤。
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"
注意
使用 PowerShell Cmdlet 時,不需要停止剖析令牌。 不過,將自變數傳遞至設計為使用這些自變數呼叫原生命令的 PowerShell 函式可能會很有用。
傳遞包含引號字元的自變數
某些原生命令需要包含引號字元的自變數。 PowerShell 7.3 已變更針對原生命令剖析命令行的方式。
警告
新行為是 Window PowerShell 5.1 行為 的重大變更 。 這可能會中斷在叫用原生應用程式時因應各種問題的腳本和自動化。 使用停止剖析令牌 (--%
) 或 Start-Process
Cmdlet,以避免在需要時傳遞原生自變數。
新的 $PSNativeCommandArgumentPassing
喜好設定變數會控制此行為。 此變數可讓您在運行時間選取行為。 合法值為 Legacy
、 Standard
與 Windows
。 默認行為是平臺特定的。 在 Windows 平臺上,預設設定為 Windows
,且非 Windows 平台預設為 Standard
。
Legacy
是歷史行為。 和 Standard
模式的行為Windows
相同,但模式中Windows
,下列檔案的調用會自動使用Legacy
樣式自變數傳遞。
cmd.exe
cscript.exe
wscript.exe
- 結尾為
.bat
- 結尾為
.cmd
- 結尾為
.js
- 結尾為
.vbs
- 結尾為
.wsf
$PSNativeCommandArgumentPassing
如果 設定為 Legacy
或 Standard
,則剖析器不會檢查這些檔案。
注意
下列範例會 TestExe.exe
使用 工具。 您可以從原始程式碼建置 TestExe
。 請參閱 PowerShell 來源存放庫中的 TestExe 。
這項變更提供的新行為:
具有內嵌引號的常值或可展開字串,現在會保留引號:
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>
現在會保留空字串作為自變數:
PS> TestExe -echoargs '' a b '' Arg 0 is <> Arg 1 is <a> Arg 2 is <b> Arg 3 is <>
這些範例的目標是使用空格和引號將目錄路徑 (傳遞至原生命令) "C:\Program Files (x86)\Microsoft\"
,以便以引號字串的形式接收路徑。
在 Windows
或 Standard
模式中,下列範例會產生預期的結果:
TestExe -echoargs """${env:ProgramFiles(x86)}\Microsoft\"""
TestExe -echoargs '"C:\Program Files (x86)\Microsoft\"'
若要在模式中 Legacy
取得相同的結果,您必須逸出引號,或使用停止剖析令牌 (--%
) :
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\\""
注意
PowerShell 無法將反斜杠 (\
) 字元辨識為逸出字元。 它是 ProcessStartInfo.ArgumentList 基礎 API 所使用的逸出字元。
PowerShell 7.3 也新增了追蹤原生命令之參數係結的功能。 如需詳細資訊,請參閱 Trace-Command。
將自變數傳遞至 PowerShell 命令
從 PowerShell 3.0 開始,您可以使用 參數結束 標記 () --
來停止 PowerShell 將輸入解譯為 PowerShell 參數。 這是 POSIX 殼層和公用程式規格中指定的慣例。
參數結尾令牌
參數結尾標記 (--
) 表示其後面的所有自變數都會以其實際形式傳遞,就像雙引號放在它們周圍一樣。 例如,您可以使用 --
來輸出字串 -InputObject
,而不使用引號或將它解譯為參數:
Write-Output -- -InputObject
-InputObject
不同於停止剖析 () --%
令牌,在標記之後 --
的任何值都可以由 PowerShell 解譯為表達式。
Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64
此行為僅適用於PowerShell命令。 如果您在呼叫外部命令時使用 --
令牌,字串 --
會當做自變數傳遞至該命令。
TestExe -echoargs -a -b -- -c
輸出會顯示 --
當做自變數傳遞至 TestExe
。
Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>
Tilde (~)
() 在 ~
PowerShell中具有特殊意義。 當它與路徑開頭的PowerShell命令搭配使用時,圖格字元會展開至使用者的主目錄。 如果在路徑中其他地方使用波浪字元,則會將其視為常值字元。
PS D:\temp> $PWD
Path
----
D:\temp
PS D:\temp> Set-Location ~
PS C:\Users\user2> $PWD
Path
----
C:\Users\user2
在此範例中,的 New-Item
Name 參數需要字串。 波浪字元會被視為常值字元。 若要變更為新建立的目錄,您必須使用波浪線字元限定路徑。
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\~
當您搭配原生命令使用波浪字元時,PowerShell 會將波浪圖傳遞為常值字元。 在路徑中使用波浪圖會導致 Windows 上不支援磚字元的原生命令發生錯誤。
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