共用方式為


關於管線

簡短描述

在 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參數,因為會透過管線提交指定的進程。

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

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-ServiceStart-ServiceStop-Service Cmdlet。

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

Get-Service wmi | Start-Service

如需另一個範例,您可以透過管道 Get-ItemGet-ChildItem PowerShell 登錄提供者中或的輸出傳送至 New-ItemProperty Cmdlet。 這個範例會將新的登錄專案NoOfEmployees(其值為8124)新增至MyCompany登錄機碼。

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

許多公用程式 Cmdlet,例如 Get-MemberWhere-ObjectSort-Object 、和,在 Group-Object Measure-Object 管線中幾乎是以獨佔方式使用。 您可以透過管道傳送任何物件類型至這些 Cmdlet。 這個範例示範如何依每個進程中的開啟控制碼數目,排序電腦上的所有處理常式。

Get-Process | Sort-Object -Property handles

您可以透過管線將物件傳送至格式設定、匯出和輸出 Cmdlet,例如 Format-ListFormat-TableExport-ClixmlExport-CSVOut-File

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

Get-Process winlogon | Format-List -Property *

有了一點實務,您會發現將簡單的命令結合成管線可節省時間和輸入,讓您的腳本更有效率。

管線的工作方式

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

接受管線輸入

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

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

Get-Help Start-Service -Full

Get-Help Start-Service -Parameter *

Start-Service Cmdlet 的說明會顯示只有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 類型或可以轉換成該類型的值。

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

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

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

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

參數繫結

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

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

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

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

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

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

一次處理

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

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 會一次將物件傳送至命令。 當您使用命令參數時,會以單一陣列物件的形式傳送物件。 這種次要差異會有顯著的後果。

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

在下列範例中,陣列和 hashtable 會以管道傳送至 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排除重複的專案,因此,如果物件全都屬於相同類型,則只會顯示一種物件類型。

不過,如果您使用的InputObject參數 Get-Member ,則會 Get-Member 收到一個系統的陣列,做為單一單位來處理物件。 它會顯示物件陣列的屬性。 (請注意,在 [] 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 無法讓輸送的物件與接收 Cmdlet 的參數產生關聯時,命令會失敗。

在下列範例中,我們會試著將登錄專案從一個登錄機碼移至另一個。 此 Get-Item Cmdlet 會取得目的地路徑,然後再以管道傳送至 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
}

追蹤的結果很冗長,但會顯示系結至 Cmdlet 的值, Get-Item 然後再將已命名的值系結至 Move-ItemProperty Cmdlet。

...
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

...
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的屬性。

使用 Get-Member 查看來自的物件屬性 Get-Item

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

輸出顯示專案是不具有目的地屬性的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 來取得我們想要移動之專案的路徑

例如,

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

內建行接續

如先前所討論,管線是由管線運算子()所連接的一連串命令 | ,通常是以單行撰寫。 不過,為了方便起見,PowerShell 可讓您將管線分割成多行。 當管道運算子是行上的最後一個 token 時,PowerShell 剖析器會將下一行加入至目前的命令,以繼續管線的結構。

例如,下列單行管線:

Command-1 | Command-2 | Command-3

可以撰寫為:

Command-1 |
  Command-2 |
    Command-3

後續幾行的前置空格並不重要。 縮排可增強可讀性。

另請參閱

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach