さて、名前付きのScriptBlockといえば function や filter です。
ただ、こういったやり方もあるのかなということで、ScriptBlockをHashtableに保持して任意に使う方法も考えてみました。
SQLのProcedureのように、記述内容がぱっと確認できるイメージです。
これならHashtable毎に分類もできていいかも!という単純な発想で。
ただ、当然書き換えもできるので、自由過ぎる気もしますが…Tipsということで。
ScriptBlockに制限したHashtableを作る
せっかくScriptBlockに制限したいので、前回の記事で紹介した型安全(type-safe)なHashtableを利用します。
※要はDictionaryです。が、ここではHashtableとしています。分かりにくくてすいません。
PowerShellでHashtableを型付けしたい
このようなコードでサクッと。
$ScriptTable = New-Object 'System.Collections.Generic.Dictionary[string, ScriptBlock]'
ScriptBlockを入れる
では、二乗するScriptBlockと三乗するScriptBlockを入れてみましょう。
$ScriptTable.Double = {$_ * $_}
$ScriptTable.Triple = {$_ * $_ * $_}
Valueを見てみましょう。
$ScriptTable.Double
入っていますね。
$_ * $_
ScriptBlock型でないものを入れようとするとどうなるの?
例えば[int]を入れてみると
$ScriptTable.ID = 4
ちゃんと型制限にかかりましたね。
null 値の式ではメソッドを呼び出せません。
発生場所 D:\Document\Program\Powershell\TypedHashtable\TypedHashtable.ps1:20 文字:1
+ $emploeetyped.Name.GetType().FullName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) []、RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
勿論[string]もだめです。
$ScriptTable.Name = "John"
想定通りです。
このオブジェクトにプロパティ 'ID' が見つかりません。プロパティが存在し、設定可能なことを確認してください。
発生場所 D:\Document\Program\Powershell\TypedHashtable\TypedHashtable.ps1:27 文字:1
+ $ScriptTable.ID = 4
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) []、RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
抜け道
ScriptBlockは、ようは{}なので…こんな抜け道があります。
[int]を入れるなら
$ScriptTable.ScriptInt = {4}
[string]を入れるなら
$ScriptTable.ScriptStr = {"abc"}
型を確認しましょう。
$ScriptTable.ScriptInt.GetType().fullName
ScriptBlockですね。
System.Management.Automation.ScriptBlock
HashtableにいれたScriptBlockの実行方法
まずは、作ったHashtableを確認しましょう。
$ScriptTable
想定通りですね。
Key Value
--- -----
Double $_ * $_
Triple $_ * $_ * $_
ScriptInt 4
ScriptStr "abc"
自動変数を使わないScriptBlockの実行方法
単純に、& (アンパサダント) で実行できます。
&$ScriptTable.ScriptInt
&$ScriptTable.ScriptStr
出力結果です。
4
abc
あるいは、& (アンパサダント)ではなく . (ドット化)でも実行できます。
.$ScriptTable.ScriptInt
.$ScriptTable.ScriptStr
出力結果です。
4
abc
そして値自体は型がそれぞれ割り当てられています。
System.Int32
System.String
自動変数を使ったScriptBlockの実行方法
自動変数$_を使ってますので、| を介してHashtableに入れたScriptBlockに渡します。
正常に実行できない方法
当然この場合、先ほどのやり方では実行できず、エラーも出ませんが、出力もでません。
2 | &$ScriptTable.Double
2 | .$ScriptTable.Double
これもダメなのはお分かりの通りです。
2 | &{$ScriptTable.Double}
2 | .{$ScriptTable.Double}
これでは、ScriptBlockの記述が出るだけです。
$_ * $_
$_ * $_
正常に実行できる方法
ならどうするのか、自動変数が生成されないのが理由なので、自動変数に渡せるやり方を使えばいいわけです。
つまりForeach-Obejctで渡します。
2 | %{& $ScriptTable.Double}
2 | %{& $ScriptTable.Triple}
でましたね。
4
8
あるいは、& (アンパサダント)ではなく . (ドット化)でも実行できます。
2 | %{. $ScriptTable.Double}
2 | %{. $ScriptTable.Triple}
でましたね。
4
8
※補足
$_が必要なので、Invoke-Commandで渡そうとするとダメになります。
2 | %{Invoke-Command {$ScriptTable.Double}}
ScriptBlockが出力されてしまいます。
$_ * $_
paramを使ったScriptBlockの実行方法
もっと使いやすい方法として、paramを利用しましょう。
まずは、paramを含むScriptBlockをHashtableにいれます。
$ScriptTable.QuadroParam = {param([int]$num); $num * $num * $num * $num}
実行するには、単純に、& (アンパサダント) をつけます。
& $ScriptTable.QuadroParam -num 2
出ましたね。
8
あるいは、& (アンパサダント)ではなく . (ドット化)でも実行できます。
. $ScriptTable.QuadroParam -num 2
出ましたね。
8
さらに、Invoke-Commandでもいいでしょう。
Invoke-Command {& $ScriptTable.QuadroParam -num 2}
でました。
8
まとめ
簡単なScriptBlockをまとめておいて分類するのに便利かなとか思ったのです。
しかし、ScriptBlockはインテリセンスが効かないのが辛いですね、paramである-nunを呼び出そうにも知らないと実行できないのがちょっと。
使わなさそうな気がしてきましたorz