前回の第一回シェル芸への挑戦で牟田口先生から以下の別解をいただきました。
問題7-2 Compare-Object (1..10) (Get-Content .\num.txt) -PassThru
— 牟田口大介さん (@mutaguchi) 1月 24, 2013
さて、-PassThreパラメータ…コレがようやく理解出来たので記事にしたいと思います。 さらにPowerShell V3.0では-PassThruも強化されていますのでぜひぜひ。
そもそも-PassThruって何するの
一番分かりやすい説明はコレでしょうか。
Hey, Scripting Guy! Blog - Use the PowerShell Passthru Parameter and Get Back Objects
以下の記述があります。
So, what does passthru do for me? For example, there are many Windows PowerShell cmdelts that simply work, and they do not return any data. An example is the Start-Process cmdlet. Here is an example of using the Start-Process cmdlet to start Notepad. Notice, that the line following the command is empty~中略~ If I add the passthru switched parameter to the end of the command, a Process object returns to the Windows PowerShell console.
要約すると、「返戻値を持たないコマンドレットであっても、当該コマンドのオブジェクトを返してくれる」ということです。
-PassThruパラメータの指定方法
コマンドの最後にパラメータを付けます。 -PassThruパラメ-タは引数を持たないスイッチなので、以下のような要領で使用します。
Start-Service -Name 'wuauserv' -PassThru
-PassThruパラメータを指定しないとこうですね。
Start-Service -Name 'wuauserv'
-PassThruがやっていること
以下のような記事があります。
Powershell: how to implement standard switches?
[CmdltBinding()] attributeを使わずに、-PassThruを実装するにはという内容です。 興味深いのでよろしければ。
-PassThruパラメータをつけると出力がどう変わるの?
コマンドによって、出力が変化します。 ここでは、以下のコマンドでの出力の違いを紹介します。
Start-Process Start-Service Out-GridView Compare-Object Add-Member
Start-Processの例
Hey, Scripting Guy! Blogで例に挙げられているStart-Processコマンドレットの事例です。 Start-Processは、通常Processを開始するのみで返戻値を持ちません。 以下のコマンドを-PassThruパラメータなしで実行すると返戻値を持たないことが分かります。
Start-Process notepad
ところが、-PassThruパラメータをコマンドの末尾に付けることで、プロセスを実行しつつ、自身のProcess-Objectを返してくれます。
Start-Process notepad -PassThru
-PassThruする事で、そのプロセスの実行結果を返してパイプラインにつなげるため、Get-Processなどで取得する事の労力が省かれ非常に有益となります。 たとえば、プロセスを実行してから、そのプロセスの完了をWaite-Processで待機する間に処理を挟むなどです。
$firefox = Start-Process firefox -PassThru # {...入れたい処理....} Wait-Process -Id ($firefox.Id)
Start-Serviceの例
では、Start-Serviceではどうなるのでしょうか。 Start-ServiceもStart-Processと同様に、通常は実行したサービスの状態を返しませんが…-PassThruを指定すると返しています。
Start-Service -Name 'wuauserv' -PassThru
Out-GridViewの例
PowerShell 3.0での-PassThruの例として以下の記事があります。
PowerShell 3.0 -PassThru
ここで、なんとOut-Gridで-PassThruを指定すると、選んだ項目を返してくれるとあります。 たとえば、現在のプロセス一覧をGUI表示し、選んだ結果を返す例です。 まずは-PassThruなしで実行してみますが……ただ表示するだけで、プロセスを選んでいても返されません。
Get-Process | Out-GridView
一方、Out-GridViewに-PassThruパラメータを指定するとOKボタンが出来ています。 OKを押すと、その際選択していたプロセス情報が標準出力に返されます。
Get-Process | Out-GridView -PassThru
Out-GridViewで選択していたプロセスが標準出力に返されました。
Compare-Objectの例
そして、今回のきっかけとなったCompare-Object (diff)です。
出力が値だけに変化したことが分かります。 -PassThruすることで扱いやすくなりますね。
Add-Memberの例
PSObjectでないオブジェクトの拡張を行うとき(メンバーを追加など)に利用するのが、Add-Memberです。NotePropertyやScriptMethodなどを追加出来るので便利なコマンドです。
さて、Add-Memberする際は、自身が-is PSObejct -eq $trueならいいのですが、そうでない場合にはPSObjectでラップしてあげる必要があります。
そこで-PassThruパラメータです。
Add-Member実行時に-PassThruを付けることで、Add-Memeberの結果、新しく作られたPSObjectを自身に返します。 この結果、Add-MeMberの対象オブジェクトを拡張することが可能になります。
一方Add-Member実行時に-PassThruを付けないとどうなるでしょうか。
Start-Processなどと同様、Add-Memberコマンドレットは実行結果(Add-Memeberして新しく作ったPSObject)を返しません。
結果、Add-Memberの対象オブジェクトを拡張する事に失敗します。
サンプルとして、NotePropertyにCommentプロパティを追加し値に"Hello"を与えてみます。
-PassThruがない場合
$sample = "ABC" $sample -is [PSObject] $sample | Add-Member NoteProperty Comment "Hello" -Force $sample.comment
結果はこの通り、NotePropertyが表示できません。(Falseは、-is [PSObject]の結果です。)
False
Get-Memeberでプロパティを確認すると…NotePropertyの追加に失敗しています。
$sample | Get-Member -MemberType Properties | Format-Table -AutoSize TypeName: System.String Name MemberType Definition ---- ---------- ---------- Length Property int Length {get;}
-PassThruがある場合
$sample = "ABC" $sample -is [PSObject] $Sample = $sample | Add-Member NoteProperty Comment "Hello" -Force -PassThru $sample.comment
結果はこの通り、NotePropertyが表示出来ました。(Falseは、-is [PSObject]の結果です。)
False Hello
Get-Memeberでプロパティを確認すると…しっかりNotePropertyの追加ができています。
$sample | Get-Member -MemberType Properties | Format-Table -AutoSize TypeName: System.String Name MemberType Definition ---- ---------- ---------- Comment NoteProperty System.String Comment=Hello Length Property int Length {get;}
-PassThruパラメータになれよう!!
もっともな一言がPowerShell 3.0 -PassThruにありましたw
Summary of PowerShell 3.0 PassThru The best way to learn about PowerShell's -PassThru parameter is by experimenting with examples such as Stop-Process or Out-GridView.
ということで、習うより慣れろってことで。
参考資料
Windows PowerShell: オブジェクトをカスタマイズするさまざまな方法
FilterとPassThruの使い方 Windows Server 2012のWDACで使用できるPowerShellコマンドレット (Add-OdbcDsn) について
牟田口先生からコメントいただきました
-PassThruは「通常は値を出力しない場合も出力する」「入力と同じ型で出力する」と考えれば大体あってるかと。 / “PowerShellの-PassThruパラメータについて « guitarrapc.wordpress.com” htn.to/bzrUS4
— 牟田口大介さん (@mutaguchi) 1月 24, 2013