about_Pipelines
トピック
about_pipelines
簡易説明
Windows PowerShell でのパイプラインによるコマンドの結合。
詳細説明
パイプラインとは、パイプライン演算子 (|) (ASCII 124) を使用して連結
された一連のコマンドです。各パイプライン演算子は、直前のコマンドの
結果を次のコマンドに渡します。
パイプラインを使用すると、一方のコマンドにより出力されたオブジェクト
を他方のコマンドの入力として使用できます。そのコマンドの出力をさらに別の
コマンドに渡すこともできます。その結果、一連の単純なコマンドから非常に強力
なコマンド チェーン、または "パイプライン" を作成できます。
次に例を示します。
Command-1 | Command-2 | Command-3
この例では、Command-1 により出力されるオブジェクトが Command-2 に渡されます。
Command-2 は、これらのオブジェクトを処理し、Command-3 に渡します。Command-3 は、
これらのオブジェクトを処理し、パイプラインでの次の処理に渡します。このパイプラ
インにはこれ以上コマンドが存在しないので、結果がコンソールに表示されます。
パイプラインでは、左から右に、表示された順序でコマンドが処理されます。
単一の操作として処理され、出力が生成されると、そのまま表示されます。
簡単な例を次に示します。Notepad プロセスを取得してプロセスを停止するには、
次のコマンドを実行します。
get-process notepad |stop-process
最初のコマンドでは、Get-Process コマンドレットを使用して Notepad プロセスを
表すオブジェクトを取得します。次に、パイプライン演算子 (|) によってプロセス
オブジェクトが Stop-Process コマンドレットに渡され、Notepad プロセスが停止します。
指定されたプロセスがパイプラインを介して渡されるため、Stop-Process コマンドに
Name や ID などのプロセスを指定するパラメーターが含まれていないことに注意してください。
実際の使用例を次に示します。このコマンド パイプラインでは、現在のディレクトリからテキスト
ファイルを取得し、10,000 バイトを超えるファイルだけを選択して長さで並べ替えた後、
各ファイルの名前と長さを表に示します。
Get-ChildItem -path *.txt | Where-Object {$_.length -gt 10000} |
Sort-Object -property Length | Format-Table -property name, length
このパイプラインは、指定した順序で並べられた 4 つのコマンドから構成されています。
コマンドは横に並べて記述されますが、次の図ではプロセスの流れを縦方向に示しています。
Get-ChildItem -path *.txt
|
| (FileInfo objects )
| ( .txt )
|
V
Where-Object {$_.length -gt 10000}
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
|
V
Sort-Object -property Length
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
| ( Sorted by length )
|
V
Format-Table -property name, length
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
| ( Sorted by length )
| (Formatted in a table )
|
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
パイプラインの使用
Windows PowerShell コマンドレットは、パイプラインでの使用を想定して設計されています。
たとえば、一般的な使用例では、Get コマンドレットで取得した結果をパイプ処理し、同じ名詞
の処理コマンドレット (Set、Start、Stop、Rename コマンドレットなど) に渡すことができます。
たとえば、Get-Service コマンドレットからすべてのサービスをパイプ処理して、Start-Service
または Stop-Service コマンドレットに渡すことができます (ただし、無効になっているサービスは、
この方法では再開できません)。
次のコマンド パイプラインを実行すると、コンピューター上で WMI サービスが起動されます。
get-service wmi |start-service
Windows PowerShell プロバイダーのオブジェクトの取得または設定を行うコマンドレット (Item および
ItemProperty コマンドレットなど) も、パイプラインで使用できるように設計されています。
たとえば、Windows PowerShell レジストリ プロバイダーの Get-Item または Get-ChildItem
コマンドの結果をパイプ処理して、New-ItemProperty コマンドレットに渡すことができます。
次のコマンドは、8124 という値を持つ新しいレジストリ エントリ NoOfEmployees を MyCompany
レジストリ キーに追加します。
get-item -path HKLM:\Software\MyCompany | new-Itemproperty -name NoOfEmployees -value 8124
Get-Member、Where-Object、Sort-Object、Group-Object、および Measure-Object などの多くの
ユーティリティ コマンドレットは、ほぼパイプラインにのみ使用されます。これらのコマンドレットに
は、あらゆるオブジェクトをパイプ処理で渡すことができます。
たとえば、コンピューター上のすべてのプロセスをパイプ処理して Sort-Object コマンドに渡し、
それらをハンドル数に基づいて並べ替えることができます。
get-process | sort-object -property handles
また、Format-List および Format-Table などの書式設定用コマンドレット、Export-Clixml および
Export-CSV などの Export コマンドレット、Out-Printer などの Out コマンドレットにも、任意のオブジ
ェクトをパイプ処理で渡すことができます。
たとえば、Winlogon プロセスを Format-List コマンドレットにパイプ処理して渡し、プロセスのすべての
プロパティを一覧表示できます。
get-process winlogon | format-list -property *
少し練習するだけで、単純なコマンドをパイプラインで連結することが、時間や労力の軽減、また効率の
良いスクリプトの作成につながるということを実感できます。
パイプラインの動作
オブジェクトがパイプ処理される、つまり一方のコマンドの出力に含まれるオブジェクトが他方のコマンドに渡されると、
Windows PowerShell はパイプ処理されたオブジェクトを受け取り側のコマンドレットのいずれかのパラメーターに関連付けます。
このため、Windows PowerShell には入力オブジェクトをコマンドレット パラメーターに関連付ける
"パラメーターをバインドする" コンポーネントが存在し、このコンポーネントは次の条件を満たすパラメーターを検索します。
-- パイプラインからの入力を許可するパラメーター (すべてのパラメーターが許可するわけではないため)
-- 渡されるオブジェクトの型またはオブジェクトの変換が可能な目的の型を受け入れるパラメーター
-- コマンドでまだ使用されていないパラメーター
たとえば、Start-Service コマンドレットには多くのパラメーターが存在しますが、パイプラインの入力を許可するのは
Name および InputObject の 2 つのパラメーターのみです。Name パラメーターは文字列を受け取り、InputObject
パラメーターはサービス オブジェクトを受け取ります。このため、文字列およびサービス オブジェクト (または文字列
およびサービス オブジェクトに変換可能なプロパティを持つオブジェクト) をパイプ処理して、Start-Service
に渡すことができます。
Windows PowerShell のパラメーター バインド コンポーネントが、パイプ処理されたオブジェクトを受け取り側の
コマンドレット パラメーターに関連付けることができない場合、コマンドは失敗し、見つからなかったパラメーター
値の入力を求めるメッセージが Windows PowerShell によって表示されます。
パラメーター バインド コンポーネントを強制して、パイプ処理されたオブジェクトを特定のパラメーターに関連付
けることはできません。また、ユーザーがパラメーターを提示することもできません。その代わり、パイプ処理は
コンポーネントのロジックによって最大限効率的に管理されます。
個別の処理
パイプ処理によるコマンドへのオブジェクトの送信は、コマンドのパラメーターによるオブジェクトの
送信とよく似ています。
たとえば、コンピューター上のサービスを表すオブジェクトをパイプ処理で Format-Table コマンドに
渡す操作について考えます。
get-service | format-table -property name, dependentservices
この操作は、サービス オブジェクトを変数に格納し、Format-Table の InputObject パラメーターを使用
してサービス オブジェクトを送信する操作と非常に似ています。
$services = get-service
format-table -inputobject $services -property name, dependentservices
または、コマンドをパラメーター値に埋め込む操作と似ています。
format-table -inputobject (get-service wmi) -property name, dependentservices
ただし、大きな違いがあります。つまり、複数のオブジェクトをコマンドに渡す場合、パイプ処理では
オブジェクトが一度に 1 つずつコマンドに渡されます。一方、コマンド パラメーターを使用する場合は、
オブジェクトが単一の配列オブジェクトとして渡されます。
見かけは機能上の違いですが、これによって興味深い効果、場合によっては便利な効果を得ることができます。
たとえば、複数のプロセス オブジェクトをパイプ処理して、Get-Process コマンドレットから Get-Member
コマンドレットに渡す場合、Windows PowerShell ではプロセス オブジェクトは一度に 1 つずつ Get-Member
に渡されます。Get-Member は、プロセス オブジェクトの .NET クラス (型)、プロパティ、およびメソッドを
表示します(Get-Member では、重複は取り除かれます。このため、すべてのオブジェクトの型が同じである場合は、
1 つのオブジェクト型のみが表示されます)。
この場合、Get-Member によって各プロセス オブジェクト (System.Diagnostics.Process オブジェクト) の
プロパティとメソッドが表示されます。
get-process | get-member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
一方、Get-Member の InputObject パラメーターを使用すると、System.Diagnostics.Proc
ess オブジェクトの配列が 1 つの単位として Get-Member に渡されます。このため、
オブジェクトの配列のプロパティが表示されます (System.Object 型名の後にある配列記号
([]) に注意してください)。
get-member -inputobject (get-process)
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
...
結果が意図したものと異なるかもしれませんが、しくみを理解することで、適切に利用できます。
たとえば、プロセス オブジェクトの配列には Count プロパティがあります。これを利用して、
コンピューター上のプロセスの数をカウントすることができます。
(get-process).count
この違いが重要になることがあります。したがって、オブジェクトをパイプ処理してコマンドレットに
渡す場合は、オブジェクトが一度に 1 つずつ渡されることに注意してください。
パイプライン入力の許可
パイプラインでオブジェクトを受け取るには、受け取る側のコマンドレットにパイプライン
入力を許可するパラメーターが存在している必要があります。Get-Help コマンドを Full
または Parameter パラメーターと一緒に使用すると、パイプライン入力を許可するコマンド
レットのパラメーターを特定できます (存在する場合)。
Get-Help の既定の表示では、パラメーター属性のテーブルに "パイプライン入力を許可する"
という項目が表示されます。このテーブルは、Get-Help コマンドレットの Full または
Parameter パラメーターを設定した場合にのみ表示されます。
たとえば、Start-Service コマンドレットのどのパラメーターがパイプライン入力を許可
しているかを調べるには、次のように入力します。
get-help start-service -full
get-help start-service -parameter *
たとえば、Start-Service コマンドレットのヘルプによると、パイプライン入力を許可する
("true") パラメーターは Name および InputObject パラメーターです。その他のパラメーター
では、"パイプライン入力を許可する" 行の値が "false" になっています。
-name <string[]>
開始するサービスのサービス名を指定します。
パラメーター名は省略可能です。-Name またはそのエイリアスである -ServiceName を使用する
か、パラメーター名を省略することができます。
必須 true
位置 1
既定値
--> パイプライン入力を許可する true (ByValue, ByPropertyName)
ワイルドカード文字を許可する true
-inputObject <ServiceController[]>
開始するサービスを表す ServiceController オブジェクトを指定します。
オブジェクトが格納されている変数を入力するか、オブジェクトを取得
するコマンドまたは式を記述します。
必須 false
位置 named
既定値
--> パイプライン入力を許可する true (ByValue)
ワイルドカード文字を許可する false
これは、パイプラインを介してオブジェクト (PsObjects) を Where-Object コマンドレットに
渡すことができ、渡されたオブジェクトは Windows PowerShell によって InputObject
パラメーターに関連付けられることを示しています。
パイプライン入力を許可する方法
コマンドレット パラメーターでパイプライン入力を許可するには、次の 2 つの方法があります。
-- ByValue: "値に基づいて" 入力を許可するパラメーターは、パイプ処理されたオブジェクトの
.NET 型がパラメーターの値と同じであるか、オブジェクトをその型に変換可能な場合に
オブジェクトを許可します。
たとえば、Start-Service の Name パラメーターは、値に基づいてパイプライン入力を許可します。
この場合、文字列オブジェクトまたは文字列に変換することができるオブジェクトが許可されます。
-- ByPropertyName: "プロパティ名に基づいて" 入力を許可するパラメーターは、パイプ処理された
オブジェクトにパラメーターと同じ名前のプロパティが存在する場合にオブジェクトを許可します。
たとえば、Start-Service の Name パラメーターは、Name プロパティを持つオブジェクトを許可します。
(オブジェクトのプロパティを一覧表示するには、オブジェクトをパイプ処理して Get-Member に渡します。)
一部のパラメーターでは、値およびプロパティ名のどちらに基づいてもオブジェクトを許可できます。
これらのパラメーターは、簡単にパイプライン入力を受け取ることができるように設計されています。
パイプライン エラーの調査
パイプラインのエラーによりコマンドが失敗する場合は、エラーを調査し、コマンドを書き直すことができます。
たとえば、次のコマンドでは、Get-Item コマンドレットを使用して移動先のパスを取得し、そのパスをパイプ処理で
Move-ItemProperty コマンドレットに渡すことにより、レジストリ エントリを一方のレジストリ キーから他方の
レジストリ キーに移動します。
具体的には、このコマンドは Get-Item コマンドレットを使用して移動先のパスを取得します。結果を Move-
ItemProperty コマンドレットに渡すために、パイプライン演算子が使用されます。Move-ItemProperty コマンドは、
移動するレジストリ エントリの現在のパスおよび名前を指定します。
get-item -path hklm:\software\mycompany\sales |
move-itemproperty -path hklm:\software\mycompany\design -name product
このコマンドは失敗し、Windows PowerShell により次のエラー メッセージが表示されます。
Move-ItemProperty: 入力オブジェクトをコマンドのパラメーターにバインドできません。コマンドがパイプライン入
力を受け入れないか、または入力とそのプロパティが、パイプライン入力を受け入れるいずれのパラメーターにも
一致しません。
行:1 文字:23
+ $a | move-itemproperty <<<< -path hklm:\software\mycompany\design -name product
調査するには、Trace-Command コマンドレットを使用して Windows PowerShell のパラメーター バインド
コンポーネントをトレースします。次のコマンドでは、コマンドの処理中にパラメーター バインド
コンポーネントがトレースされます。-pshost パラメーターを使用して結果をコンソールに表示し、
後で参照できるように、-filepath コマンドを使用して結果を debug.txt ファイルに送信します。
trace-command -name parameterbinding -expression {get-item -path hklm:\software\mycompany\sales |
move-itemproperty -path hklm:\software\mycompany\design -name product} -pshost -filepath debug.txt
トレース結果は非常に長いものですが、Get-Item コマンドレットにバインドされている値、さらに Move-ItemProperty
コマンドレットにバインドされている名前付きの値が示されています。
...
BIND NAMED cmd line args [Move-ItemProperty]
BIND arg [hklm:\software\mycompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
....
BIND POSITIONAL cmd line args [Move-ItemProperty]
...
最後に、Move-ItemProperty の Destination パラメーターへのパスのバインドに失敗したことが示されています。
...
BIND PIPELINE object to parameters: [Move-ItemProperty]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
...
エラーを調査するには、Get-Help コマンドレットを使用して Destination パラメーターの属性を表示します。
次のコマンドを入力すると、Destination パラメーターに関する詳細情報を取得できます。
get-help move-itemproperty -parameter destination
結果には、Destination が "プロパティ名に基づいて" のみパイプライン入力を受け取ることが示されています。
つまり、パイプ処理されたオブジェクトに Destination という名前のプロパティが存在している必要があります。
-destination <string>
移動先のパスを指定します。
必須 true
位置 2
既定値
パイプライン入力を許可する true (ByPropertyName)
ワイルドカード文字を許可する true
パイプ処理で Move-ItemProperty コマンドレットにパイプされるオブジェクトのプロパティを表示するには、
オブジェクトをパイプ処理して Get-Member コマンドレットに渡します。次のコマンドでは、コマンドの最初
の部分の結果をパイプ処理して Get-Member コマンドレットに渡します。
get-item -path hklm:\software\mycompany\sales |get-member
出力では、項目が Microsoft.Win32.RegistryKey で、この項目には Destination プロパティが含まれないこ
とが示されます。これがコマンドが失敗した理由です。
コマンドを修正するには、Move-ItemProperty コマンドレットに移動先を指定する必要があります。
Get-ItemProperty コマンドを使用してパスを取得することはできますが、コマンドの Move-ItemProperty
部分で名前と移動先を指定する必要があります。
get-item -path hklm:\software\mycompany\design |
move-itemproperty -dest hklm:\software\mycompany\design -name product
コマンドが成功したかどうかを確認するには、Get-ItemProperty コマンドを使用します。
get-itemproperty hklm:\software\mycompany\sales
結果から、Product レジストリ エントリが Sales キーに移動されたことがわかります。
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany\sales
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany
PSChildName : sales
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
Product : 18
関連項目
about_objects
about_parameters
about_command_syntax
about_foreach