簡短描述
描述 PowerShell 如何剖析命令。
完整描述
當您在命令提示字元中輸入命令時,PowerShell 會將命令文字分成一系列稱為 標記的區段,然後決定如何解譯每個令牌。
例如,如果您輸入:
Write-Host book
PowerShell 會將命令分成兩個令牌,Write-Host 和 book,並使用兩個主要剖析模式之一獨立解譯每個令牌:表達式模式和自變數模式。
備註
當 PowerShell 剖析命令輸入時,它會嘗試將命令名稱解析為 Cmdlet 或原生可執行檔。 如果命令名稱沒有完全匹配,PowerShell 會將命令作為默認動詞添加到 Get- 前面。 例如,PowerShell 會將 Process 剖析為 Get-Process。 基於下列原因,不建議使用此功能:
- 效率不佳。 這會導致PowerShell多次搜尋。
- 首先解析具有相同名稱的外部程式,因此不能執行預期的 cmdlet。
-
Get-Help和Get-Command無法辨識無動詞名稱。
表達式模式
表達式模式是用於結合運算式,這是在腳本語言中進行值操作的必要功能。 表達式是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' (字串) |
將參數傳遞至原生指令
從 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),因為它們是作為參數逐字傳遞給 target 命令的。
傳遞包含引號字元的參數
某些原生命令需要包含引號字元的自變數。 一般而言,PowerShell 的命令行剖析會移除您提供的引號字元。 剖析的自變數接著會聯結成單一字串,每個參數都以空格分隔。 然後,這個字串會指派給 物件的Arguments 屬性 ProcessStartInfo 。 字串內的引號必須使用額外的引號或反斜杠 (\) 字元逸出。
備註
PowerShell 不會將反斜杠 ()\ 字元識別為轉義字元。 它是底層 API ProcessStartInfo.Arguments用於的轉義字元。
如需逸出需求的詳細資訊,請參閱 ProcessStartInfo.Arguments 的檔。
以下是使用該工具 TestExe.exe 的範例。 PowerShell 源儲存庫中的 Pester 測試使用此工具。 這些範例的目標是將目錄路徑 "C:\Program Files (x86)\Microsoft\" 傳遞至原生命令,使其接收路徑做為引號字串。
的 參數會將接收的值顯示為可執行檔的自變數。 您可以使用此工具來確認您已正確逸出自變數中的字元。
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 --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""
所有範例的輸出都相同:
Arg 0 is <"C:\Program Files (x86)\Microsoft\">
您可以從原始程式碼建置 TestExe。 請參閱 TestExe。
將自變數傳遞至 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>