about_Pipelines

簡短描述

將命令結合至 PowerShell 中的管線

完整描述

管線是由管線運算子所連接的一系列命令, | () (ASCII 124) 。 每個管線運算子都會將上述命令的結果傳送至下一個命令。

第一個命令的輸出可以傳送,以作為第二個命令的輸入進行處理。 而且該輸出可以傳送至另一個命令。 結果是由一系列簡單命令組成的複雜命令鏈結或 管線

例如,

Command-1 | Command-2 | Command-3

在此範例中,發出的物件 Command-1 會傳送至 Command-2Command-2 處理 物件,並將其傳送至 Command-3Command-3 處理物件,並將其傳送至管線。 因為管線中沒有其他命令,所以結果會顯示在主控台中。

在管線中,命令會依左至右的順序進行處理。 處理會當做單一工作處理,而且輸出會在產生時顯示。

以下是一個簡單範例。 下列命令會取得記事本程式,然後停止它。

例如,

Get-Process notepad | Stop-Process

第一個命令會 Get-Process 使用 Cmdlet 來取得代表記事本進程的 物件。 它會使用管線運算子 (|) 將進程物件傳送至 Stop-Process Cmdlet,這會停止記事本進程。 請注意, Stop-Process 命令沒有 NameID 參數可指定進程,因為指定的進程是透過管線送出。

此管線範例會取得目前目錄中的文字檔、只選取長度超過 10,000 個位元組的檔案、依長度排序,以及顯示資料表中每個檔案的名稱和長度。

Get-ChildItem -Path *.txt |
  Where-Object {$_.length -gt 10000} |
    Sort-Object -Property length |
      Format-Table -Property name, length

此管線是由指定順序中的四個命令所組成。 下圖顯示每個命令的輸出,因為它傳遞至管線中的下一個命令。

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 Cmdlet 都是設計來支援管線。 在大部分情況下,您可以將Get Cmdlet 的結果傳送至相同名詞的另一個 Cmdlet。 例如,您可以使用管線將 Cmdlet 的 Get-Service 輸出傳送至 Start-ServiceStop-Service Cmdlet。

此範例管線會在電腦上啟動 WMI 服務:

Get-Service wmi | Start-Service

例如,您可以將 的輸出 Get-Item 管線傳送至 New-ItemProperty Cmdlet,或在 Get-ChildItem PowerShell 登錄提供者內。 本範例會將值為8124的新登錄專案NoOfEmployees新增至MyCompany登錄機碼。

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

許多公用程式 Cmdlet,例如 Get-MemberWhere-ObjectSort-ObjectGroup-ObjectMeasure-Object 幾乎完全用於管線中。 您可以使用管線將任何物件類型傳送至這些 Cmdlet。 此範例示範如何依每個進程中開啟的控制碼數目,排序電腦上的所有進程。

Get-Process | Sort-Object -Property handles

您可以使用管線將物件傳送至格式、匯出和輸出 Cmdlet,例如 Format-ListFormat-Table 、、 Export-ClixmlExport-CSVOut-File

此範例示範如何使用 Format-List Cmdlet 來顯示進程物件的屬性清單。

Get-Process winlogon | Format-List -Property *

您也可以使用管線將原生命令的輸出傳送至 PowerShell Cmdlet。 例如:

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

在練習中,您會發現將簡單的命令結合至管線可節省時間和輸入,並讓您的腳本更有效率。

管線的運作方式

本節說明輸入物件如何系結至 Cmdlet 參數,並在管線執行期間進行處理。

接受管線輸入

若要支援管線,接收 Cmdlet 必須具有可接受管線輸入的參數。 搭配[完整] 或 [參數] 選項使用 Get-Help 命令,以判斷 Cmdlet 接受管線輸入的參數。

例如,若要判斷 Cmdlet 哪些參數 Start-Service 接受管線輸入,請輸入:

Get-Help Start-Service -Full

Get-Help Start-Service -Parameter *

Cmdlet 的說明 Start-Service 會顯示只有 InputObjectName 參數接受管線輸入。

-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 會嘗試將物件與 InputObjectName 參數產生關聯。

接受管線輸入的方法

Cmdlet 參數可以接受兩種不同方式之一的管線輸入:

  • ByValue:參數接受符合預期的 .NET 類型或可轉換成該類型的值。

    例如,的 Start-ServiceName參數會依值接受管線輸入。 它可以接受可轉換成字串的字串物件或物件。

  • ByPropertyName:只有在輸入物件具有與參數相同名稱的屬性時,參數才會接受輸入。

    例如,的 Start-Service Name 參數可以接受具有 Name 屬性的物件。 若要列出物件的屬性,請將它管線傳送至 Get-Member

某些參數可以同時接受值或屬性名稱的物件,讓您更輕鬆地從管線取得輸入。

參數繫結

當您將物件從一個命令傳送至另一個命令時,PowerShell 會嘗試將管線物件與接收 Cmdlet 的參數產生關聯。

PowerShell 的參數系結元件會根據下列準則,將輸入物件與 Cmdlet 參數產生關聯:

  • 參數必須接受來自管線的輸入。
  • 參數必須接受要傳送的物件類型,或可轉換成預期型別的類型。
  • 參數未用於 命令中。

例如, Start-Service Cmdlet 有許多參數,但只有兩個參數: NameInputObject 接受管線輸入。 Name參數會接受字串,而 InputObject參數會採用服務物件。 因此,您可以使用可轉換成字串或服務物件的屬性,使用管線傳送字串、服務物件和服務物件。

PowerShell 盡可能有效率地管理參數系結。 您無法建議或強制 PowerShell 系結至特定參數。 如果 PowerShell 無法系結管線物件,此命令就會失敗。

如需疑難排解系結錯誤的詳細資訊,請參閱本文稍後 的調查管線錯誤

一次一次處理

將物件管線傳送至命令,就像使用 命令的參數來提交物件一樣。 讓我們看看管線範例。 在此範例中,我們使用管線來顯示服務物件的資料表。

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

不過,有一個重要的差異。 當您使用管線將多個物件傳送至命令時,PowerShell 會一次將物件傳送至命令一個。 當您使用命令參數時,物件會以單一陣列物件的形式傳送。 此次要差異有顯著的結果。

執行管線時,PowerShell 會自動列舉任何實 IEnumerable 作 介面的類型,並一次透過管線傳送成員。 例外狀況是 [hashtable] ,需要呼叫 GetEnumerator() 方法。

在下列範例中,陣列和雜湊表會透過管線傳送至 Measure-Object Cmdlet,以計算從管線接收的物件數目。 陣列具有多個成員,而雜湊表具有多個索引鍵/值組。 一次只列舉一個陣列。

@(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 Cmdlet 傳送至 Get-Member Cmdlet,PowerShell 就會一次傳送每個進程物件至 Get-MemberGet-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 排除重複專案,因此如果物件全都是相同的類型,它只會顯示一個物件類型。

不過,如果您使用 的 Get-MemberInputObject參數,則會 Get-Member 以單一單位的形式接收System.Diagnostics.Process物件的陣列。 它會顯示 物件陣列的屬性。 (注意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

請務必記住,傳送至管線的物件會一次傳遞一個。

在管線中使用原生命令

PowerShell 可讓您在管線中包含原生外部命令。 不過,請務必注意,PowerShell 的管線是物件導向,且不支援原始位元組資料。

從輸出原始位元組資料的原生程式管線或重新導向輸出,會將輸出轉換成 .NET 字串。 此轉換可能會導致原始資料輸出損毀。

因應措施是,使用 cmd.exe /c 或 和 使用 | 原生殼層所提供的 和 > 運算子來 sh -c 呼叫原生命令。

調查管線錯誤

當 PowerShell 無法將管道物件與接收 Cmdlet 的參數產生關聯時,命令會失敗。

在下列範例中,我們會嘗試將登錄專案從一個登錄機碼移至另一個登錄機碼。 Cmdlet Get-Item 會取得目的地路徑,然後傳送至 Move-ItemProperty Cmdlet。 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 Cmdlet 來追蹤 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 Cmdlet 的值,然後顯示系結至 Cmdlet 的 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使用 Cmdlet 來檢視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

若要修正命令,我們必須在 Cmdlet 中 Move-ItemProperty 指定目的地,並使用 Get-Item 來取得我們想要移動之專案的 Path

例如,

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

內建行接續

如先前所述,管線是由管線運算子所連接的一系列命令, (|) ,通常是以單行撰寫。 不過,為了方便閱讀,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貼上時,才會在行開頭貼上管線的程式碼。 以滑鼠右鍵按一下貼上作業,一次插入一行。 由於該行不是以管線字元結尾,因此 PowerShell 會將輸入視為完成,並執行該行做為輸入。

另請參閱