8. ステートメント

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

説明:

"ステートメント" では、実行する何らかのアクションを指定します。 この句の中で特に記載のない限り、ステートメントは字句の順序で実行されます。

statement-block を使用すると、一連のステートメントを 1 つの構文単位にグループ化できます。

8.1.1 ラベル付きステートメント

構文:

labeled-statement:
    switch-statement
    foreach-statement
    for-statement
    while-statement
    do-statement

説明:

反復ステートメント (§8.4) または switch ステートメント (§8.6) の場合、必要に応じて、1 つのステートメント ラベル ("ラベル") をすぐ前に付けることができます。 ステートメント ラベルは、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) { }

ループは 5 回反復されますが、パイプラインには何も書き込まれません。 ステートメントの値は $null です。

$v = for ($i = 1; $i -le 5; ++$i) { $i }

ループは 5 回反復され、そのたびにパイプラインに int 値の $i が書き込まれます。 ステートメントの値は、長さが 5 の object[] です。

$v = for ($i = 1; $i -le 5; ) { ++$i }

ループは 5 回反復されますが、パイプラインには何も書き込まれません。 ステートメントの値は $null です。

$v = for ($i = 1; $i -le 5; ) { (++$i) }

ループは 5 回反復されますが、各値がパイプラインに書き込まれます。 ステートメントの値は、長さが 5 の object[] です。

$i = 1; $v = while ($i++ -lt 2) { $i }

ループの反復は 1 回です。 ステートメントの値は、値が 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 を参照してください。

pipeline での最初のコマンドは、式またはコマンド呼び出しです。 通常、コマンドの呼び出しは "コマンド名" で始まり、これは一般に ID そのものです。 "コマンド要素" は、コマンドの引数リストを表します。 パイプラインは、改行またはエスケープされていないセミコロンによって終了します。

コマンドの呼び出しは、コマンドの名前と、それに続く 0 個以上の引数で構成されます。 引数には次のようなルールが適用されます。

  • 式ではないが、エスケープされていない空白を含まない任意のテキストが含まれる引数は、二重引用符で囲まれているかのように扱われます。 大文字と小文字の区別は保持されます。

  • 変数の置換とサブ式の展開 (§2.3.5.2) は、expandable-string-literalexpandable-here-string-literal の内部で行われます。

  • テキストを引用符で囲むと、先頭、末尾、途中の空白を引数の値に含めることができます。 [: 空白を含む引数が引用符で囲まれている場合、1 つの引数が複数の引数に変換されることはありません。 注の終わり]

  • 引数をかっこで囲むと、元の式のテキストではなく、式を評価した結果が渡されます。

  • スイッチ パラメーター (§2.3.4) のように見えても、それを意図したものではない引数を渡すには、その引数を引用符で囲みます。

  • [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 の制御式は、ブール型であるか、その型に暗黙的に変換できる必要があります。 else-clause は省略可能です。 0 個以上の elseif-clause を使用できます。

最上位の pipeline が True の場合は、その statement-block が実行されて、ステートメントの実行が終了します。 そうでない場合で、elseif-clause が存在し、その pipeline が True の場合は、その statement-block が実行されて、ステートメントの実行が終了します。 それ以外の場合で、else-clause が存在する場合は、その statement-block が実行されます。

例 :

$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 は、ブール型であるか、その型に暗黙的に変換できる必要があります。 statement-block で構成されるループ本体は、制御式が 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 は、ブール型であるか、その型に暗黙的に変換できる必要があります。 while 形式では、statement-block で構成されるループ本体は、制御式が 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-condition は、ブール型であるか、その型に暗黙的に変換できる必要があります。 statement-block で構成されるループ本体は、制御式が True である間、繰り返し実行されます。 制御式は、ループ本体の各実行の前に評価されます。

for-initializer は、制御式の最初の評価の前に評価されます。 式 for-initializer は、その副作用のみが評価されます。生成された値は破棄され、パイプラインには書き込まれません。

for-iterator は、ループ本体の各実行の後で評価されます。 式 for-iterator は、その副作用のみが評価されます。生成された値は破棄され、パイプラインには書き込まれません。

for-condition を省略した場合、制御式は True になります。

例 :

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

説明:

statement-block で構成されるループ本体は、pipeline によって指定されたコレクション内の変数 variable によって指定される各要素に対して実行されます。 variable のスコープは、foreach ステートメントに限定されません。 そのため、ループ本体の実行が終了した後も、最終的な値が保持されます。 pipeline でコレクションではなくスカラー (値 $null を除く) が指定されている場合、そのスカラーは要素が 1 つのコレクションとして扱われます。 pipeline で値 $null が指定されていると、pipeline は要素が 0 のコレクションとして扱われます。

foreach-parameter-parallel が指定されている場合、動作は実装によって定義されます。

foreach-parameter‑parallel は、ワークフローでのみ許可されます (§8.10.2)。

すべての foreach ステートメントにはそれ自体の列挙子 $foreach があり (§2.3.2.2§4.5.16)、それはそのループが実行されている間だけ存在します。

pipeline によって生成されるオブジェクトは、statement-block の実行が開始される前に収集されます。 ただし、ForEach-Object コマンドレットでは、オブジェクトが生成されるたびに statement-block が実行されます。

例 :

$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 ステートメント

説明:

label-expression のある break ステートメントは、"ラベル付き break ステートメント" と呼ばれます。 label-expression のない break ステートメントは、"ラベルなし break ステートメント" と呼ばれます。

trap ステートメントの外側では、反復ステートメント (§8.4) 内でラベルなし break ステートメントを直接実行すると、外側の最小の反復ステートメントの実行が終了します。 switch ステートメント (§8.6) 内でラベルなし break ステートメントを直接使用すると、現在の switch の switch-condition に対するパターン マッチングが終了します。 trap ステートメント内からの break の使用の詳細については、§8.8 を参照してください。

必要に応じて、反復ステートメントまたは switch ステートメントのすぐ前で、1 つのステートメント ラベル (§8.1.1) を指定できます。このようなステートメント ラベルは、ラベル付き break ステートメントのターゲットとして使用できます。この場合、そのステートメントにより、外側のターゲットの反復ステートメントの実行が終了します。

どのローカル スコープでも、ラベル付き 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 ステートメント

説明:

label-expression のある continue ステートメントは、"ラベル付き continue ステートメント" と呼ばれます。 label-expression のない continue ステートメントは、"ラベルなし continue ステートメント" と呼ばれます。

trap ステートメント内からの continue の使用については、§8.8 を参照してください。

ループ内でラベルなし continue ステートメントを使用すると、現在のループの実行が終了され、外側の最も小さい反復ステートメント (8.4 を参照) の右中かっこに制御が移ります。 switch 内でラベルなし continue ステートメントを使用すると、現在の switch 反復の実行が終了され、外側の最も小さい switchswitch-condition (§8.6) に制御が移ります。

必要に応じて、反復ステートメントまたは switch ステートメント (§8.6) のすぐ前に、1 つのステートメント ラベル (§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 を参照してください。)

pipeline が省略され、throw ステートメントが catch-clause 内にない場合、動作は実装によって定義されます。 pipeline が存在し、throw ステートメントが catch-clause 内にある場合、その catch-clause によってキャッチされた例外は、catch-clause 句に関連付けられたすべての finally-clause が実行された後で再スローされます。

pipeline が存在する場合、スローされる例外の型は実装によって定義されます。

例外がスローされると、その例外を処理できる外側の try ステートメントの最初の catch 句に制御が移ります。 最初に例外がスローされる場所は、"スロー ポイント" と呼ばれます。 例外がスローされると、例外と一致する catch 句が見つかるまで、一致するものがないことがわかるまで、§8.7 で説明されている手順が繰り返されます。

例 :

throw
throw 100
throw "No such record in file"

pipeline が省略され、throw ステートメントが catch-clause 内からではない場合は、テキスト "ScriptHalted" がパイプラインに書き込まれ、発生する例外の型は System.Management.Automation.RuntimeException になります。

pipeline が存在する場合、発生した例外は 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.Int32 で値が 10 と 20 の 2 つの要素が含まれる制限なし配列 System.Object[]) が含まれます。

8.5.4 return ステートメント

説明:

return ステートメントでは、pipeline がある場合はそれによって指定された値がパイプラインに書き込まれ、関数またはスクリプトの呼び出し元に制御が戻されます。 関数またはスクリプトでは、0 個以上の return ステートメントを使用できます。

実行が関数の終了中かっこに到達した場合は、pipeline のない暗黙的な return が想定されます。

return ステートメントは、他の言語のように、プログラマが自己表現できる "糖衣構文" です。ただし、関数またはスクリプトから返される値は、実際には、その関数またはスクリプトによってパイプラインに書き込まれたすべての値に、pipeline によって指定されている値を加えたものです。 スカラー値のみがパイプラインに書き込まれる場合は、その型が戻り値の型になります。それ以外の場合、戻り値の型は、パイプラインに書き込まれたすべての値が含まれる制限なしの 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 を呼び出すと、3 つの要素が含まれる制限なしの 1 次元配列が返されます。

8.5.5 exit ステートメント

説明:

exit ステートメントを呼び出すと、現在のスクリプトが終了し、制御と "終了コード" がホスト環境または呼び出し元スクリプトに返されます。 pipeline が指定されている場合は、必要に応じて、指定された値が int に変換されます。 そのような変換が存在しない場合、または pipeline が省略された場合は、int 値 0 が返されます。

例 :

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-condition で 1 つの値を指定すると、制御は 1 つ以上の一致するパターン ステートメント ブロックに渡されます。 一致するパターンがない場合は、既定のアクションを実行できます。

スイッチには、1 つ以上の switch-clause が含まれ、それぞれパターン ("既定以外の switch 句") またはキーワード default ("既定の switch 句") で始まっている必要があります。 スイッチには、0 または 1 個の default switch 句と、0 個以上の既定以外の switch 句が含まれる必要があります。 switch 句は、任意の順序で記述できます。

複数のパターンが同じ値を持っていてもかまいません。 パターンはリテラルである必要はなく、スイッチの複数のパターンが異なる型であってもかまいません。

switch-condition の値がパターンの値と一致する場合、そのパターンの statement-block が実行されます。 複数のパターン値が switch-condition の値と一致する場合、それらの statement-block ブロックのいずれかに break ステートメント (§8.5.1) が含まれていない限り、一致する各パターンの statement-block が構文順に実行されます。

switch-condition の値がどのパターン値とも一致しない場合は、default switch 句が存在すれば、その statement-block が実行されます。そうでなければ、その switch-condition のパターン マッチングが終了されます。

スイッチは入れ子にすることができ、各スイッチに固有の switch 句のセットがあります。 このような場合、switch 句は、現在スコープ内にある最も内側のスイッチに属します。

statement-block に入るときに、制御がその statement-block に移動する原因になった switch-condition の値が、$_ に自動的に割り当てられます。 その statement-blockswitch-clause-condition でも、$_ を使用できます。

文字列以外の一致は、等価性 (§7.8.1) をテストすることによって行われます。

マッチングに文字列が含まれる場合、既定では、比較で大文字と小文字は区別されません。 switch-parameter-casesensitive が存在すると、比較で大文字と小文字が区別されます。

パターンにはワイルドカード文字 (§3.15) を含めることができます。その場合、ワイルドカード文字列の比較は、switch-parameter -wildcard が存在する場合にのみ実行されます。 規定では、比較で大文字と小文字は区別されません。

パターンには正規表現 (§3.16) を含めることができます。その場合、正規表現の文字列の比較は、switch-parameter -regex が存在する場合にのみ実行されます。 規定では、比較で大文字と小文字は区別されません。 -regex が存在し、パターンが一致する場合、$matches は、そのパターンの switch-clause statement-block で定義されます。

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 の場合は、そのブロックが評価され、必要に応じて結果がブール値に変換されます。 結果が値 $true の場合は、対応する statement-block が実行されます。それ以外の場合は実行されません。

switch-condition で複数の値を指定した場合、スイッチは、上で 1 つの値を指定する switch-condition について説明した規則を使用して、構文順に各値に適用されます。 すべての switch ステートメントにはそれ自体の列挙子 $switch があり (§2.3.2.2§4.5.16)、それはそのスイッチが実行されている間だけ存在します。

switch ステートメントはラベルを持つことができ、ラベル付きとラベルなしの break (§8.5.1) および continue (§8.5.2) ステートメントを含むことができます。

switch-condition-file switch-filename である場合は、式の値が反復処理される代わりに、switch-filename で指定されているファイル内の値がスイッチによって反復処理されます。ファイルは、値を構成する行ごとに 1 行ずつ読み取られます。 行終端記号は値に含まれません。

例 :

$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 ブロック" は、try ステートメントに関連付けられた statement-block です。 "catch ブロック" は、catch-clause に関連付けられた statement-block です。 "finally ブロック" は、finally-clause に関連付けられた statement-block です。

catch-type-list のない catch-clause は、"一般的な catch 句" と呼ばれます。

catch-clause は "例外ハンドラー" であり、catch-type-list に発生した例外の型が含まれている catch-clause は、"一致する catch 句" です。 一般的な catch 句は、例外のすべての型と一致します。

catch-clausefinally-clause は省略可能ですが、それらのうちの少なくとも 1 つが存在する必要があります。

スローされた例外の処理は、例外と一致する catch 句が見つかるまで、次の手順を繰り返し評価する処理で構成されます。

  • 現在のスコープで、スロー ポイントを囲む各 try ステートメントが調べられます。 各 try ステートメント S について、最も内側の try ステートメントから始めて、最も外側の try ステートメントで終わるまで、次の手順が評価されます。

    • Stry ブロックでスロー ポイントが囲まれていて、S に 1 つ以上の catch 句がある場合、catch 句が構文の順序で調べられ、例外に適したハンドラーが検索されます。 例外の型または例外の型の基本データ型が指定されている最初の catch 句が、一致と見なされます。 一般的な catch 句は、すべての例外型に対して一致と見なされます。 一致する catch 句がある場合は、その catch 句のブロックに制御を移すことによって、例外処理が完了します。 一致する catch 句内の変数 $_ には、現在の例外の説明が含まれています。

    • それ以外の場合で、try ブロックまたは Scatch ブロックでスロー ポイントが囲まれていて、Sfinally ブロックがある場合は、finally ブロックに 制御が移されます。 finally ブロックによって別の例外がスローされた場合、現在の例外の処理は終了されます。 それ以外の場合、制御が finally ブロックの末尾に達すると、現在の例外の処理が継続されます。

  • 現在のスコープ内で例外ハンドラーが見つからなかった場合、現在のスコープが呼び出されたステートメントに対応するスロー ポイントを囲むスコープに対して、上記の手順が繰り返されます。

  • 例外処理によってすべてのスコープが終了された場合は、その例外に対してハンドラーが存在しないことを示し、動作は指定されません。

try ブロックで到達できない catch 句がないようにするため、catch 句では、同じ try ブロック内の前の catch 句で指定された型と等しい例外型、またはその型から派生した例外型を、指定しなくてもかまいません。

finally ブロックのステートメントは、制御が try ステートメントを離れるときに常に実行されます。 これは、制御の移動が発生した原因が、通常の実行の結果、breakcontinue、または return ステートメントが実行された結果、または try ステートメントから例外がスローされた結果のいずれであっても、当てはまります。

finally ブロックの実行中に例外がスローされた場合、例外は 1 つ外側にある 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 ブロックに型固有の catch-clause がある場合、例外の InnerException プロパティが調べられ、上の System.IndexOutOfRangeException 型でのように一致の検出が試みられます。

8.8 trap ステートメント

構文:

trap-statement:
    *trap* new-lines~opt~ type-literal~opt~ new-lines~opt~ statement-block

説明:

type-literal がある場合とない場合の trap ステートメントは、それぞれ、catch-type-list がある場合とない場合の catch ブロック (§8.7) に似ています。ただし、trap ステートメントでは一度に 1 つの型のみをトラップできる点が異なります。

同じ statement-block で複数の trap ステートメントを定義することができ、定義の順序は関係ありません。 同じスコープ内で同じ type-literal を持つ 2 つの trap ステートメントが定義されている場合は、構文的に最初のものが一致する型の例外を処理するために使用されます。

catch ブロックとは異なり、trap ステートメントは例外の型と厳密に一致します。派生型の一致は実行されません。

例外が発生した場合、現在のスコープに一致する trap ステートメントが存在しない場合は、外側のスコープで一致する trap ステートメントが検索されます。これには、呼び出し元のスクリプト、関数、またはフィルターの検索、さらにその呼び出し元での検索などが含まれる場合があります。 検索によってすべてのスコープが終了された場合は、その例外に対してハンドラーが存在しないことを示し、動作は指定されません。

trap ステートメントの statement-body は、対応する例外を処理するためにのみ実行されます。それ以外の場合は実行されません。

trapstatement-body が正常に終了した場合、既定では、エラー オブジェクトがエラー ストリームに書き込まれ、例外は処理済みと見なされて、例外を可視化した trap ステートメントが含まれるスコープ内のステートメントの直後のステートメントの実行が続けられます。 例外の原因は、trap ステートメントが含まれるコマンドによって呼び出されたコマンド内にある可能性があります。

trapstatement-body で実行された最後のステートメントが continue (§8.5.2) の場合、エラー ストリームへのエラー オブジェクトの書き込みは抑制され、例外を可視化した trap ステートメントが含まれるスコープ内のステートメントの直後のステートメントの実行が続けられます。 trapstatement-body で実行された最後のステートメントが break (§8.5.1) の場合、エラー ストリームへのエラー オブジェクトの書き込みは抑制され、例外が再スローされます。

trap ステートメント内の変数 $_ には、現在のエラーの説明が含まれます。

try ブロック内から生成された例外に一致する catch ブロックがなく、しかし一致する trap ステートメントが上位のブロック レベルに存在する場合について考えます。 try ブロックの finally 句が実行された後は、親スコープに一致する catch ブロックがある場合でも、trap ステートメントに制御が移ります。 trap ステートメントが try ブロック自体の内部で定義されていて、その try ブロックに一致する catch ブロックがある場合、trap ステートメントに制御が移ります。

例 :

次の例では、エラー オブジェクトが書き込まれて、トラップの原因であるステートメントの直後のステートメントから実行が続けられます。つまり、"Done" がパイプラインに書き込まれます。

$j = 0; $v = 10/$j; "Done"
trap { $j = 2 }

次の例では、エラー オブジェクトの書き込みは抑制され、トラップの原因であるステートメントの直後のステートメントから実行が続けられます。つまり、"Done" がパイプラインに書き込まれます。

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; continue }

次の例では、エラー オブジェクトの書き込みは抑制され、例外が再スローされます。

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; break }

次の例では、trap ステートメントと例外を生成するステートメントが同じスコープ内にあります。 例外がキャッチされて処理された後、パイプラインへの 1 の書き込みで実行が再開されます。

&{trap{}; throw '\...'; 1}

次の例では、trap ステートメントと例外を生成するステートメントが異なるスコープ内にあります。 例外がキャッチされて処理された後、パイプラインへの (1 ではなく) 2 の書き込みで実行が再開されます。

trap{} &{throw '\...'; 1}; 2

8.9 data ステートメント

構文:

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

説明:

data ステートメントを使用すると、"データ セクション" が作成されます。そのセクションのデータはコードとは別に保持されます。 この分離により、エラー メッセージやヘルプ文字列など、テキスト用の個別の文字列リソース ファイルなどの機能がサポートされます。 また、異なる言語に翻訳される文字列の分離、検索、処理が容易になり、国際化もサポートされます。

スクリプトまたは関数では、0 個以上のデータ セクションを使用できます。

データ セクションの statement-block に格納できるのは、次の PowerShell 機能のみに制限されます。

  • -match を除くすべての演算子
  • if ステートメント
  • 次の自動変数: $PsCulture$PsUICulture$true$false$null
  • コメント
  • Pipelines
  • セミコロン (;) で区切られたステートメント
  • リテラル
  • ConvertFrom-StringData コマンドレットの呼び出し
  • supportedcommand パラメーターを使用して識別されるその他のコマンドレット

ConvertFrom-StringData コマンドレットを使用する場合は、任意の形式の文字列リテラルを使用してキーと値のペアを表すことができます。 ただし、expandable-string-literalexpandable-here-string-literal に、変数の置換またはサブ式の展開を含めることはできません。

例 :

SupportedCommand パラメーターは、指定されたコマンドレットまたは関数のみがデータを生成することを示します。 たとえば、次のデータ セクションに含まれるユーザー作成のコマンドレット ConvertTo-XML では、XML ファイル内のデータが書式設定されます。

data -supportedCommand ConvertTo-XML {
    Format-XML -strings string1, string2, string3
}

次に考える例のデータ セクションには、文字列をハッシュ テーブルに変換する 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 が存在する場合、data ステートメントの値の格納先である変数の名前が、それによって設定されます (先頭の $ を除いて)。 具体的には、$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

説明:

"関数定義" では、定義されている関数、フィルター、またはワークフローの名前と、ある場合はパラメーターの名前を指定します。 また、その関数の目的を達成するために実行される 0 個以上のステートメントも含まれます。

各関数は、System.Management.Automation.FunctionInfo クラスのインスタンスです。

8.10.1 フィルター関数

通常の関数はパイプラインで 1 回実行され、$input を介して入力コレクションにアクセスしますが、"フィルター" は、入力コレクション内のオブジェクトごとに 1 回実行される特殊な種類の関数です。 現在処理されているオブジェクトは、$_ 変数で使用できます。

名前付きブロック (§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 という 2 つのパラメーターがあります。 また、負でない指数値について、$base^$exponent^ を計算して結果を Get-Power の呼び出し元に返すステートメントのセットも含まれます。

スクリプト、関数、またはフィルターの実行が開始されると、各パラメーターは対応する引数の値に初期化されます。 対応する引数がなく、既定値 (§8.10.4) が指定されている場合は、その値が使用されます。それ以外の場合は、値 $null が使用されます。 このように、各パラメーターは、script-block の開始時に代入によって初期化されたような、新しい変数です。

script-parameter に型制約 (上の [long][int] など) が含まれている場合、対応する引数の値は必要に応じてその型に変換されます。それ以外の場合、変換は行われません。

スクリプト、関数、またはフィルターの実行が開始されると、その内部に制限なしの 1 次元配列として $args 変数が定義されます。それには、名前または位置によってバインドされていないすべての引数が、構文順に格納されます。

次の関数定義と呼び出しを考えてみます。

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 の宣言には、初期化子を含めることができます。その場合、p が呼び出し内のどの引数にもバインドされていないと、その初期化子の値を使用して p が初期化されます。

次の関数定義と呼び出しを考えてみます。

function Find-Str ([string]$str, [int]$start_pos = 0) { ... }

Find-Str "abcabc" # 2nd argument omitted, 0 used for $start_pos
Find-Str "abcabc" 2 # 2nd argument present, so it is used for $start_pos

8.10.5 [switch] 型制約

スイッチ パラメーターを渡すときは、コマンド内の対応するパラメーターを、型スイッチによって制約する必要があります。 型スイッチには、True と False の 2 つの値があります。

次の関数定義と呼び出しを考えてみます。

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 名前付きブロック

script-block 内のステートメントは、1 つの大きな名前なしブロックに入れるか、1 つ以上の名前付きブロックに分散させることができます。 名前付きブロックを使用すると、パイプラインからのコレクションをカスタム処理できます。名前付きブロックは任意の順序で定義できます。

"begin ブロック" (つまり、キーワード begin でマークされたもの) 内のステートメントは、最初のパイプライン オブジェクトが提供される前に 1 回実行されます。

"process ブロック" (つまり、キーワード process でマークされたもの) 内のステートメントは、提供されたパイプライン オブジェクトごとに実行されます。 ($_ を使用して、パイプラインから渡された入力コレクション内で現在処理されているオブジェクトにアクセスできます)。つまり、要素が 0 個のコレクションがパイプラインから送られてきた場合、プロセス ブロックはまったく実行されません。 ただし、スクリプトまたは関数がパイプライン コンテキストの外部で呼び出された場合は、このブロックが 1 回だけ実行され、現在のコレクション オブジェクトがないので、$_$null に設定されます。

"end ブロック" (つまり、キーワード end でマークされたもの) 内のステートメントは、最後のパイプライン オブジェクトが提供された後に 1 回実行されます。

8.10.8 dynamicParam ブロック

§8.10 のここまでのサブセクションでは、ソース コードの一部として定義される "静的パラメーター" を扱っています。 名前付きブロック (§8.10.7) のもう 1 つの形式であり、キーワード dynamicParam でマークされる "dynamicParam ブロック" を使用して、"動的パラメーター" を定義することもできます。 この機構の多くは実装によって定義されます。

動的パラメーターは、特定の条件下でのみ使用できる、コマンドレット、関数、フィルター、またはスクリプトのパラメーターです。 そのようなケースの 1 つは、Set-Item コマンドレットの Encoding パラメーターです。

statement-block で、if ステートメントを使用して、関数でパラメーターを使用できる条件を指定します。 New-Object コマンドレットを使用して、パラメーターを表す実装定義型のオブジェクトを作成し、その名前を指定します。 また、New-Object を使用して、パラメーターの実装定義属性を表すための、別の実装定義型のオブジェクトを作成します。

次の例では、Name と Path という名前の標準パラメーターと、DP1 という名前の省略可能な動的パラメーター持つ関数を示します。 DP1 パラメーターは PSet1 パラメーター セット内にあり、型は Int32 です。 DP1 パラメーターは、それが HKEY_LOCAL_MACHINE レジストリ ドライブで使用されていることを示す "HKLM:" が Path パラメーターの値に含まれている場合にのみ、Sample 関数で使用できます。

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 です。

パラメーターの実装定義の属性には、MandatoryPositionValueFromPipeline が含まれます。

8.10.9 param ブロック

param-block により、パラメーターを宣言する別の方法が提供されます。 たとえば、次のパラメーター宣言のセットは同じものです。

function FindStr1 ([string]$str, [int]$start_pos = 0) { ... }
function FindStr2 {
    param ([string]$str, [int]$start_pos = 0) ...
}

param-block を使用すると、param-block では attribute-list が許可されますが、function-parameter-declaration は許可されません。

スクリプトでは param-block は使用できますが、function-parameter-declaration は使用できません。 関数またはフィルターの定義では、function-parameter-declaration または param-block のどちらかは使用できますが、両方とも使用することはできません。

次の例を確認してください。

param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)]
        [string[]] $ComputerName )

パラメーター $ComputerNamestring[] 型で、必須であり、パイプラインから入力を受け取ります。

Parameter 属性の詳細と他の例については、§12.3.7 を参照してください。

8.11 parallel ステートメント

構文:

parallel-statement:
    *parallel* statement-block

parallel ステートメントには、実装で定義された方法で実行される 0 個以上のステートメントが含まれます。

parallel ステートメントは、ワークフロー (§8.10.2) でのみ使用できます。

8.12 sequence ステートメント

構文:

sequence-statement:
    *sequence* statement-block

sequence ステートメントには、実装で定義された方法で実行される 0 個以上のステートメントが含まれます。

sequence ステートメントは、ワークフロー (§8.10.2) でのみ使用できます。

8.13 inlinescript ステートメント

構文:

inlinescript-statement:
    inlinescript statement-block

inlinescript ステートメントには、実装で定義された方法で実行される 0 個以上のステートメントが含まれます。

inlinescript ステートメントは、ワークフロー (§8.10.2) でのみ使用できます。

8.14 パラメーターのバインド

スクリプト、関数、フィルター、またはコマンドレットが呼び出されるとき、各引数を位置で対応するパラメーターにバインドできます。最初のパラメーターの位置は 0 です。

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

スクリプト、関数、フィルター、またはコマンドレットが呼び出されるとき、引数を名前で対応するパラメーターにバインドできます。 これを行うには、"引数付きパラメーター" を使用します。これは、パラメーターの名前の先頭にダッシュ (-) を付けた引数で、それに続けてその引数に関連付けられた値を指定します。 使用するパラメーター名では、大文字と小文字の区別がない任意のスペルを使用でき、対応するパラメーターを一意に指定する任意のプレフィックスを使用できます。 パラメーター名を選択するときは、共通パラメーターの名前を使用しないようにしてください。

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 を参照してください。

スクリプト、関数、フィルター、またはコマンドレットは、呼び出しコマンド ライン、パイプライン、またはその両方から、引数を受け取ることができます。 パラメーターのバインドは次の順序で解決されます。

  1. すべての名前付きパラメーターがバインドされます
  2. 位置指定パラメーターがバインドされます
  3. 完全一致の値 (§12.3.7) でパイプラインからバインドされます
  4. 変換された値 (§12.3.7) でパイプラインからバインドされます
  5. 完全一致の名前 (§12.3.7) でパイプラインからバインドされます
  6. 変換された名前 (§12.3.7) でパイプラインからバインドされます

これらの手順の一部には、§6 で説明されている変換が含まれます。 ただし、バインドで使用される変換のセットは、言語変換で使用されるものとまったく同じではありません。 具体的には次のとおりです。

  • $null を bool にキャストすることはできますが、$nullbool にバインドすることはできません。
  • $null がコマンドレットのスイッチ パラメーターに渡されるときは、$true が渡された場合と同様に処理されます。 一方、関数のスイッチ パラメーターに渡されるときは、$false が渡された場合と同様に処理されます。
  • bool 型またはスイッチのパラメーターは、数値または bool の引数にのみバインドできます。
  • パラメーターの型はコレクションではないが、引数は何らかのコレクションである場合は、パラメーターの型がオブジェクトまたは PsObject でない限り、変換は試みられません。 (この制限の主なポイントは、コレクションが文字列パラメーターに変換されるのを禁止することです)。それ以外の場合は、通常の変換が試みられます。

パラメーターの型が IList または ICollection<T> の場合は、コンストラクター、op_Implicit、op_Explicit によるそれらの変換のみが試みられます。 そのような変換が存在しない場合は、"コレクション" 型のパラメーターに対する特別な変換が使用されます。これには、IListICollection<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"