tech.guitarrapc.cóm

Technical updates

PowerShellの-PassThruパラメータについて

前回の第一回シェル芸への挑戦で牟田口先生から以下の別解をいただきました。

さて、-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

f:id:guitarrapc_tech:20140919051800p:plain

ところが、-PassThruパラメータをコマンドの末尾に付けることで、プロセスを実行しつつ、自身のProcess-Objectを返してくれます。

Start-Process notepad -PassThru

f:id:guitarrapc_tech:20140919051820p:plain

-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

f:id:guitarrapc_tech:20140919051841p:plain

Out-GridViewの例

PowerShell 3.0での-PassThruの例として以下の記事があります。

PowerShell 3.0 -PassThru

ここで、なんとOut-Gridで-PassThruを指定すると、選んだ項目を返してくれるとあります。 たとえば、現在のプロセス一覧をGUI表示し、選んだ結果を返す例です。 まずは-PassThruなしで実行してみますが……ただ表示するだけで、プロセスを選んでいても返されません。

Get-Process | Out-GridView

f:id:guitarrapc_tech:20140919051914p:plain

一方、Out-GridViewに-PassThruパラメータを指定するとOKボタンが出来ています。 OKを押すと、その際選択していたプロセス情報が標準出力に返されます。

Get-Process | Out-GridView -PassThru

f:id:guitarrapc_tech:20140919052028p:plain

Out-GridViewで選択していたプロセスが標準出力に返されました。

f:id:guitarrapc_tech:20140919052100p:plain

 

Compare-Objectの例

そして、今回のきっかけとなったCompare-Object (diff)です。

f:id:guitarrapc_tech:20140919052226p:plain

出力が値だけに変化したことが分かります。 -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) について

牟田口先生からコメントいただきました