about_Pipelines
簡短描述
將命令結合至 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。
例如,您可以使用管線將 Cmdlet 的 Get-Service
輸出傳送至 Start-Service
或 Stop-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-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 *
您也可以使用管線將原生命令的輸出傳送至 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
命令搭配 Full 或 Parameter 選項,以判斷 Cmdlet 接受管線輸入的參數。
例如,若要判斷 Cmdlet 哪些參數 Start-Service
接受管線輸入,請輸入:
Get-Help Start-Service -Full
或
Get-Help Start-Service -Parameter *
Cmdlet 的說明 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 參數產生關聯。
接受管線輸入的方法
Cmdlet 參數可以透過兩種不同的方式之一接受管線輸入:
ByValue:參數會接受符合預期 .NET 類型的值,或可轉換成該類型的值。
例如,的
Start-Service
Name 參數會依值接受管線輸入。 它可以接受可轉換成字串的字串物件或物件。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 參數來提交物件集合一樣。
例如,我們可以將服務的集合儲存至使用 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-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
InputObject 參數,則會Get-Member
以單一單位的形式接收 System.Diagnostics.Process 物件的數位。 它會顯示 物件陣列的屬性。 (記下 System.Object 類型 name.) 之後的陣列符號 ([]
)
例如
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-ItemProperty
Destination 參數。
...
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 會將輸入視為完成,並執行該行做為輸入。