PowerShellでHashTableや配列の値をパイプラインでFunctionに渡すこの時試したのは以下の方法です。
- ハッシュテーブル(HashTable)
- 配列(Array)
- ハッシュテーブルを[PSCustomObject]でキャスト
スプラッティングとは
ここに詳細があります。Windows PowerShell: スプラッティング スプラッティングを使用して Windows PowerShell スクリプトを簡略化する方法について教えてくださいようは、パラメータをバンドル(あらかじめまとめてしまう)という事です。
コマンドに渡す前にパラメーターをバンドルできれば時間を節約できます。 Windows PowerShell では、パラメーターをバンドルしてコマンドに渡す方法のことを "スプラッティング" と言います。 ※抜粋
具体的にはどうする?
HashTableを作って、代入した変数をFunctionで利用する際に@で指定すればいいだけです。 簡単ですね。 例えば以下のHashTableでスプラッティングするなら……$test =@{ path="C:\hoge\fuga"; sortby="Extention"; count=1}Functionへの指定時に
$test.プロパティ
ではなく@test
とするだけという。
Test-Function @test特にFunctionには制限がありません ( 検証ミスりました
パラメータに[Parameter(ValueFromPipeline=$true)]か[Parameter(ValueFromPipelineByPropertyName=$true)]を有効にしておく必要があります。 どちらか片方が有効なら、問題ありません。 が、どちらも指定していないと、自動的にプロパティを指定してくれません。
スプラッティングしてみよう
では早速テストしてみましょう。 前回の追記でサンプルとしてだしたFunctionを利用します。function Get-FirstItem { [CmdletBinding()] param( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$path, [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$sortby, [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [int]$count ) begin{ } process{ Get-ChildItem $path | Sort-Object $sortby | Select-Object -First $count } end{ } }パラメータをHashTableで定義します。
$test =@{ path="C:\hoge\fuga"; sortby="Extention"; count=1}スプラッティングして、Functionに渡します。
Get-FirstItem @testおー、取得できました。
ディレクトリ: C:\hoge\fuga Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/02/19 20:06 16 6.txt
受け手のパラメータを有効にしないと?
では、受け手のFunctionで、パラメータの[Parameter(ValueFromPipeline=$true)]
と[Parameter(ValueFromPipelineByPropertyName=$true)]
をそれぞれ有効/無効にするとどうなるか見てみましょう。
まずは、ValueFromPipeline=$true
だけを有効にしてみます。
function Get-FirstItem { [CmdletBinding()] param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string]$path, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string]$sortby, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [int]$count ) begin{ } process{ Get-ChildItem $path | Sort-Object $sortby | Select-Object -First $count } end{ } }実行します。
Get-FirstItem @test問題ないですね。
ディレクトリ: C:\hoge\fuga Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/02/19 20:06 16 6.txtでは、両方無効にしてみます。
function Get-FirstItem { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$path, [Parameter(Mandatory=$true)] [string]$sortby, [Parameter(Mandatory=$true)] [int]$count ) begin{ } process{ Get-ChildItem $path | Sort-Object $sortby | Select-Object -First $count } end{ } }実行してみます。
Get-FirstItem @test問題なく実行できます。 (前回の検証では変数に変な値が入っていました)
ディレクトリ: C:\hoge\fuga Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2013/02/19 20:06 16 6.txt
コマンド パイプライン位置 1 のコマンドレット Get-FirstItem 次のパラメーターに値を指定してください: path:
まとめ
プロパティをまとめる……ありはありですね。 HshTableのままで扱いたいけど、プロパティ指定にも使う場合は、スプラッティングかK,V指定で渡す。 [PSCustomObject]にキャストするのに一時的にHashTableを利用したなら[PSCustomObejct]の方が楽なきもします。 いずれにしても、K,V指定が便利な場面と、プロパティ指定が楽な場面、それぞれに応じればいいのではないでしょうか。Functionへのパラメータ指定
前回の記事の[PSCustomObject]も含めて考えると、今後作成するFunctionは、ValueFromPipelineByPropertyName
とValueFromPipeline
の両方が$trueでもいい気もしますが……んーどうなんでしょう。
牟田口先生のまとめ
勉強になるので、軽くまとめておきます。@guitarrapc 今回のみたくカスタムオブジェクトを作って渡す用なのかなと思うんですが、それならスプラッティングのほうが連想配列のまま渡せて便利だしで、うーむ、という。
— 牟田口大介さん (@mutaguchi) 2013年2月20日
@guitarrapc あとは-InputObject <object[]>にするよりは型安全とダックタイピングが両立するというメリットもあるかもですが、PSで型安全とか言い出してもなあ、とも思いますし中々これぞという使用法がみつからないです。
— 牟田口大介さん (@mutaguchi) 2013年2月20日
@guitarrapc あとスプラッティングだと配列で渡せないけど、カスタムオブジェクトとByPropertyNameならパイプライン経由で渡せるというメリットはあるのかもですね。
— 牟田口大介さん (@mutaguchi) 2013年2月20日
@guitarrapc ただ、いろんなコマンドレットを見てると、一つのパラメータセットに二つ以上ValueFromPipelineがついてるパラメータがあることは少ないようにも思います。
— 牟田口大介さん (@mutaguchi) 2013年2月20日
@guitarrapc ValueFromPipelineByPropertyNameが複数パラメータで定義されてるパラメータセットと、ValueFromPipelineが1個だけのパラメータセットというパターンが多いような。
— 牟田口大介さん (@mutaguchi) 2013年2月20日