about_Pipelines
簡単な説明
PowerShell でコマンドをパイプラインに結合する
長い説明
パイプラインは、パイプライン演算子 ( | ) によって接続された一連のコマンドです (ASCII 124)。 各パイプライン演算子は、前のコマンドの結果を次のコマンドに送信します。
最初のコマンドの出力は、2番目のコマンドの入力として処理のために送信できます。 また、その出力を他のコマンドに送信することもできます。 結果として、一連の単純なコマンドで構成される複雑なコマンドチェーンまたは パイプライン が生成されます。
たとえば、次のように入力します。
Command-1 | Command-2 | Command-3
この例では、によって出力される Command-1 オブジェクトがに Command-2 送信されます。
Command-2 オブジェクトを処理し、に Command-3 送信します。 Command-3 オブジェクトを処理し、パイプラインに送信します。 パイプラインにはこれ以上コマンドがないため、結果はコンソールに表示されます。
パイプラインでは、コマンドは左から右に順番に処理されます。 処理は単一の操作として処理され、生成されると出力が表示されます。
単純な例を次に示します。 次のコマンドは、メモ帳プロセスを取得して停止します。
たとえば、次のように入力します。
Get-Process notepad | Stop-Process
最初のコマンドは、コマンドレットを使用 Get-Process して、メモ帳プロセスを表すオブジェクトを取得します。 パイプライン演算子 ( | ) を使用して、プロセスオブジェクトをコマンドレットに Stop-Process 送信します。これにより、メモ帳プロセスが停止されます。 Stop-Process指定されたプロセスはパイプラインを介して送信されるため、このコマンドには、プロセスを指定するための 名前 または ID パラメーターがありません。
このパイプラインの例では、現在のディレクトリ内のテキストファイルを取得し、1万バイトを超えるファイルのみを選択し、長さで並べ替え、各ファイルの名前と長さをテーブルに表示します。
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 for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| ( Length > 10000 )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
| ( Formatted in a table )
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
パイプラインの使用
ほとんどの PowerShell コマンドレットは、パイプラインをサポートするように設計されています。 ほとんどの場合、 Get コマンドレットの結果を同じ名詞の別のコマンドレットに パイプ することができます。
たとえば、コマンドレットの Get-Service 出力をコマンドレットまたは Stop-Service コマンドレットに Start-Service パイプすることができます。
このパイプライン例では、コンピューター上の WMI サービスを開始します。
Get-Service wmi | Start-Service
別の例として、PowerShell レジストリプロバイダー内のまたは Get-ChildItem の Get-Item 出力をコマンドレットに New-ItemProperty パイプすることができます。 この例では、値が 8124 の新しいレジストリエントリ Noofemployees を MyCompany レジストリキーに追加します。
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
、、、 Group-Object 、 Measure-Object などの多くのユーティリティコマンドレット Get-Member は、ほとんどの場合 Where-Object Sort-Object 、パイプラインでのみ使用されます。 パイプを使用して、任意のオブジェクト型をこれらのコマンドレットに送ることができます。 この例では、コンピューター上のすべてのプロセスを、プロセスごとに開いているハンドルの数で並べ替える方法を示します。
Get-Process | Sort-Object -Property handles
パイプを使用して Format-List 、オブジェクトを書式設定、エクスポート、および出力コマンドレット (、 Export-CSV Format-Table Export-Clixml Out-File 、、、など) に送ることができます。
この例では、 Format-List コマンドレットを使用して、プロセスオブジェクトのプロパティの一覧を表示する方法を示します。
Get-Process winlogon | Format-List -Property *
パイプを使用して、ネイティブコマンドの出力を PowerShell コマンドレットに送ることもできます。 次に例を示します。
PS> ipconfig.exe | Select-String -Pattern 'IPv4'
IPv4 Address. . . . . . . . . . . : 172.24.80.1
IPv4 Address. . . . . . . . . . . : 192.168.1.45
IPv4 Address. . . . . . . . . . . : 100.64.108.37
重要
成功 と エラー のストリームは、他のシェルの stdin および stderr ストリームに似ています。 ただし、stdin は入力のために PowerShell パイプラインに接続されていません。 詳細については、「 about_Redirection」を参照してください。
単純なコマンドをパイプラインにまとめると、時間と入力が節約され、スクリプトの効率が向上することがわかります。
パイプラインのしくみ
ここでは、入力オブジェクトをコマンドレットパラメーターにバインドし、パイプラインの実行中に処理する方法について説明します。
パイプライン入力の受け入れ
パイプライン処理をサポートするには、受信コマンドレットにパイプライン入力を受け入れるパラメーターが必要です。 Get-Helpコマンドを Full または Parameter オプションと共に使用して、パイプライン入力を受け入れるコマンドレットのパラメーターを決定します。
たとえば、コマンドレットの Start-Service どのパラメーターがパイプライン入力を受け入れるかを決定するには、次のように入力します。
Get-Help Start-Service -Full
または
Get-Help Start-Service -Parameter *
コマンドレットの Start-Service ヘルプでは、 InputObject パラメーターと Name パラメーターのみがパイプライン入力を受け入れることが示されています。
-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <String[]>
Specifies the service names for the service to be started.
The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
パイプラインを介してオブジェクトをに Start-Service 送信すると、PowerShell は、オブジェクトを InputObject パラメーターと Name パラメーターに関連付けようとします。
パイプライン入力を受け入れる方法
コマンドレットのパラメーターは、次の2つの方法のいずれかでパイプライン入力を受け入れることができます。
Byvalue: パラメーターは、予期された .net 型に一致する値、またはその型に変換できる値を受け入れます。
たとえば、の
Start-ServiceName パラメーターは、値によってパイプライン入力を受け入れます。 文字列に変換できる文字列オブジェクトまたはオブジェクトを受け入れることができます。Bypropertyname: パラメーターは、入力オブジェクトにパラメーターと同じ名前のプロパティがある場合にのみ、入力を受け入れます。
たとえば、の
Start-Servicename パラメーターは、 name プロパティを持つオブジェクトを受け入れることができます。 オブジェクトのプロパティを一覧表示するには、をにGet-Memberパイプします。
パラメーターによっては、値またはプロパティ名の両方でオブジェクトを受け取ることができるため、パイプラインからの入力が簡単になります。
パラメーターのバインド
パイプを使用してオブジェクトを1つのコマンドから別のコマンドにパイプすると、PowerShell は、パイプされたオブジェクトを受信側のコマンドレットのパラメーターに関連付けます。
PowerShell のパラメーターバインドコンポーネントは、次の条件に従って、入力オブジェクトをコマンドレットパラメーターに関連付けます。
- パラメーターは、パイプラインからの入力を受け入れる必要があります。
- パラメーターは、送信されるオブジェクトの型または必要な型に変換できる型を受け入れる必要があります。
- パラメーターがコマンドで使用されませんでした。
たとえば Start-Service 、コマンドレットには多くのパラメーターがありますが 、そのうち の2つだけがパイプライン 入力を受け入れ ます。 Name パラメーターは文字列を受け取り、 InputObject パラメーターはサービスオブジェクトを受け取ります。 したがって、文字列、サービスオブジェクト、およびオブジェクトを、文字列またはサービスオブジェクトに変換できるプロパティと共にパイプすることができます。
PowerShell は、可能な限り効率的にパラメーターバインディングを管理します。 特定のパラメーターにバインドする PowerShell を提案したり、強制したりすることはできません。 PowerShell がパイプされたオブジェクトをバインドできない場合、コマンドは失敗します。
バインディングエラーのトラブルシューティングの詳細については、この記事で後述する「 パイプラインエラーの調査 」を参照してください。
1回限りの処理
オブジェクトをコマンドにパイプするのは、コマンドのパラメーターを使用してオブジェクトを送信するのとよく似ています。 パイプラインの例を見てみましょう。 この例では、パイプラインを使用して、サービスオブジェクトのテーブルを表示します。
Get-Service | Format-Table -Property Name, DependentServices
機能的には、これはの InputObject パラメーターを使用してオブジェクトコレクションを送信するの Format-Table と似ています。
たとえば、 InputObject パラメーターを使用して渡された変数にサービスのコレクションを保存できます。
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
または、 InputObject パラメーターにコマンドを埋め込むこともできます。
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
ただし、重要な違いがあります。 パイプを使用して複数のオブジェクトをコマンドに渡した場合、PowerShell は一度に1つずつコマンドにオブジェクトを送信します。 コマンドパラメーターを使用すると、オブジェクトは1つの配列オブジェクトとして送信されます。 この軽微な違いには大きな影響があります。
パイプラインを実行すると、PowerShell は、インターフェイスを実装 IEnumerable する任意の型を自動的に列挙し、パイプラインを介して一度に1つずつメンバーを送信します。 例外は [hashtable] で、メソッドを GetEnumerator() 呼び出す必要があります。
次の例では、配列とハッシュテーブルをコマンドレットに Measure-Object パイプして、パイプラインから受信したオブジェクトの数をカウントしています。 配列に複数のメンバーがあり、ハッシュテーブルに複数のキーと値のペアが含まれています。 配列は、一度に1つずつ列挙されます。
@(1,2,3) | Measure-Object
Count : 3
Average :
Sum :
Maximum :
Minimum :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count : 1
Average :
Sum :
Maximum :
Minimum :
Property :
同様に、コマンドレットから Get-Process コマンドレットに Get-Member 複数のプロセスオブジェクトをパイプすると、PowerShell は各プロセスオブジェクトを一度に1つずつに Get-Member 送信します。 Get-Member プロセスオブジェクトの .NET クラス (型)、およびそのプロパティとメソッドを表示します。
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 重複を排除します。したがって、オブジェクトの種類がすべて同じである場合は、オブジェクトの種類が1つだけ表示されます。
ただし、の Get-Member Get-Member InputObject パラメーターを使用すると、は1つの単位として system.string オブジェクトの配列を 受け取ります。 オブジェクトの配列のプロパティを表示します。 ( 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 つ配信される点に注意してください。
パイプラインでのネイティブ コマンドの使用
PowerShell を使用すると、パイプラインにネイティブ外部コマンドを含めできます。 ただし、PowerShell のパイプラインはオブジェクト指向であり、未加工のバイト データをサポートしていない点に注意してください。
生のバイト データを出力するネイティブ プログラムからの出力をパイプ処理またはリダイレクトすると、出力が .NET 文字列に変換されます。 この変換により、生データ出力が破損する可能性があります。
回避策として、 または を使用してネイティブ コマンドを呼び出 cmd.exe /c sh -c | し、ネイティブ シェルによって提供される 演算子と 演算子 > を使用します。
パイプライン エラーの調査
PowerShell でパイプされたオブジェクトを受信側コマンドレットのパラメーターに関連付けできない場合、コマンドは失敗します。
次の例では、レジストリ エントリをレジストリ キー間で移動します。 コマンドレット Get-Item は宛先パスを取得し、次にコマンドレットにパイプされます Move-ItemProperty 。 コマンド Move-ItemProperty は、移動するレジストリ エントリの現在のパスと名前を指定します。
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
コマンドが失敗し、PowerShell に次のエラー メッセージが表示されます。
Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<< -Path HKLM:\Software\MyCompany\design -Name p
調査するには、 コマンドレットを使用 Trace-Command して、PowerShell のパラメーター バインド コンポーネントをトレースします。 次の例では、パイプラインの実行中にパラメーター バインドをトレースします。 PSHost パラメーターは コンソールにトレース結果を表示し、FilePath debug.txt パラメーターは後で参照するためにトレース結果をファイルに送信します。
Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}
トレースの結果は長 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`]
...
最後に、パスをの Destination パラメーターにバインドしようとして 失敗したとMove-ItemProperty表示されます。
...
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 パラメーターの属性 を表示 します。
Get-Help Move-ItemProperty -Parameter Destination
-Destination <String>
Specifies the path to the destination location.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
結果は、 Destination がパイプライン入力 のみを "by プロパティ名" で受け取るという結果を示しています。 そのため、パイプされたオブジェクトには Destination という名前のプロパティが必要 です。
から Get-Member 取得したオブジェクトのプロパティを表示するには、 を使用します Get-Item。
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
出力は、項目が Destination プロパティを持つ Microsoft.Win32.RegistryKey オブジェクトを 示 しています。 これは、コマンドが失敗した理由を説明します。
Path パラメーターは、名前または値でパイプライン入力を受け取ります。
Get-Help Move-ItemProperty -Parameter Path
-Path <String[]>
Specifies the path to the current location of the property. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
コマンドを修正するには、 コマンドレットMove-ItemProperty``Get-Itemで宛先を指定し、 を使用して移動する項目の パス を取得する必要があります。
たとえば、次のように入力します。
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
組み込み行の継続
既に説明したように、パイプラインはパイプライン演算子 (|) によって接続される一連のコマンドで、通常は 1 行で記述されます。 ただし、読みやすさを確保するために、PowerShell を使用すると、パイプラインを複数の行に分割できます。
パイプ演算子が行の最後のトークンである場合、PowerShell パーサーは次の行を現在のコマンドに結合して、パイプラインの構築を続行します。
たとえば、次の単一行パイプラインです。
Command-1 | Command-2 | Command-3
次のように記述できます。
Command-1 |
Command-2 |
Command-3
後続の行の先頭のスペースは重要ではありません。 インデントを使用すると、読みやすさが向上します。
PowerShell 7 では、行の先頭にパイプライン文字を含むパイプラインの継続のサポートが追加されています。 次の例は、この新しい機能を使用する方法を示しています。
# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
| Get-Item | Where-Object FullName -match "AppData"
| Sort-Object FullName -Unique
# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
|
Get-Item | Where-Object FullName -match "AppData"
|
Sort-Object FullName -Unique
重要
シェルで対話的に作業する場合は、CtrlV を使用して貼り付ける場合にのみ、行の先頭にパイプラインを含むコードを+貼り付けます。 貼り付け操作を右クリックすると、一度に 1 行挿入されます。 行はパイプライン文字で終わらないので、PowerShell は入力が完了したと見なし、入力された行を実行します。
関連項目
フィードバック
フィードバックの送信と表示