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