tech.guitarrapc.cóm

Technical updates

PowerShellのスプラッティングを試す

前々回の記事で、パイプラインを介してFunctionに渡す例をやりました。
PowerShellでHashTableや配列の値をパイプラインでFunctionに渡す
この時試したのは以下の方法です。
  1. ハッシュテーブル(HashTable)
  2. 配列(Array)
  3. ハッシュテーブルを[PSCustomObject]でキャスト
さて、Functionへのパラメータ指定の方法として、ValueFromPipelineByPropertyNameの有用性を考えると、事前にパラメータを定義できたら……と思うこともあったりなかったり、やっぱりなかったり。 とはいえ、一度見てみましょう。

スプラッティングとは

ここに詳細があります。
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には制限がありません ( 検証ミスりました ただし、受け手側のFunctionに条件が1つだけあります。
パラメータに[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は、ValueFromPipelineByPropertyNameValueFromPipelineの両方が$trueでもいい気もしますが……んーどうなんでしょう。

牟田口先生のまとめ

勉強になるので、軽くまとめておきます。