共用方式為


關於解析

簡短描述

描述 PowerShell 如何剖析命令。

完整描述

當您在命令提示字元中輸入命令時,PowerShell 會將命令文字分成一系列稱為 標記的區段,然後決定如何解譯每個令牌。

例如,如果您輸入:

Write-Host book

PowerShell 會將命令分成兩個令牌,Write-Hostbook,並使用兩個主要剖析模式之一獨立解譯每個令牌:表達式模式和自變數模式。

備註

當 PowerShell 剖析命令輸入時,它會嘗試將命令名稱解析為 Cmdlet 或原生可執行檔。 如果命令名稱沒有精確匹配,PowerShell 會在命令前面加上 Get- 作為預設動詞。 例如,PowerShell 會將 Service 剖析為 Get-Service。 基於下列原因,不建議使用此功能:

  • 效率不佳。 這會導致PowerShell多次搜尋。
  • 具有相同名稱的外部程式會先解析,因此您可能不會執行預期的 Cmdlet。
  • Get-HelpGet-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 $- 論點 “$-” (string)
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) 運算式 假(布爾值)
Write-Output (2) 運算式 2 (整數)
Set-Variable AB A,B 引數 'A','B'(陣列)
CMD /CECHO A,B 引數 'A,B' (字串)
CMD /CECHO $AB 運算式 '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 將輸入解析為命令或表達式。

備註

停止解析符號僅適用於 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> 未參考定義的環境變數,令牌會透過 as-is傳遞。

您無法使用流重定向(例如 >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 已變更命令行剖析原生命令的方式。

謹慎

新行為是 Windows PowerShell 5.1 行為的 重大更改 。 這可能會中斷在叫用原生應用程式時解決各種問題的腳本和自動化。 在需要時,使用停止剖析標記(--%)或 Start-Process cmdlet 以避免本機引數傳遞。

新的 $PSNativeCommandArgumentPassing 喜好設定變數會控制此行為。 此變數可讓您在運行時間選取行為。 有效值為 LegacyStandardWindows。 默認行為是平臺特定的。 在 Windows 平臺上,預設設定為 Windows,非 Windows 平台預設為 Standard

Legacy 是具有歷史意義的行為。 WindowsStandard 模式的行為相同,但在 Windows 模式中,下列檔案的調用會自動使用 Legacy 樣式自變數傳遞。

  • cmd.exe
  • cscript.exe
  • wscript.exe
  • .bat 結尾
  • .cmd 結尾
  • .js 結尾
  • .vbs 結尾
  • .wsf 結尾

如果 $PSNativeCommandArgumentPassing 設定為 LegacyStandard,剖析器不會檢查這些檔案。

備註

下列範例使用 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\" 傳遞至原生命令,使其接收路徑做為引號字串。

WindowsStandard 模式中,下列範例會產生預期的結果:

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 無法將反斜杠 (\) 字元辨識為逸出字元。 這是基礎 API 用於 ProcessStartInfo.ArgumentList的逸出字元。

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>

蒂爾德 (~)

波浪符號(~)在 PowerShell 中具有特殊意義。 當它與路徑開頭的PowerShell命令搭配使用時,磚字元會展開至使用者的主目錄。 如果路徑中任何其他位置都使用Tilde 字元,則會將其視為常值字元。

PS D:\temp> $PWD

Path
----
D:\temp

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

Path
----
C:\Users\user2

在此範例中,New-Item 參數需要字串。 波浪號字元會被視為文字字元。 若要變更為新建立的目錄,您必須使用並排字元來限定路徑。

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

當您搭配原生命令使用 tilde 字元時,PowerShell 會將磚傳遞為常值字元。 在路徑中使用Tilde 會導致 Windows 上不支援Tilde 字元的原生命令發生錯誤。

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

另請參閱