簡短描述
將命令結合至 PowerShell 中的管線
完整描述
管線是由管線運算符(|)所連接的一系列命令(ASCII 124)。 每個管線運算子都會將上述命令的結果傳送至下一個命令。
第一個命令的輸出可以傳送給第二個命令做為輸入進行處理。 而且該輸出可以傳送至另一個命令。 結果是一個複雜的命令鏈或 管道 ,它由一系列簡單的命令組成。
例如,
Command-1 | Command-2 | Command-3
在這裡範例中,Command-1 發出的物件會傳送至 Command-2。
Command-2 處理物件,並將其傳送至 Command-3。
Command-3 處理物件,並將其傳送至管線。 因為管線中沒有其他命令,因此結果會顯示在控制台中。
在管線中,命令會依左至右的順序進行處理。 處理會作為單一作業進行,而輸出會隨著產生而顯示出來。
以下是簡單的範例。 以下命令會獲取記事本的程序,然後將其停止。
例如,
Get-Process notepad | Stop-Process
第一個命令會使用 Get-Process Cmdlet 來取得代表記事本程序的物件。 它會使用管線運算符 (|) 將進程對象傳送至 Stop-Process Cmdlet,這會停止記事本程式。 請注意,Stop-Process 命令沒有 Name 或 ID 參數來指定進程,因為指定的進程是透過管線送出。
此管線範例會取得目前目錄中的文本檔、只選取長度超過 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。
例如,您可以使用管線將 Get-Service Cmdlet 的輸出傳送至 Start-Service 或 Stop-Service Cmdlet。
這個範例管線會在電腦上啟動 WMI 服務:
Get-Service wmi | Start-Service
例如,您可以使用管線將 PowerShell 登錄提供者內的 Get-Item 或 Get-ChildItem 的輸出傳送至 New-ItemProperty cmdlet。 本範例將一個新的註冊表項目 NoOfEmployees,其值為 8124,新增到 MyCompany 註冊表機碼中。
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
許多公用程式 Cmdlet,例如 Get-Member、Where-Object、Sort-Object、Group-Object和 Measure-Object 幾乎完全用於管線中。 您可以使用管線將任何物件類型傳送至這些 Cmdlet。 這個範例示範如何依每個進程中開啟的句柄數目排序計算機上的所有進程。
Get-Process | Sort-Object -Property handles
您可以使用管道將物件傳送至格式化、匯出和輸出的 Cmdlet,例如 Format-List、Format-Table、Export-Clixml、Export-CSV和 Out-File。
這個範例示範如何使用 Format-List Cmdlet 來顯示進程對象的屬性清單。
Get-Process winlogon | Format-List -Property *
透過一些練習,您會發現將簡單的命令結合到管線可節省時間和輸入,並讓您的腳本更有效率。
管線的運作方式
本節說明輸入物件如何系結至 Cmdlet 參數,並在管線執行期間進行處理。
接受管線輸入
若要支援管道傳送,接收 Cmdlet 必須有接受管線輸入的參數。 使用 Get-Help 命令搭配 Full 或 Parameter 選項,以判斷 Cmdlet 接受管線輸入的參數。
例如,若要判斷 Start-Service Cmdlet 接受管線輸入的參數,請輸入:
Get-Help Start-Service -Full
或
Get-Help Start-Service -Parameter *
Start-Service Cmdlet 的說明顯示只有 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 參數。
接受管線輸入的方法
Cmdlet 參數可以使用兩種不同的方式之一來接受管線輸入:
ByValue:參數會接受符合預期 .NET 類型或可轉換成該類型的值。
例如, 的
Start-Service參數會依值接受管線輸入。 它可以接受字串物件或可轉換為字串的物件。ByPropertyName:只有在輸入物件具有與 參數相同名稱的屬性時,參數才會接受輸入。
例如,
Start-Service的 Name 參數可以接受具有 Name 屬性的物件。 若要列出物件的屬性,請使用管線將它傳送至Get-Member。
有些參數可以透過值或屬性名稱來接受物件,這樣可以讓您更容易從管線輸入資料。
參數係結
當您使用管線將對象從某個命令傳送至另一個命令時,PowerShell 會嘗試將管道物件與接收 Cmdlet 的參數產生關聯。
PowerShell 的參數係結元件會根據下列準則,將輸入物件與 Cmdlet 參數產生關聯:
- 參數必須接受來自管線的輸入。
- 參數必須接受所傳送的物件類型,或可以轉換成預期型別的類型。
- 命令中未使用 參數。
例如,Start-Service Cmdlet 有許多參數,但其中只有兩個參數,Name 和 InputObject 接受管線輸入。
Name 參數會接受字串,而 InputObject 參數接受服務物件。 因此,您可以透過管線傳送字串、服務對象,以及具備可轉換為字串或服務對象屬性的物件。
PowerShell 會盡可能有效率地管理參數係結。 您無法建議或強制 PowerShell 系結至特定參數。 如果 PowerShell 無法繫結管道物件,命令就會失敗。
如需更詳細的綁定錯誤疑難排解資訊,請參閱本文後面的 管線錯誤分析。
一次一次處理
透過管道傳遞物件至命令,就像使用命令的參數來提交物件一樣。 讓我們看看管線範例。 在此範例中,我們使用管線來顯示服務對象的數據表。
Get-Service | Format-Table -Property Name, DependentServices
在功能上,這就像使用 的 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() 該方法。
在下列範例中,陣列和雜湊表會透過管線傳送至 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 :
zh-TW: 同樣地,如果您透過管線將多個程序物件從 Get-Process Cmdlet 傳送至 Get-Member Cmdlet,PowerShell 會將每個程序物件依序傳送到 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
...
備註
Get-Member 會排除重複專案,因此如果物件都是相同的類型,它只會顯示一個物件類型。
不過,如果您使用 的 Get-Member 參數,則 Get-Member 會以單一單位的形式接收 System.Diagnostics.Process 對象的陣列。 它會顯示 物件的陣列屬性。 (請注意,[] 類型名稱之後的陣列符號 ()。
例如,
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
}
追蹤的結果很冗長,但是它們會顯示系結至 Get-Item Cmdlet 的值,然後顯示系結至 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 物件,沒有 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 Cmdlet 中指定目的地,並使用 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
後續行的前導空格不重要。 縮排可增強可讀性。