次の方法で共有


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 の新しいレジストリ エントリ NoOfEmployeesMyCompany レジストリ キーに追加します。

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

Get-MemberWhere-ObjectSort-ObjectGroup-ObjectMeasure-Objectなどのユーティリティ コマンドレットの多くは、パイプラインでのみ使用されます。 任意の種類のオブジェクトをこれらのコマンドレットにパイプできます。 この例では、コンピューター上のすべてのプロセスを、各プロセスで開いているハンドルの数で並べ替える方法を示します。

Get-Process | Sort-Object -Property handles

オブジェクトを、 Format-ListFormat-TableExport-ClixmlExport-CSVOut-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-ServiceName パラメーターは、値によるパイプライン入力を受け入れます。 文字列オブジェクトまたは文字列に変換できるオブジェクトを受け取ることができます。

  • ByPropertyName: パラメーターは、入力オブジェクトにパラメーターと同じ名前のプロパティがある場合にのみ入力を受け入れます。

    たとえば、 Start-Service の Name パラメーターは、 Name プロパティを持つオブジェクトを受け取ることができます。 オブジェクトのプロパティを一覧表示するには、パイプ処理して Get-Memberします。

一部のパラメーターでは、値またはプロパティ名の両方でオブジェクトを受け取ることができ、パイプラインからの入力を簡単に行うことができます。

パラメーター バインド

あるコマンドから別のコマンドにオブジェクトをパイプすると、PowerShell はパイプされたオブジェクトを受信コマンドレットのパラメーターに関連付けようとします。

PowerShell のパラメーター バインド コンポーネントは、次の条件に従って、入力オブジェクトをコマンドレット パラメーターに関連付けます。

  • パラメーターは、パイプラインからの入力を受け入れる必要があります。
  • パラメーターは、送信されるオブジェクトの型、または予想される型に変換できる型を受け入れる必要があります。
  • パラメーターはコマンドで使用されませんでした。

たとえば、 Start-Service コマンドレットには多くのパラメーターがありますが、パイプライン入力を受け入れるパラメーターは 2 つだけですが、 NameInputObjectName パラメーターは文字列を受け取り、InputObject パラメーターはサービス オブジェクトを受け取ります。 そのため、文字列、サービス オブジェクト、および文字列またはサービス オブジェクトに変換できるプロパティを持つオブジェクトをパイプできます。

PowerShell は、可能な限り効率的にパラメーター バインドを管理します。 PowerShell で特定のパラメーターにバインドするように提案したり強制したりすることはできません。 PowerShell でパイプされたオブジェクトをバインドできない場合、コマンドは失敗します。

バインド エラーのトラブルシューティングの詳細については、この記事で後述する「 Investigating Pipeline Errors 」を参照してください。

一度に 1 回の処理

コマンドへのオブジェクトのパイプ処理は、コマンドのパラメーターを使用してオブジェクトを送信するのとよく似ています。 パイプラインの例を見てみましょう。 この例では、パイプラインを使用してサービス オブジェクトのテーブルを表示します。

Get-Service | Format-Table -Property Name, DependentServices

機能的には、これは、Format-TableInputObject パラメーターを使用してオブジェクト コレクションを送信するようなものです。

たとえば、 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-MemberInputObject パラメーターを使用する場合、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-ItemPropertyDestination パラメーターへのパスのバインドが失敗したことを示します。

...
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 では入力が完了したと見なされ、入力された行が実行されます。

関連項目