about_Pipelines
簡単な説明
PowerShell でコマンドをパイプラインに結合する
詳細な説明
パイプラインは、パイプライン演算子 (|
) (ASCII 124) によって接続される一連のコマンドです。 各パイプライン演算子は、前のコマンドの結果を次のコマンドに送信します。
最初のコマンドの出力は、2 番目のコマンドへの入力として処理するために送信できます。 その出力は、さらに別のコマンドに送信できます。 その結果、一連の単純なコマンドで構成される複雑なコマンド チェーンまたは pipeline になります。
たとえば、 にします。
Command-1 | Command-2 | Command-3
この例では、出力 Command-1
オブジェクトが Command-2
に送信されます。
Command-2
はオブジェクトを処理し、 Command-3
に送信します。 Command-3
はオブジェクトを処理し、パイプラインに送信します。 パイプラインにはこれ以上コマンドがないため、結果はコンソールに表示されます。
パイプラインでは、コマンドは左から右に順番に処理されます。 処理は 1 つの操作として処理され、出力は生成時に表示されます。
単純な例を次に示します。 次のコマンドは、メモ帳プロセスを取得し、停止します。
たとえば、 にします。
Get-Process notepad | Stop-Process
最初のコマンドでは、 Get-Process
コマンドレットを使用してメモ帳プロセスを表すオブジェクトを取得します。 パイプライン演算子 (|
) を使用してプロセス オブジェクトを Stop-Process
コマンドレットに送信し、メモ帳プロセスを停止します。 指定したプロセスはパイプラインを介して送信されるため、 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 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
コマンドレットの出力を Start-Service
または Stop-Service
コマンドレットにパイプできます。
次のパイプラインの例では、コンピューター上で WMI サービスを開始します。
Get-Service wmi | Start-Service
別の例として、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
などのユーティリティ コマンドレットの多くは、パイプラインでのみ使用されます。 任意の種類のオブジェクトをこれらのコマンドレットにパイプできます。 この例では、コンピューター上のすべてのプロセスを、各プロセスで開いているハンドルの数で並べ替える方法を示します。
Get-Process | Sort-Object -Property handles
オブジェクトを、 Format-List
、 Format-Table
、 Export-Clixml
、 Export-CSV
、 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
重要
Success および Error ストリームは、他のシェルの 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-Service
の Name パラメーターは、値によるパイプライン入力を受け入れます。 文字列オブジェクトまたは文字列に変換できるオブジェクトを受け取ることができます。ByPropertyName: パラメーターは、入力オブジェクトにパラメーターと同じ名前のプロパティがある場合にのみ入力を受け入れます。
たとえば、
Start-Service
の Name パラメーターは、 Name プロパティを持つオブジェクトを受け取ることができます。 オブジェクトのプロパティを一覧表示するには、パイプ処理してGet-Member
します。
一部のパラメーターでは、値またはプロパティ名の両方でオブジェクトを受け取ることができ、パイプラインからの入力を簡単に行うことができます。
パラメーター バインド
あるコマンドから別のコマンドにオブジェクトをパイプすると、PowerShell はパイプされたオブジェクトを受信コマンドレットのパラメーターに関連付けようとします。
PowerShell のパラメーター バインド コンポーネントは、次の条件に従って、入力オブジェクトをコマンドレット パラメーターに関連付けます。
- パラメーターは、パイプラインからの入力を受け入れる必要があります。
- パラメーターは、送信されるオブジェクトの型、または予想される型に変換できる型を受け入れる必要があります。
- パラメーターはコマンドで使用されませんでした。
たとえば、 Start-Service
コマンドレットには多くのパラメーターがありますが、パイプライン入力を受け入れるパラメーターは 2 つだけですが、 Name と InputObject 。 Name パラメーターは文字列を受け取り、InputObject パラメーターはサービス オブジェクトを受け取ります。 そのため、文字列、サービス オブジェクト、および文字列またはサービス オブジェクトに変換できるプロパティを持つオブジェクトをパイプできます。
PowerShell は、可能な限り効率的にパラメーター バインドを管理します。 PowerShell で特定のパラメーターにバインドするように提案したり強制したりすることはできません。 PowerShell でパイプされたオブジェクトをバインドできない場合、コマンドは失敗します。
バインド エラーのトラブルシューティングの詳細については、この記事で後述する「 Investigating Pipeline Errors 」を参照してください。
一度に 1 回の処理
コマンドへのオブジェクトのパイプ処理は、コマンドのパラメーターを使用してオブジェクトを送信するのとよく似ています。 パイプラインの例を見てみましょう。 この例では、パイプラインを使用してサービス オブジェクトのテーブルを表示します。
Get-Service | Format-Table -Property Name, DependentServices
機能的には、これは、Format-Table
の InputObject パラメーターを使用してオブジェクト コレクションを送信するようなものです。
たとえば、 InputObject パラメーターを使用して渡される変数にサービスのコレクションを保存できます。
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
または、 InputObject パラメーターにコマンドを埋め込むことができます。
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
ただし、重要な違いがあります。 複数のオブジェクトを 1 つのコマンドにパイプ処理すると、PowerShell は一度に 1 つずつオブジェクトをコマンドに送信します。 コマンド パラメーターを使用すると、オブジェクトは 1 つの配列オブジェクトとして送信されます。 この小さな違いは大きな影響を及ぼします。
パイプラインを実行すると、PowerShell は、 IEnumerable
インターフェイスまたはその一般的な対応するインターフェイスを実装するすべての型を自動的に列挙します。 列挙された項目は、パイプラインを通じて一度に 1 つずつ送信されます。 PowerShell では、Rows
プロパティSystem.Data.DataTable 型も列挙されます。
自動列挙にはいくつかの例外があります。
- ハッシュ テーブル、
IDictionary
インターフェイスまたはそのジェネリック インターフェイスを実装する型、および System.Xml.XmlNode 型のGetEnumerator()
メソッドを呼び出す必要があります。 - System.String クラスは
IEnumerable
を実装しますが、PowerShell は文字列オブジェクトを列挙しません。
次の例では、配列とハッシュテーブルを 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
...
Note
Get-Member
は重複を排除するため、オブジェクトがすべて同じ型の場合は、1 つのオブジェクト型のみが表示されます。
ただし、Get-Member
の InputObject パラメーターを使用する場合、Get-Member
は、System.Diagnostics.Process オブジェクトの配列を 1 つの単位として受け取ります。 オブジェクトの配列のプロパティが表示されます。 (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 文字列に変換されます。 この変換により、生データ出力が破損する可能性があります。
ただし、PowerShell 7.4 では、ネイティブ コマンドの stdout ストリームをファイルにリダイレクトするとき、またはバイト ストリーム データをネイティブ コマンドの stdin ストリームにパイプするときにバイト ストリーム データを保持するPSNativeCommandPreserveBytePipe
試験的機能が追加されました。
たとえば、ネイティブ コマンド curl
を使用すると、バイナリ ファイルをダウンロードし、それをディスクにリダイレクトを使用して保存することができます。
$uri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz'
# native command redirected to a file
curl -s -L $uri > powershell.tar.gz
バイト ストリーム データは、別のネイティブ コマンドの stdin ストリームにパイプすることもできます。 次の例では、curl
を使用して zip 形式の TAR ファイルをダウンロードしています。 ダウンロードしたファイル データは、tar
コマンドにストリーミングされ、アーカイブの内容が抽出されます。
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
PowerShell コマンドのバイト ストリーム出力をネイティブ コマンドの入力にパイプすることもできます。 次の例では、Invoke-WebRequest
を使用して、前の例と同じ TAR ファイルをダウンロードしています。
# byte stream piped to a native command
(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
この機能では、stderr 出力を stdout にリダイレクトするとき、バイト ストリーム データをサポートしません。 stderr および stdout ストリームを結合すると、結合されたストリームは文字列データとして扱われます。
パイプライン エラーの調査
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`]
...
最後に、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 パラメーターの属性を表示します。
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 がパイプライン入力のみを "プロパティ名で" 受け取っていることを示しています。 したがって、パイプされたオブジェクトには、 Destination という名前のプロパティが必要です。
Get-Member
を使用して、Get-Item
から取得されるオブジェクトのプロパティを確認します。
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
出力は、アイテムが Microsoft.Win32.RegistryKey オブジェクトであり、 Destination プロパティを持っていないことを示しています。 これは、コマンドが失敗した理由を説明します。
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
を使用して移動する項目の Path を取得する必要があります。
たとえば、 にします。
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
重要
シェルで対話形式で作業する場合は、 Ctrl+V を使用して貼り付ける場合にのみ、行の先頭にパイプラインを含むコードを貼り付けます。 貼り付け操作を右クリックすると、一度に 1 行ずつ挿入されます。 行はパイプライン文字で終わらないため、PowerShell では入力が完了したと見なされ、入力された行が実行されます。
関連項目
PowerShell