about_Pipelines

簡単な説明

PowerShell でコマンドをパイプラインに結合する

長い説明

パイプラインは、パイプライン演算子 () によって接続される一連のコマンドです (|ASCII 124)。 各パイプライン演算子は、前のコマンドの結果を次のコマンドに送信します。

最初のコマンドの出力は、2 番目のコマンドへの入力として処理するために送信できます。 その出力は、さらに別のコマンドに送信できます。 その結果、一連の単純なコマンドで構成される複雑なコマンド チェーンまたは パイプライン が生成されます。

たとえば、次のように入力します。

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 または Stop-Service コマンドレットにStart-Serviceパイプできます。

次のパイプラインの例では、コンピューター上で WMI サービスを開始します。

Get-Service wmi | Start-Service

別の例として、 または Get-ChildItem PowerShell レジストリ プロバイダー内のGet-Item出力を コマンドレットにNew-ItemPropertyパイプできます。 次の使用例は、値 8124 の新しいレジストリ エントリ NoOfEmployeesMyCompany レジストリ キーに追加します。

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

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

Get-Process | Sort-Object -Property handles

オブジェクトを、、、 などのFormat-ListExport-CSVFormat-TableExport-ClixmlOut-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-HelpFull オプションまたは Parameter オプションと共に使用して、パイプライン入力を受け入れるコマンドレットのパラメーターを決定します。

たとえば、パイプライン入力を受け入れるコマンドレットのパラメーターを Start-Service 決定するには、次のように入力します。

Get-Help Start-Service -Full

または

Get-Help Start-Service -Parameter *

コマンドレットのヘルプは、Start-ServiceInputObject パラメーターと 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 型に一致する値、またはその型に変換できる値を受け取ります。

    たとえば、 の Name パラメーター Start-Service は、値によるパイプライン入力を受け入れます。 文字列オブジェクトまたは文字列に変換できるオブジェクトを受け取ることができます。

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

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

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

パラメーターのバインド

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

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

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

たとえば、 Start-Service コマンドレットには多くのパラメーターがありますが、パイプライン入力を受け入れるのは NameInputObject の 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

ただし、重要な違いがあります。 複数のオブジェクトを 1 つのコマンドにパイプすると、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-ProcessGet-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 つのオブジェクト型のみが表示されます。

ただし、 の InputObject パラメーターGet-Memberを使用すると、Get-MemberSystem.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 文字列に変換されます。 この変換により、生データ出力が破損する可能性があります。

回避策として、 または sh -c を使用してネイティブ コマンドをcmd.exe /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 がパイプライン入力のみを "プロパティ名で" 受け取っていることを示しています。 したがって、パイプされたオブジェクトには 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 では入力が完了したと見なされ、入力された行が実行されます。

関連項目