編輯附註
重要
Windows PowerShell 語言規格 3.0 於 2012 年 12 月發行,並以 Windows PowerShell 3.0 為基礎。 此規格不會反映 PowerShell 的目前狀態。 沒有計劃更新此檔以反映目前的狀態。 此文件在此提供作為歷史參考。
規範文件可作為 Microsoft Word 檔從 Microsoft 下載中心取得:https://www.microsoft.com/download/details.aspx?id=36389 此 Word 檔已在 Microsoft Learn 上轉換以供展示。 在轉換期間,已進行一些編輯變更,以配合 Docs 平臺的格式設定。 已修正某些錯字和次要錯誤。
8.1 語句區塊和清單
語法:
提示
語法定義中的 ~opt~ 表示法指出語彙實體在語法中是選擇性的。
statement-block:
new-lines~opt~ { statement-list~opt~ new-lines~opt~ }
statement-list:
statement
statement-list statement
statement:
if-statement
label~opt~ labeled-statement
function-statement
flow-control-statement statement-terminator
trap-statement
try-statement
data-statement
inlinescript-statement
parallel-statement
sequence-statement
pipeline statement-terminator
statement-terminator:
;
new-line-character
描述:
語句 指定要執行的某種動作。 除非在此子句中另有指示,否則語句會依語匯順序執行。
語句區塊 可讓一組語句分組成單一語法單位。
8.1.1 標記語句
語法:
labeled-statement:
switch-statement
foreach-statement
for-statement
while-statement
do-statement
描述:
迴圈語句(§8.4)或 switch 陳述式(§8.6)可以選擇性地在最前面加上一個標籤,標籤。 語句標籤可作為break敘述(§8.5.1)或continue敘述(§8.5.2)的選擇性目標。 不過,標籤不會改變控制流程。
冒號(:)和緊接著它的標記之間不允許有空格。
例子:
:go_here while ($j -le 100) {
# ...
}
:labelA
for ($i = 1; $i -le 5; ++$i) {
:labelB
for ($j = 1; $j -le 3; ++$j) {
:labelC
for ($k = 1; $k -le 2; ++$k) {
# ...
}
}
}
8.1.2 語句值
陳述的值是其寫入管線的累計的值集合。 如果語句寫入單一純量值,即為語句的值。 如果語句寫入多個值,語句的值就是一組儲存在不受限制之 1 維陣列元素中的值,依寫入的順序。 請考慮下列範例:
$v = for ($i = 10; $i -le 5; ++$i) { }
迴圈沒有執行任何反覆操作,並且不會寫入任何內容到管線。 語句的值是$null。
$v = for ($i = 1; $i -le 5; ++$i) { }
雖然迴圈迭代了五次,但沒有寫入管道。 陳述的值是$null。
$v = for ($i = 1; $i -le 5; ++$i) { $i }
循環重複五次,每次都將 int 值 $i寫入管線。 語句的值是 object[],長度為 5 位。
$v = for ($i = 1; $i -le 5; ) { ++$i }
雖然迴圈迭代了五次,但沒有寫入管道。 語句的值是$null。
$v = for ($i = 1; $i -le 5; ) { (++$i) }
迴圈會執行五次,每個值都會寫入管道。 語句的值是 object[],長度為 5 位。
$i = 1; $v = while ($i++ -lt 2) { $i }
迴圈會執行一次。 語句的值是值為 2 的 int。
以下是一些其他範例:
# if $count is not currently defined then define it with int value 10
$count = if ($count -eq $null) { 10 } else { $count }
$i = 1
$v = while ($i -le 5) {
$i # $i is written to the pipeline
if ($i -band 1) {
"odd" # conditionally written to the pipeline
}
++$i # not written to the pipeline
}
# $v is object[], Length 8, value 1,"odd",2,3,"odd",4,5,"odd"
8.2 管道陳述
語法:
pipeline:
assignment-expression
expression redirections~opt~ pipeline-tail~opt~
command verbatim-command-argument~opt~ pipeline-tail~opt~
assignment-expression:
expression assignment-operator statement
pipeline-tail:
| new-lines~opt~ command
| new-lines~opt~ command pipeline-tail
command:
command-name command-elements~opt~
command-invocation-operator command-module~opt~ command-name-expr command-elements~opt~
command-invocation-operator: one of
& .
command-module:
primary-expression
command-name:
generic-token
generic-token-with-subexpr
generic-token-with-subexpr:
No whitespace is allowed between ) and command-name.
generic-token-with-subexpr-start statement-list~opt~ )
command-namecommand-name-expr:
command-name
primary-expressioncommand-elements:
command-element
command-elements command-element
command-element:
command-parameter
command-argument
redirection
command-argument:
command-name-expr
verbatim-command-argument:
--% verbatim-command-argument-chars
描述:
重新導向 在 §7.12中討論;賦值表達式 在 §7.11中討論;以及 命令調用運算符 點(.)在 §3.5.5中討論。 如需有關命令調用中參數映射的討論,請參閱 §8.14。
管線 中的第一個命令是表達式或命令調用。 一般而言,命令調用的開頭是 命令名稱,這通常是裸露的標識符。 command-elements 代表命令的自變數清單。 換行符或未逸出的分號字符 n 會終止管線。
命令調用是由命令的名稱所組成,後面接著零個或多個自變數。 管理參數的規則如下:
不是表達式,但包含不含未逸出空格符之任意文字的自變數,會被視為雙引號。 會保留字母大小寫。
變數替代和子表達式展開(第章2.3.5.2)會在可展開字串常量中以及可展開這裡字串常量中進行。
引號內的文字允許在自變數的值中包含前置、尾端和內嵌空格符。 [附註:引號自變數中的空格符不會將單一自變數轉換成多個自變數。 結束注]
將括弧放在參數周圍,使該表達式被評估並將結果傳遞,而不是傳遞原始表達式的文字。
指定符合具有
[switch]類型條件約束的參數的自變數時(#.8.10.5),自變數名稱的存在會導致該參數設定為$true。 不過,您可以藉由將後綴附加至 自變數,明確地設定參數的值。 例如,假設類型限制參數 p,-p:$true的自變數會將 p 設定為 True,而-p:$false會將 p 設定為 False。--的自變數表示,之後的所有自變數都會以實際形式傳遞,就像將雙引號放在它們周圍一樣。--%的自變數表示之後的所有自變數都會以最少的剖析和處理方式傳遞。 這個自變數稱為逐字參數。 逐字參數後面的自變數不是PowerShell運算式,即使它們是語法有效的PowerShell運算式也一樣。
如果命令類型為 Application,則參數 --% 不會傳遞至命令。
--% 之後的自變數會展開任何環境變數(以 %括住的字串)。 例如:
echoargs.exe --% "%path%" # %path% is replaced with the value $Env:path
尚未指定參數評估的順序。
如需參數綁定的相關信息,請參閱 §8.14。 如需名稱查閱的相關信息,請參閱 §3.8。
一旦完成自變數處理,就會叫用 命令。 如果叫用的命令正常結束(§8.5.4),控制會回到腳本或函數中緊接在該命令叫用之後的點。 如需異常終止行為的描述,請參閱 break (§8.5.1)、continue (§8.5.2)、throw (§8.5.3)、exit(§8.5.5)、try(§8.7),以及 trap (§8.8)。
一般而言,命令會使用其名稱,後面接著任何自變數來叫用。 不過,可以使用命令呼叫運算子 &。 如果命令名稱包含未逸出的空格符,則需要用引號括起來,並使用此運算符來執行。 由於腳本區塊沒有名稱,因此必須使用這個運算符來叫用它。 例如,下列命令呼叫 Get-Factorial 的操作是等價的:
Get-Factorial 5
& Get-Factorial 5
& "Get-Factorial" 5
允許直接和間接遞迴函數調用。 例如
function Get-Power([int]$x, [int]$y) {
if ($y -gt 0) { return $x * (Get-Power $x (--$y)) }
else { return 1 }
}
例子:
New-Object 'int[,]' 3,2
New-Object -ArgumentList 3,2 -TypeName 'int[,]'
dir E:\PowerShell\Scripts\*statement*.ps1 | ForEach-Object {$_.Length}
dir E:\PowerShell\Scripts\*.ps1 |
Select-String -List "catch" |
Format-Table Path, LineNumber -AutoSize
8.3 if 語句
語法:
if-statement:
if new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-block
elseif-clauses~opt~ else-clause~opt~
elseif-clauses:
elseif-clause
elseif-clauses elseif-clause
elseif-clause:
new-lines~opt~ elseif new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-block
else-clause:
new-lines~opt~ else statement-block
描述:
Pipeline 控制表達式的類型必須是 bool 類型,或可隱式轉換為該類型。 else 子句 是可選的。 可能會有零個或多個 elseif 子句。
如果最上層 管線 測試 True,則會執行其 語句區塊,並終止語句的執行。 否則,如果 elseif-clause 存在,且其 流程 測試結果為 True,則會執行其 語句區塊 並終止該語句的執行。 否則,如果 else-clause 存在,則會執行其 語句區塊。
例子:
$grade = 92
if ($grade -ge 90) { "Grade A" }
elseif ($grade -ge 80) { "Grade B" }
elseif ($grade -ge 70) { "Grade C" }
elseif ($grade -ge 60) { "Grade D" }
else { "Grade F" }
8.4 迴圈語句
8.4.1 while 語句
語法:
while-statement:
while new-lines~opt~ ( new-lines~opt~ while-condition new-lines~opt~ ) statement-block
while-condition:
new-lines~opt~ pipeline
描述:
控制表達式 while-condition 必須具有bool類型,或隱含轉換成該類型。 循環主體由 語句區塊所組成,會重複執行,直到控制表達式測試 False 為止。 控制表達式會在每次執行循環主體之前進行評估。
例子:
$i = 1
while ($i -le 5) { # loop 5 times
"{0,1}`t{1,2}" -f $i, ($i*$i)
++$i
}
8.4.2 do 語句
語法:
do-statement:
do statement-block new-lines~opt~ while new-lines~opt~ ( while-condition new-lines~opt~ )
do statement-block new-lines~opt~ until new-lines~opt~ ( while-condition new-lines~opt~ )
while-condition:
new-lines~opt~ pipeline
描述:
控制表達式 while-condition 必須具有bool類型,或隱含轉換成該類型。 在 while 形式中,迴圈主體由 語句區塊所組成,當控制表達式為 True 時將重複執行。 在 until 結構中,迴圈主體會重複執行,直到控制表達式的結果為 True。 控制表達式會在迴圈主體的每個執行之後進行評估。
例子:
$i = 1
do {
"{0,1}`t{1,2}" -f $i, ($i * $i)
}
while (++$i -le 5) # loop 5 times
$i = 1
do {
"{0,1}`t{1,2}" -f $i, ($i * $i)
}
until (++$i -gt 5) # loop 5 times
8.4.3 for 語句
語法:
for-statement:
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~ statement-terminator
new-lines~opt~ for-iterator~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~
new-lines~opt~ ) statement-block
for-initializer:
pipeline
for-condition:
pipeline
for-iterator:
pipeline
描述:
控制表達式 在 for 迴圈中的條件 必須是 bool 類型,或能隱含地轉換為該類型。 循環主體由語句區塊 所組成,會在控制表達式測試為真時反覆執行。 控制表達式會在每次執行循環主體之前進行評估。
在控制表達式的第一次評估之前,會先評估表達式 for-initializer。 表達式 的初始化器 只會因其副作用而被評估;其所產生的任何值會被捨棄,且不會寫入管道。
每次執行循環主體後,都會評估運算式 為迭代器。 表達式 反覆運算器 只會評估其副作用;它所產生的任何值會被捨棄,而且不會寫入管線。
如果省略用於條件 的表達式
例子:
for ($i = 5; $i -ge 1; --$i) { # loop 5 times
"{0,1}`t{1,2}" -f $i, ($i * $i)
}
$i = 5
for (; $i -ge 1; ) { # equivalent behavior
"{0,1}`t{1,2}" -f $i, ($i * $i)
--$i
}
8.4.4 foreach 語句
語法:
foreach-statement:
foreach new-lines~opt~ foreach-parameter~opt~ new-lines~opt~
( new-lines~opt~ variable new-lines~opt~ *in* new-lines~opt~ pipeline
new-lines~opt~ ) statement-block
foreach-parameter:
-parallel
描述:
循環主體包含 語句區塊,針對由 管線指定的集合中由 變數 所指定的每個元素執行。
變數 的範圍不限於 foreach 語句。 因此,它會在迴圈主體完成執行之後保留其最終值。 如果 管線 指定純量(不包括值$null),而不是集合,該純量就會被視為一個元素的集合。 如果 管線 指定值 $null,管線 會被視為零元素的集合。
如果指定 foreach-parameter-parallel,則行為是由實作來定義的。
在工作流程中,僅允許使用 foreach-parameter‑parallel(§8.10.2)。
每個 foreach 語句都有自己的列舉值 $foreach (2.3.2.2、4.5.16),只有在該循環執行時才會存在。
在 語句區塊 開始執行之前,會先收集 管線 所產生的物件。 不過,使用 ForEach-Object cmdlet 時,語句區塊 會在每個物件產生時執行。
例子:
$a = 10, 53, 16, -43
foreach ($e in $a) {
...
}
$e # the int value -43
foreach ($e in -5..5) {
...
}
foreach ($t in [byte], [int], [long]) {
$t::MaxValue # get static property
}
foreach ($f in Get-ChildItem *.txt) {
...
}
$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }
foreach ($e in $h1.Keys) {
"Key is " + $e + ", Value is " + $h1[$e]
}
8.5 流程控制語句
語法:
flow-control-statement:
break label-expression~opt~
continue label-expression~opt~
throw pipeline~opt~
return pipeline~opt~
exit pipeline~opt~
label-expression:
simple-name
unary-expression
描述:
流程控制語句會導致無條件地將控制傳送到其他位置。
8.5.1 break 語句
描述:
具有
在陷阱語句之外,迭代語句內直接有未標示的 break 陳述 (§8.4) 會終止執行該最小包圍的迭代語句。 switch 陳述式中直接有未標記的 break 語句(§8.6)會終止目前 switch 的 switch 條件的模式比對。 如需在陷阱語句中使用 break 的詳細資訊,請參閱 (§8.8)。
迭代語句或 switch 語句可以選擇性地緊接在一個語句標籤前面(§8.1.1)。這類語句標籤可用作帶有標籤的 break 語句的目標。在此情況下,該語句會終止目標封閉的迭代語句的執行。
在任何本地範圍內,標示的中斷不需要立即解決;搜尋相符的標籤可能會繼續進行,甚至可以跨越腳本和函式呼叫的界限。 如果找不到相符的標籤,則會終止目前的命令調用。
label-expression 所指定的標籤名稱 不需要常數值。
如果 label-expression 是 一元表達式,則會轉換成字元串。
例子:
$i = 1
while ($true) { # infinite loop
if ($i * $i -gt 100) {
break # break out of current while loop
}
++$i
}
$lab = "go_here"
:go_here
for ($i = 1; ; ++$i) {
if ($i * $i -gt 50) {
break $lab # use a string value as target
}
}
:labelA
for ($i = 1; $i -le 2; $i++) {
:labelB
for ($j = 1; $j -le 2; $j++) {
:labelC
for ($k = 1; $k -le 3; $k++) {
if (...) { break labelA }
}
}
}
8.5.2 繼續語句
描述:
具有 continue 的 語句被稱為 的 continue 標記語句。 沒有 標籤表示式 的 continue 語句,稱作 未標記的 continue 語句。
迴圈內未標記的 continue 語句會終止當前迴圈的執行,並將控制權轉移至最小封閉的迴圈語句的結束大括號(§8.4)。 未標記的 continue 語句在 switch 中會終止目前 switch 迭代的執行,並將控制權傳輸至最近封閉的 switch's switch 條件 (§8.6)。
一個迭代語句或 switch 語句(§8.6)可能選擇性地可以被一個語句標籤直接引導(§8.1.1)。 這類語句標籤可作為已標籤 continue 語句的目標。在這種情況下,該語句將終止目前迴圈或 switch 迭代的執行,並將控制權轉移至目標封入的迭代或 switch 語句標籤。
任何本機範圍都不需要解析標示 continue;搜尋相符標籤可能會 continue 呼叫堆疊,即使是跨腳本和函式呼叫界限也一樣。 如果找不到相符的標籤,則會終止目前的命令調用。
label-expression 所指定的標籤名稱 不需要常數值。
如果 label-expression 是 一元表達式,則會轉換成字元串。
例子:
$i = 1
while (...) {
...
if (...) {
continue # start next iteration of current loop
}
...
}
$lab = "go_here"
:go_here
for (...; ...; ...) {
if (...) {
continue $lab # start next iteration of labeled loop
}
}
:labelA
for ($i = 1; $i -le 2; $i++) {
:labelB
for ($j = 1; $j -le 2; $j++) {
:labelC
for ($k = 1; $k -le 3; $k++) {
if (...) { continue labelB }
}
}
}
8.5.3 throw 語句
描述:
例外狀況是處理系統或應用層級錯誤條件的方法。 throw 語句會引發例外狀況。 (如需例外狀況處理的討論,請參閱 •8.7。
若省略 管線,且 throw 語句不在 catch 子句中,則行為由實作決定。 如果
如果 管道 存在,擲回的例外狀況類型由實作決定。
擲回例外狀況時,控件會傳送至可以處理例外狀況的封入 try 語句中的第一個 catch 子句。 一開始拋出例外狀況的位置稱為 拋出點。 一旦拋出例外狀況,§8.7 中所述的步驟會重複執行,直到找到匹配此例外狀況的 catch 子句,或者找不到任何匹配的 catch 子句。
例子:
throw
throw 100
throw "No such record in file"
如果省略 管線,而且 throw 語句不在 catch-clause內,則會將 “ScriptHalted” 文字寫入管線,而且引發的例外狀況類型為 System.Management.Automation.RuntimeException。
如果 管線 存在,引發的例外狀況會被包裝在一個類型為 System.Management.Automation.RuntimeException的物件中,其中包含關於該例外狀況的資訊,這些資訊以 System.Management.Automation.ErrorRecord 物件的形式呈現(可透過 $_存取)。
範例 1:throw 123 會導致類型 RuntimeException例外狀況。 從 catch 區塊內,$_.TargetObject 包含包裝在 內的物件,在此案例中為值 123 的 System.Int32。
範例 2:throw "xxx" 會導致類型 RuntimeException例外狀況。 在 catch 區塊中,$_.TargetObject 包含內部包裝的對象,此案例中的對象是值為「xxx」的 System.String。
範例 3:throw 10,20 會導致類型 RuntimeException例外狀況。 從 catch 區塊內,$_.TargetObject 包含包裝在其內的物件,在此案例中為 System.Object[],這是包含兩個 System元素的不受限制的陣列。Int32 的值 10 和 20。
8.5.4 傳回語句
描述:
return 語句會將管線所指定的值寫入至管線,管線所指定的值,如果有的話,並將控制權傳回給函式或腳本的呼叫端。 函式或腳本可能有零個或多個 return 語句。
如果執行到達函式的右括號,則假設存在一個不包含 return 的隱含 。
return 語句是一種「語法糖」,讓程式設計人員可以像用其他語言一樣表達自己;然而,從函式或腳本傳回的值實際上是該函式或腳本寫入至管線的所有值,加上任何由 管線所指定的值。 如果只有純量值寫入管線,則其類型為傳回之值的型別;否則,傳回型別是一個不受限制的 1 維陣列,其中包含寫入管線的所有值。
例子:
function Get-Factorial ($v) {
if ($v -eq 1) {
return 1 # return is not optional
}
return $v * (Get-Factorial ($v - 1)) # return is optional
}
呼叫 Get-Factorial 的呼叫者會收到 int。
function Test {
"text1" # "text1" is written to the pipeline
# ...
"text2" # "text2" is written to the pipeline
# ...
return 123 # 123 is written to the pipeline
}
要呼叫 Test 的呼叫者會得到一個包含三個元素的不受限制的一維陣列。
8.5.5 結束語句
描述:
exit 語句會終止目前的腳本,並將控制和 結束代碼傳回至主機環境或呼叫腳本。 如果提供 管線,則會在需要時將其所指定的值轉換成整數型別。 如果不存在這類轉換,或省略 管線,則會傳回 int 值零。
例子:
exit $count # terminate the script with some accumulated count
8.6 switch 陳述式
語法:
switch-statement:
switch new-lines~opt~ switch-parameters~opt~ switch-condition switch-body
switch-parameters:
switch-parameter
switch-parameters switch-parameter
switch-parameter:
-Regex
-Wildcard
-Exact
-CaseSensitive
-Parallel
switch-condition:
( new-lines~opt~ pipeline new-lines~opt~ )
-File new-lines~opt~ switch-filename
switch-filename:
command-argument
primary-expression
switch-body:
new-lines~opt~ { new-lines~opt~ switch-clauses }
switch-clauses:
switch-clause
switch-clauses switch-clause
switch-clause:
switch-clause-condition statement-block statement-terimators~opt~
switch-clause-condition:
command-argument
primary-expression
描述:
如果 開關條件 指派單一值,控制就會傳遞至一個或多個符合的模式語句區塊。 如果沒有模式相符,可以採取一些默認動作。
一個開關必須包含一個或多個 switch-clause,每個子句都以模式(非預設 switch 子句)或關鍵字 default(預設 switch 子句)開頭。 開關可以包含零或一個 default 開關子句,以及零個或多個非預設的開關子句。 Switch 子句可以依任何順序撰寫。
多個模式的值可能相同。 一個模式不必是文字常值,而 switch 語句可以包含不同類型的模式。
如果 開關條件 的值符合模式值,則執行該模式的語句區塊 。 如果 交換條件的值符合多個模式值,則會依詞法順序執行每個相符模式的 語句區塊,除非其中任何 語句區塊含有 break 語句(§8.5.1)。
如果 切換條件 的值不符合任何模式值,並且存在 default 切換子句,則會執行其 語句區塊;否則,該 切換條件 的模式比對將終止。
各個交換器可能是巢狀的,每個交換器都有自己的交換器子句集。 在這類情況下,switch 子句屬於目前範圍中最內層的 switch。
在進入每個 語句區塊時,$_ 會被自動賦予導致控制流到該 語句區塊的 開關條件 的值。
$_ 也可用於 語句區塊的 切換條件子句。
非字串的比對是通過測試是否相等(§7.8.1)。
如果比對涉及字串,則比較預設不區分大小寫。 當 切換參數-CaseSensitive 存在時,會使比較區分大小寫。
模式可能包含通配符(~3.15),在此情況下,會執行通配符字串比較,但前提是 參數-Wildcard 存在。 根據預設,比較不區分大小寫。
模式可能包含正則表達式 (\3.16),在此情況下,會執行正則表達式字串比較,但前提是 switch-parameter-Regex 存在。 根據預設,比較不區分大小寫。 如果 -Regex 存在且模式相符,$Matches 定義於該模式的 switch-clause語句區塊 中。
可以將 switch-parameter 縮寫;可以使用參數的任何不同前導部分。 例如,‑Regex、‑Rege、‑Reg、‑Re和 ‑R 相等。
如果指定了衝突的 switch-parameter,則語匯上最後一個占上風。
‑Exact 的存在會停用 -Regex 和 -Wildcard;不過,它不會影響 ‑Case。
如果指定了 switch-parameter‑Parallel,則其行為由實作決定。
工作流程中只允許 switch-parameter‑Parallel (§8.10.2)。
如果模式是 script-block-expression,則會評估該區塊,並視需要將結果轉換成 bool。 如果結果的值為 $true,則執行對應的 語句區塊,否則不執行。
如果 參數條件 指定多個值,則會按字母順序依次使用上述規則將交換條件套用到每個值,就像 參數條件 指定單一值時一樣。 每個 switch 語句都有自己的列舉器 $switch (§2.3.2.2,§4.5.16),只有在執行該 switch 語句時才存在。
switch 語句可能有標籤,而且可能包含已加上標籤且未標記的中斷 (\8.5.1),並繼續 (\8.5.2) 語句。
如果 switch-condition 是 -Fileswitch-filename,而不是在表達式中的值上迭代,則開關會依次處理 switch-filename所指定檔案中的值。檔案會逐行讀取,每一行代表一個值。 行終止符不會包含在值中。
例子:
$s = "ABC def`nghi`tjkl`fmno @#$"
$charCount = 0; $pageCount = 0; $lineCount = 0; $otherCount = 0
for ($i = 0; $i -lt $s.Length; ++$i) {
++$charCount
switch ($s[$i]) {
"`n" { ++$lineCount }
"`f" { ++$pageCount }
"`t" { }
" " { }
default { ++$otherCount }
}
}
switch -Wildcard ("abc") {
a* { "a*, $_" }
?B? { "?B? , $_" }
default { "default, $_" }
}
switch -Regex -CaseSensitive ("abc") {
^a* { "a*" }
^A* { "A*" }
}
switch (0, 1, 19, 20, 21) {
{ $_ -lt 20 } { "-lt 20" }
{ $_ -band 1 } { "Odd" }
{ $_ -eq 19 } { "-eq 19" }
default { "default" }
}
8.7 try/finally 語句
語法:
try-statement:
try statement-block catch-clauses
try statement-block finally-clause
try statement-block catch-clauses finally-clause
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
new-lines~opt~ catch catch-type-list~opt~
statement-block
catch-type-list:
new-lines~opt~ type-literal
catch-type-list new-lines~opt~ , new-lines~opt~
type-literalfinally-clause:
new-lines~opt~ finally statement-block
描述:
try 語句提供攔截區塊執行期間發生的例外狀況的機制。 try 語句也可讓您指定一律在控件離開 try 語句時執行的程式代碼區塊。 透過 throw 語句引發例外狀況的程式描述於 :8.5.3。
try 區塊
沒有 catch-type-list 的 catch-clause 稱為 通用捕獲子句。
每個 catch 子句 都是 例外狀況處理程式,而 catch 子句,其 catch 類型列表 包含引發例外狀況的類型是 匹配的 catch 子句。 一般 catch 子句符合所有例外狀況類型。
雖然 catch 子句 和 finally 子句 是選擇性的,但至少必須存在一個子句。
擲回例外狀況的處理是由重複評估下列步驟所組成,直到找到符合例外狀況的 catch 子句為止。
在目前的範圍內,會檢查封入擲回點的每個 try 語句。 針對每個 try 語句 S,從最內部的 try 語句開始,並以最外層的 try 語句結尾,會評估下列步驟:
如果
try的 區塊括住擲回點,而且如果 S 有一或多個 catch 子句,則會以語匯順序檢查 catch 子句,以找出適合例外狀況的處理程式。 第一個指定的例外狀況類型或其基底類型的 catch 子句會被視為相符。 一般的 catch 子句會被視為符合任何例外的條件。 如果找到相符的 catch 子句,則例外狀況處理會藉由將控制權傳送至該 catch 子句的區塊來完成。 在相符的 catch 子句內,變數$_包含目前例外狀況的描述。否則,如果
try區塊或catch的 區塊括住擲回點,而且如果 S 具有finally區塊,則會將控制權傳送至最後一個區塊。 如果finally區塊擲回另一個例外狀況,則會終止目前例外狀況的處理。 否則,當控件到達finally區塊的結尾時,會繼續處理目前的例外狀況。
如果例外狀況處理程式不在目前範圍中,則上述步驟會針對封入範圍重複,其擲回點會對應至叫用目前範圍之語句的擲回點。
如果例外狀況處理最終終止所有範圍,表示例外狀況沒有任何處理程式存在,則行為未指定。
若要防止 try 區塊中無法到達的 catch 子句,catch 子句不應該指定與相同 try 區塊中先前 catch 子句中指定的類型相等或衍生的例外狀況類型。
當控件離開 finally 語句時,一律會執行 try 區塊的語句。 無論是由於正常執行、執行 break、continue或 return 語句,還是因為從 try 語句拋出例外情況而發生的控制權轉移,這都為真。
如果在執行 finally 區塊期間擲回例外狀況,則會將例外狀況擲回至下一個封入 try 語句。 如果有另一個例外狀況正在處理中,該例外狀況會被丟棄。 產生例外狀況的程式會在 throw 語句的描述中進一步討論。
try 語句可以與 trap 語句共存;詳情請參閱 §8.8。
例子:
$a = New-Object 'int[]' 10
$i = 20 # out-of-bounds subscript
while ($true) {
try {
$a[$i] = 10
"Assignment completed without error"
break
}
catch [IndexOutOfRangeException] {
"Handling out-of-bounds index, >$_<`n"
$i = 5
}
catch {
"Caught unexpected exception"
}
finally {
# ...
}
}
擲回的每個例外狀況都會引發為 System.Management.Automation.RuntimeException。 如果在 區塊中存在特定類型的 try,則會檢查例外的 InnerException 屬性,以嘗試找到匹配項,例如上述類型 System.IndexOutOfRangeException。
8.8 陷阱語句
語法:
trap-statement:
*trap* new-lines~opt~ type-literal~opt~ new-lines~opt~ statement-block
描述:
具有和不含 trap 的 語句,與具有和不含 catch的 區塊(§8.7)類似,所不同的是 trap 語句一次只能捕捉一種類型。
多個 trap 語句可以在相同的 語句區塊中定義,而且其定義順序無關。 如果在相同範圍中定義了兩個具有相同 trap 的 語句,則語彙上第一個語句會用來處理相符類型的例外狀況。
不同於 catch 區塊,trap 語句完全符合例外狀況類型;不會執行任何衍生型別比對。
發生例外狀況時,如果目前範圍中沒有相符的 trap 語句,則會在封入範圍中搜尋相符的陷阱語句,這可能涉及在呼叫腳本、函式或篩選中尋找,然後在呼叫端中搜尋等等。 如果查閱最終終止所有範圍,表示例外狀況沒有任何處理程式存在,則行為未指定。
trap 語句的 語句主體 只有在處理相應的例外情況時才會執行;否則,執行將跳過它。
如果 trap的 語句主體 正常結束,則根據預設,錯誤物件會寫入錯誤數據流,例外狀況會被視為已處理,並且執行會在顯示例外狀況的範圍中,緊接著 trap 語句後繼續。 例外狀況的原因可能位於包含 trap 語句的命令所呼叫的命令中。
如果在 trap的 語句主體 中執行的最後一個語句是 continue(§8.5.2),則錯誤對象將不會被寫入到錯誤數據流,接下來,會繼續執行在讓例外狀況可見的設陷語句範圍中隨後的語句。 如果在 trap的 語句主體 中執行的最後一個語句是 break (§8.5.1),則會抑制錯誤物件寫入錯誤流,並重新拋出例外狀況。
在 trap 語句中,變數 $_ 包含目前錯誤的描述。
請考慮從 try 區塊內引發的例外狀況沒有相符的 catch 區塊,但相符的 trap 語句存在於較高的區塊層級。 執行 try 區塊的 finally 子句之後,即使有任何父範圍具有相符的 trap 區塊,catch 語句還是會取得控制權。 如果在 trap 區塊本身內定義 try 語句,且該 try 區塊具有相符的 catch 區塊,則 trap 語句會取得控制權。
例子:
在下列範例中,錯誤物件會被寫入,並在造成陷阱的語句之後立即繼續執行;也就是說,「完成」這個語句會被寫入到管線中。
$j = 0; $v = 10/$j; "Done"
trap { $j = 2 }
在下列範例中,錯誤物件的寫入會被抑制,執行將會緊接在引發錯誤的語句之後繼續,換句話說,「完成」將會寫入到流程中。
$j = 0; $v = 10/$j; "Done"
trap { $j = 2; continue }
在下列範例中,會隱藏錯誤物件的寫入動作,並重新拋出例外狀況。
$j = 0; $v = 10/$j; "Done"
trap { $j = 2; break }
在下列範例中,陷阱和例外狀況產生語句位於相同的範圍內。 在攔截並處理例外狀況之後,繼續執行,並將 1 寫入管線。
&{trap{}; throw '\...'; 1}
在下列範例中,陷阱和例外狀況產生語句位於不同的範圍內。 在捕捉並處理例外狀況之後,程式會繼續執行,並將2(而非1)寫入管線。
trap{} &{throw '\...'; 1}; 2
8.9 數據語句
語法:
data-statement:
data new-lines~opt~ data-name data-commands-allowed~opt~ statement-block
data-name:
simple-name
data-commands-allowed:
new-lines~opt~ -SupportedCommand data-commands-list
data-commands-list:
new-lines~opt~ data-command
data-commands-list , new-lines~opt~ data-command
data-command:
command-name-expr
描述:
數據語句會建立
腳本或函式可以有零個或多個數據區段。
資料區段 語句區塊 僅限於包含下列 PowerShell 功能:
-
-match以外的所有運算符 -
if陳述 - 下列自動變數:
$PSCulture、$PSUICulture、$true、$false和$null。 - 評論
- Pipelines
- 以分號分隔的語句(
;) - 字面值
- 呼叫 ConvertFrom-StringData Cmdlet
- 透過 SupportedCommand 參數識別的任何其他 Cmdlet
如果使用 ConvertFrom-StringData Cmdlet,可以使用任何形式的字串來表示鍵值對。 不過,可展開字串常值和 可展開此處字串常值不得包含任何變數替換或子表達式展開。
例子:
SupportedCommand 參數表示指定的 Cmdlet 或函式只會產生數據。
例如,下列數據區段包含使用者寫入的 Cmdlet ConvertTo-Xml,其會將 XML 檔案中的數據格式化:
data -SupportedCommand ConvertTo-Xml {
Format-Xml -Strings string1, string2, string3
}
請考慮下列範例,其中 data 區段包含 ConvertFrom-StringData 命令,可將字串轉換成哈希表,其值會指派給 $messages。
$messages = data {
ConvertFrom-StringData -StringData @'
Greeting = Hello
Yes = yes
No = no
'@
}
哈希表的索引鍵和值會分別使用 $messages.Greeting、$messages.Yes和 $messages.No來存取。
現在,這可以儲存為英文資源。 您可以使用下列資料區段,在不同的檔案中建立德文和西班牙文資源:
$messages = data {
ConvertFrom-StringData -StringData @"
Greeting = Guten Tag
Yes = ja
No = nein
"@
}
$messagesS = data {
ConvertFrom-StringData -StringData @"
Greeting = Buenos días
Yes = sí
No = no
"@
}
如果存在 dataname,它會將該變數命名為(不使用前置 $),用於儲存數據語句中的值。 具體來說,$name = data { ... } 相當於 data name { ... }。
8.10 函數定義
語法:
function-statement:
function new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }
filter new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }
workflow new-lines~opt~ function-name function-parameter-declaration~opt~ { script-block }
function-name:
command-argument
command-argument:
command-name-expr
function-parameter-declaration:
new-lines~opt~ ( parameter-list new-lines~opt~ )
parameter-list:
script-parameter
parameter-list new-lines~opt~ , script-parameter
script-parameter:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ variable script-parameter-default~opt~
script-block:
param-block~opt~ statement-terminators~opt~ script-block-body~opt~
param-block:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ param new-lines~opt~
( parameter-list~opt~ new-lines~opt~ )
parameter-list:
script-parameter
parameter-list new-lines~opt~ , script-parameter
script-parameter-default:
new-lines~opt~ = new-lines~opt~ expression
script-block-body:
named-block-list
statement-list
named-block-list:
named-block
named-block-list named-block
named-block:
block-name statement-block statement-terminators~opt~
block-name: one of
dynamicparam begin process end
描述:
函式定義 會指定所定義的函式、篩選或工作流程名稱及其參數的名稱,如果有的話。 它也包含執行以達到該函式用途的零個或多個語句。
每個函式都是類別 System.Management.Automation.FunctionInfo的實例。
8.10.1 篩選函式
雖然一般函式會在管線中執行一次,並透過 $input存取輸入集合,但 篩選 是一種特殊的函式,會針對輸入集合中的每個物件執行一次。
目前正在處理的物件可透過變數 $_取得。
沒有具名區塊的篩選條件(\8.10.7)相當於具有進程區塊的函式,但沒有任何開始區塊或結束區塊。
請考慮下列篩選函式定義和呼叫:
filter Get-Square2 { # make the function a filter
$_ * $_ # access current object from the collection
}
-3..3 | Get-Square2 # collection has 7 elements
6, 10, -3 | Get-Square2 # collection has 3 elements
每個過濾器都是類別 System.Management.Automation.FilterInfo(§4.5.11)的實例。
8.10.2 工作流程函式
工作流程函式就像是具有已定義之實作語意的一般函式。 工作流程函式會轉譯成一連串的 Windows Workflow Foundation 活動,並在 Windows Workflow Foundation 引擎中執行。
8.10.3 參數處理
針對名為 Get-Power的函式,請考慮下列定義:
function Get-Power ([long]$Base, [int]$Exponent) {
$result = 1
for ($i = 1; $i -le $Exponent; ++$i) {
$result *= $Base
}
return $result
}
此函式有兩個參數,$Base 和 $Exponent。 它也包含一組語句,針對非負數指數值,會計算 $Base^$Exponent^,並將結果傳回至 Get-Power的呼叫端。
當腳本、函式或篩選開始執行時,每個參數都會初始化為其對應的自變數值。 如果沒有對應的自變數,而且會提供預設值 (\8.10.4),則會使用該值;否則,會使用值 $null。 因此,每個參數都是一個新的變數,就像是在 腳本區塊的開頭通過指派來初始化一樣。
如果 script-parameter 包含類型條件約束(例如上述 [long] 和 [int]),則對應的自變數值會視需要轉換成該類型:否則,不會發生任何轉換。
當腳本、函式或篩選開始執行時,變數 $args 會在其中定義為不受限制的 1D 陣列,其中包含語匯順序中未系結名稱或位置的所有自變數。
請考慮下列函式定義和呼叫:
function F ($a, $b, $c, $d) { ... }
F -b 3 -d 5 2 4 # $a is 2, $b is 3, $c is 4, $d is 5, $args Length 0
F -a 2 -d 3 4 5 # $a is 2, $b is 4, $c is 5, $d is 3, $args Length 0
F 2 3 4 5 -c 7 -a 1 # $a is 1, $b is 2, $c is 7, $d is 3, $args Length 2
如需參數係結的詳細資訊,請參閱 <8.14
8.10.4 參數初始化器
p 參數
請考慮下列函式定義和呼叫:
function Find-Str ([string]$Str, [int]$StartPos = 0) { ... }
Find-Str "abcabc" # 2nd argument omitted, 0 used for $StartPos
Find-Str "abcabc" 2 # 2nd argument present, so it is used for $StartPos
8.10.5 [switch] 類型約束
傳遞 switch 參數時,命令中的對應參數必須受到類型參數的限制。 類型參數有兩個值:True 和 False。
請考慮下列函式定義和呼叫:
function Process ([switch]$Trace, $P1, $P2) { ... }
Process 10 20 # $Trace is False, $P1 is 10, $P2 is 20
Process 10 -Trace 20 # $Trace is True, $P1 is 10, $P2 is 20
Process 10 20 -Trace # $Trace is True, $P1 is 10, $P2 is 20
Process 10 20 -Trace:$false # $Trace is False, $P1 is 10, $P2 is 20
Process 10 20 -Trace:$true # $Trace is True, $P1 is 10, $P2 is 20
8.10.6 管線和函式
當管線中使用腳本、函式或篩選時,會將值的集合傳遞給該腳本或函式。 腳本、函式或篩選器會透過列舉值$input取得該集合的存取權(§2.3.2.2、§4.5.16),這是在進入該腳本、函式或篩選器時定義的。
請考慮下列函式定義和呼叫:
function Get-Square1 {
foreach ($i in $input) { # iterate over the collection
$i * $i
}
}
-3..3 | Get-Square1 # collection has 7 elements
6, 10, -3 | Get-Square1 # collection has 3 elements
8.10.7 具名區塊
腳本區塊內的語句 可以屬於一個大型未命名區塊,也可以分配到一個或多個命名區塊。 具名區塊允許自定義處理來自管線的集合;具名區塊可以依任何順序定義。
在傳遞第一個管線物件之前,會先執行 begin 區塊中的語句(也就是以關鍵詞 begin 標記的語句一次)。
進程區塊中的語句(亦即,以關鍵詞進程標示的語句)會針對傳遞的每個管線對象執行。 ($_ 提供從來自管線之輸入集合處理之目前物件的存取權。這表示,如果零元素的集合是透過管線傳送,則完全不會執行進程區塊。 不過,如果在管線內容外部呼叫腳本或函式,則此區塊會執行一次,且 $_ 設定為 $null,因為目前沒有集合物件。
在傳遞最後一個管線對象之後,end 區塊中的語句會執行一次,(也就是以關鍵詞 end 標記的語句)。
8.10.8 dynamicparam 區塊
到目前為止,?8.10 的子區段會處理 靜態參數,這些參數定義為原始程式碼的一部分。 您也可以透過 dynamicparam 區塊定義 動態參數,這是名稱區塊的另一種形式(§8.10.7),並以關鍵字 dynamicparam標示。 此類系統的許多機制是由實作決定的。
動態參數是 Cmdlet、函式、篩選或腳本的參數,僅適用於特定條件。 其中一個案例是 Cmdlet 的 Set-Item 參數。
在 語句區塊中,使用 if 語句來指定函式中可用參數的條件。 使用 New-Object Cmdlet 來建立實作定義型別的物件來表示參數,並指定其名稱。 此外,使用 New-Object 建立不同實作定義型別的物件,以表示 參數的實作定義屬性。
下列範例顯示名為 Name 和 Path 的標準參數,以及名為 DP1選擇性動態參數的函式。
DP1 參數位於 PSet1 參數集中,且類型為 Int32。 只有在Path參數的值包含「HKLM:」時,DP1 參數才在Sample函式中可用,指出它正用於 HKEY_LOCAL_MACHINE 登錄磁碟驅動器中。
function Sample {
param ([string]$Name, [string]$Path)
dynamicparam {
if ($Path -match "*HKLM*:") {
$dynParam1 = New-Object System.Management.Automation.RuntimeDefinedParameter("dp1", [int32], $attributeCollection)
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = 'pset1'
$attributes.Mandatory = $false
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection``1[System.Attribute]
$attributeCollection.Add($attributes)
$paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dp1", $dynParam1)
return $paramDictionary
}
}
}
用來建立物件來表示動態參數的類型 System.Management.Automation.RuntimeDefinedParameter。
用來創建表示參數屬性的物件的類型是 System.Management.Automation.ParameterAttribute。
參數的實作定義屬性包括 強制、Position和 ValueFromPipeline。
8.10.9 param 區塊
param-block 提供定義參數的替代方式。 例如,下列參數宣告集是相等的:
function FindStr1 ([string]$Str, [int]$StartPos = 0) { ... }
function FindStr2 {
param ([string]$Str, [int]$StartPos = 0) ...
}
param-block 允許 属性清單 存在於 param-block 上,而 function-parameter-declaration 則不允許这样的属性清單。
腳本可能有 參數區塊,但不能有 函數參數聲明。 函式或過濾器定義可能包含 函式參數宣告 或 參數區塊,但不能同時包含兩者。
請考慮下列範例:
param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
[string[]] $ComputerName )
一個參數 $ComputerName具有類型 string[],這是必要的,而且會從管線取得輸入。
如需 參數 屬性和更多範例的討論,請參閱 •12.3.7。
8.11 平行語句
語法:
parallel-statement:
*parallel* statement-block
平行語句包含零個或多個語句,這些語句以實作所定義的方式執行。
只有在工作流程中才允許平行語句(§8.10.2)。
8.12 序列語句
語法:
sequence-statement:
*sequence* statement-block
順序語句包含零個或多個語句,這些語句依實作定義的方式執行。
只有在工作流程中才允許序列語句(§8.10.2)。
8.13 內嵌語句
語法:
inlinescript-statement:
inlinescript statement-block
inlinescript 語句包含零個或多個語句,這些語句依照實作定義的方式執行。
在工作流程中只允許內嵌腳本語句(§8.10.2)。
8.14 參數係結
叫用腳本、函式、篩選或 Cmdlet 時,每個自變數都可以依位置系結至對應的參數,而第一個參數的位置為零。
請考慮以下關於函式 Get-Power的定義片段,以及對它的呼叫:
function Get-Power ([long]$Base, [int]$Exponent) { ... }
Get-Power 5 3 # argument 5 is bound to parameter $Base in position 0
# argument 3 is bound to parameter $Exponent in position 1
# no conversion is needed, and the result is 5 to the power 3
Get-Power 4.7 3.2 # double argument 4.7 is rounded to int 5, double argument
# 3.2 is rounded to int 3, and result is 5 to the power 3
Get-Power 5 # $Exponent has value $null, which is converted to int 0
Get-Power # both parameters have value $null, which is converted to int 0
叫用腳本、函式、篩選或 Cmdlet 時,自變數可以依名稱系結至對應的參數。 這是透過使用引數設定參數
請考慮對函式 Get-Power的下列呼叫:
Get-Power -Base 5 -Exponent 3 # -Base designates $Base, so 5 is
# bound to that, -Exponent designates
# $Exponent, so 3 is bound to that
Get-Power -Exp 3 -Bas 5 # $Base takes on 5 and $Exponent takes on 3
Get-Power -E 3 -B 5 # $Base takes on 5 and $Exponent takes on 3
另一方面,呼叫下列函式
function Get-Hypot ([double]$Side1, [double]$Side2) {
return [Math]::Sqrt($Side1 * $Side1 + $Side2 * $Side2)
}
必須使用參數 -Side1 和 -Side2,因為沒有唯一指定參數的前置詞。
相同的參數名稱不能多次使用,無論是否具備不同的引數值。
參數可以有屬性 (~12)。 如需了解個別屬性的相關資訊,請參閱 節中的 §12.3各節。 如需參數集的相關信息,請參閱 §12.3.7。
腳本、函式、篩選或 Cmdlet 可以透過調用命令行、管線或兩者接收自變數。 以下是解析參數係結的步驟:
- 系結所有具名參數,然後
- 綁定位置參數,接著
- 以值綁定自管線(§12.3.7),然後進行完全匹配,
- 從管線依值系結 (§12.3.7)並進行轉換,然後
- 依名稱從管線系結(§12.3.7)並完全匹配,然後
- 依名稱從管線繫結(§12.3.7)並進行轉換
這些步驟中有數個牽涉到轉換,如 6 中所述。不過, 系結中使用的轉換集與語言轉換中使用的轉換不同。 具體說來
- 雖然值
$null可以轉換成 bool,但$null無法繫結至bool。 - 當值
$null傳遞至 Cmdlet 的 switch 參數時,它會被視為傳遞$true。 不過,當傳遞至函式的 switch 參數時,它會如同傳遞了$false一樣被處理。 - bool 或 switch 類型的參數只能係結至數值或 bool 自變數。
- 如果參數類型不是集合,但自變數是某種集合,除非參數類型為物件或 PsObject,否則不會嘗試轉換。 (此限制的主要點是不允許將集合轉換成字串參數。否則,會嘗試一般轉換。
如果參數類型是 IList 或 ICollection<T>,則只會嘗試透過建構函式、op_Implicit和op_Explicit轉換。 如果沒有這類轉換存在,則會對「collection」類型的參數使用特殊轉換,其中包括 IList、ICollection<T>和陣列。
如果可能的話,位置參數偏好系結而不進行類型轉換。 例如
function Test {
[CmdletBinding(DefaultParameterSetName = "SetB")]
param([Parameter(Position = 0, ParameterSetName = "SetA")]
[decimal]$Dec,
[Parameter(Position = 0, ParameterSetName = "SetB")]
[int]$In
)
$PSCmdlet.ParameterSetName
}
Test 42d # outputs "SetA"
Test 42 # outputs "SetB"