PowerShellにおけるパラメータバインディングについてのまとめ

あまりPowerShellのパラメータバインディングについての記事を見かけないので頭の整理も兼ねてまとめました。
この続編として、PowerShellのDelay-Bindingについてもまとめる予定です。
※最後にパラメータバインディングのプロセスを辿れるTrace-Commandについても触れました。

###パラメータバインディングとは
コマンド実行時にパラメータと引数を結びつける（バインドする）こと。
必須パラメータは揃っているか、引数の型は適切かなどを判断する。

###パイプラインにおけるパラメータバインディング
パイプを通じて渡されたオブジェクト（パイプラインオブジェクト）は、一定のルールで現在のコマンドのパラメータにバインドされる。

###パラメータバインディングの基本ルール
(1)
パイプラインからの入力を許可するがTrue。これはヘルプで確認可能。Trueには以 下の2種類がある。

   - ByValue: パイプラインオブジェクトをバインド
   - ByPropertyName: パイプラインオブジェクトのプロパティ名とパラメータ名が一致した場合のプロパティの値をバインド

いずれの場合も、引数となる値の型がパラメータが要求する型が同じかその型に変換可能な場合のみバインドされる

(2)
そのパラメータがコマンド内で使用されていない。

###パイプラインオブジェクトのパラメータバインディング
それでは次の場合、Add-Contentはどのようにパイプラインオブジェクトをバインディングするのでしょうか。

```
[Regex]::Match("03/01/2019","\d{4}")|Add-Content file.txt
```

それを確認する前に、まずRegex.Matchメソッドの戻り値（パイプラインの入力オブジェクト）とAdd-Contentのパラメータについて調べます。

###入力オブジェクトとパラメータ
<d1>
<dt>Add-Content</dt>
<dd>-Pathでアイテムを指定、-Valueで文字列などを指定</dd>
<dd>-Path 
型: String[]
位置: 0
パイプラインオブジェクトの受け入れ: True(ByPropertyName)</dd>
<dd>-Value
型: Object[]
位置: 1
パイプラインオブジェクトの受け入れ: True(ByPropertyName,ByValue)</dd>
<dt>[Regex]::Match(String,String<pattern>)</dt>
<dd>入力文字列から正規表現に最初にマッチする部分を検索する</dd>
<dd>戻り値: System.Text.RegularExpressions.Group.Match</dd>

<dt>[Regex]::Match(String,String<pattern>).Value</dt>
<dd>正規表現にマッチした値を取得する</dd>
<dd>戻り値: System.String</dd>
</d1>

###パラメータバインディングのプロセス

以上を踏まえて、改めて次のコマンドのパラメータバインディングがどのようになされて確認します。

```
[Regex]::Match("03/01/2019","\d{4}")|Add-Content file.txt
```

この場合のAdd-Contentのパラメータバインディング
1. パラメータがあるかチェック
→なし
2. パラメータがない引数について、位置指定のパラメータの条件に合うかチェック
→位置0のパラメータは-Path、file.txtは型の条件を満たしているのでOK
3. 必須パラメータに引数がバインドされているかチェック
→-Valueに空きあり
4. パイプラインオブジェクトの型と-Valueの要求する型が一致/型変換が可能かチェック
→System.Text.RegularExpressions.Group.MatchとObject[]なので不可
5. パイプラインオブジェクトのプロパティ名とパラメータ名が一致するかチェック
→パイプラインオブジェクト内にValueプロパティあり
6. パラメータ値の型と-Valueの型と-Valueの要求する型が一致/型変換が可能かチェック
→System.StringとObject[]なので可
7. パイプラインオブジェクトがByPropertyValueで入力が可能な他のプロパティとバインドできるかチェック
→不可
8. 必須パラメータがバインドできているかチェック
→OK

###おわりに
少し雑でしたが、以上になります。

###追記（Trace-Commandについて）
パラメータバインディングの詳細についてはTrace-Commandで知ることができます。
上の例の場合、次のコマンドを実行すると詳細を確認できます。

```
Trace-Command -PSHost -Name ParameterBinding `
-Expression {[Regex]::Match("03/01/2019","\d{4}")|
    Add-Content file.txt}
```
結果を行単位で見ていくと次のようになります。

```
BIND NAMED cmd line args [Add-Content]
```
Add-Contentのパラメータと引数がバインド
→ないので無視

```
BIND POSITIONAL cmd line args [Add-Content]
     BIND arg [file.txt] to parameter [Path]
```
Add-Contentにパラメータの記載がない場合、位置によって引数がバインド
→file.txtを-Pathにバインド

```
Binding collection parameter Path: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
Creating array with element type [System.String] and 1 elements
        Argument type String is not IList, treating this as scalar
        Adding scalar element of type String to array position 0
        BIND arg [System.String[]] to param [Path] SUCCESSFUL
BIND arg [System.String[]] to param [Path] SUCCESSFUL
```

-Pathの引数の型と要求する型を確認
→一致しないが、引数をスカラーとして扱うことで変換が可能と判断してバインド

```
###中略###
MANDATORY PARAMETER CHECK on cmdlet [Add-Content]
```

Add-Contentの必須パラメータを確認
→-Valueは必須だが引数がないので先に進む

```
BIND PIPELINE object to parameters: [Add-Content]
     PIPELINE object TYPE = [System.Text.RegularExpressions.Match]
     RESTORING pipeline parameter's original values
```

パイプラインオブジェクトをAdd-Contentの引数にバインドし、オブジェクトの型を確認。そのうえで元の値に復元

```
Parameter [Value] PIPELINE INPUT ValueFromPipeline NO COERCION
```
パイプラインオブジェクトを-Valueの引数としてバインド
→型の不一致、返還も負荷のため次に進む

```
BIND arg [2019] to parameter [Value]
     Binding collection parameter Value: argument type [Match],
     parameter type [System.Object[]], collection type Array,
     element type [System.Object], no coerceElementType
     Creating array with element type [System.Object] and 1 elements
     Argument type Match is not IList, treating this as scalar
     Adding scalar element of type Match to array position 0
     BIND arg [System.Object[]] to param [Value] SUCCESSFUL
```
パイプラインオブジェクトのValueプロパティの型と-Valueが要求する型を確認
→型は一致しないが変換が可能と判断しバインド

少々雑ですが、以上になります