1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PowerShell モジュールでDynamicParameterを使うときの落とし穴

Last updated at Posted at 2021-01-23

はじめに

主にdynamicParamキーワードを用いて、関数の引数にとる値(文字列)の種類を動的に制御することができる仕組みを、こちらのサイトでご紹介されております。

今回は、この仕組みを次の例のようにInvoke-Expressionコマンドレットと絡めてモジュールから利用しようとしたときに陥った落とし穴について述べていきます。

Module/Module.psm1
function B {
    [CmdletBinding()]
    param ($array)
    dynamicParam {
        $dp = New-DynamicParameter 'Fuga' -Mandatory -Position 0 | Add-ValidateSet $array
        return New-DynamicParameterCollection $dp
    }
    process {
        $Fuga = $PSBoundParameters.Fuga
        return $Fuga
    }
}

function Piyo($command) {
    Invoke-Expression ($command -f "piyo")
}

スコープの誤設定?

早速ですが、次のコードをグローバルスコープで実行すると、エラーとなります。

失敗例
Import-Module "$PSScriptRoot\Module" -Force

function A($a) {
    Piyo 'B $a {0}'
}

A ("hoge", "huga", "piyo")
Add-ValidateSet: ...\Module1.psm1:5:84
Line |
   5 |  … namicParameter 'Fuga' -Mandatory -Position 0 | Add-ValidateSet $array
     |                                                                   ~~~~~~
     | Cannot bind argument to parameter 'ValidateSet' because it is null.     

New-DynamicParameterCollection: ...\Module1.psm1:6:47 
Line |
   6 |          return New-DynamicParameterCollection $dp
     |                                                ~~~
     | Cannot bind argument to parameter 'DynamicParameter' because it is null.

B: A positional parameter cannot be found that accepts argument 'piyo'.

これは、function B$array引数に値1が渡されておらずnullとなっていることを意味しています。
なんでこうなるのか・・・試行錯誤した結果、どうやらスコープの設定に原因があることに辿り着きました。

function A$a引数にscript又はglobal修飾子を添えれば、解決します。

成功例
Import-Module "$PSScriptRoot\Module" -Force

function A($script:a) {
    Piyo 'B $a {0}'
}

A ("hoge", "huga", "piyo") # 出力:piyo

なお、function Piyoが同一スコープにあるときや次のコードのように一体化しているときは、このエラーは発生しません。

function A($a) {
    Invoke-Expression ('B $a {0}' -f "piyo")
}

Invoke-Expressionコマンドレットが別スコープに存在するときに発生するエラーということなのでしょうか・・・?

まとめ

今回はDynamicParameterを使ったときを題材にご紹介しましたが、もしかしたらIValidateSetValuesGeneratorインターフェースを利用したパラメータの定義でも同様の落とし穴が存在するかもしれません2
とにかくダイナミックスコープというものが、ほぼJavaしかやったことのない人間にとってこんな苦しい概念だとは思いませんでした・・・orz

  1. この例で言えば、function A$a引数にとる値"hoge", "huga", "piyo"です。

  2. というのは、実は先にIValidateSetValuesGeneratorインターフェースを利用したパラメータの定義を行っていた時にこれと同じような現象に陥ったことがあり、思い切ってDynamicParameterを使ったやり方に切り替えたらこの現象に陥ってしまったためです。おそらく原因は同じことだと思いますが、今更改めて検証する気は特にありません。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?