about_pipelines
主題
about_pipelines
簡短描述
將 Windows PowerShell 中的命令組合成管線
完整描述
管線是指一系列由管線運算子 (|) (ASCII 124) 連接起來的命令, 每個管線運算子
會將前一個命令的結果傳送給下一個命令。
您可以使用管線,將某個命令輸出的物件傳送給另一個命令做為輸入,以便進行處
理。然後,您還可以將該命令的輸出再傳送給其他命令。得到的結果會是由一系列簡
單命令所組成、非常強大的命令鏈結 (或「管線」)。
例如,
命令 1 | 命令 2 | 命令 3
在此例中,命令 1 發出的物件會傳送給命令 2。命令 2 會處理這些物件,接著傳送
給命令 3。命令 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 物件 )
| ( .txt )
|
V
Where-Object {$_.length -gt 10000}
|
| (FileInfo 物件 )
| ( .txt )
| ( 長度 > 10000 )
|
V
Sort-Object -property Length
|
| (FileInfo 物件 )
| ( .txt )
| ( 長度 > 10000 )
| ( 依長度排序 )
|
V
Format-Table -property name, length
|
| (FileInfo 物件 )
| ( .txt )
| ( 長度 > 10000 )
| ( 依長度排序 )
| ( 在表格中格式化 )
|
V
名稱 長度
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
使用管線
Windows PowerShell Cmdlet 原本的設計就是可搭配管線使用。例如,通常可以針對
相同名詞,將 Get Cmdlet 的結果經由管線輸出至動作 Cmdlet (例如 Set、Start、
Stop 或 Rename Cmdlet)。
例如,您可以將 Get-Service Cmdlet 的任何服務經由管線輸出至 Start-Service
或 Stop-Service Cmdlet (但無法透過這個方法重新啟動已停用的服務)。
這個命令管線會啟動電腦上的 WMI 服務:
get-service wmi | start-service
取得和設定 Windows PowerShell 提供者之物件的 Cmdlet (例如 Item 和
ItemProperty Cmdlet) 也是設計用於管線。
例如,您可以將 Windows 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。
例如,您可以將電腦上的所有處理程序,經由管線輸出至 Sort-Object 命令,並依
據處理程序中的控制碼數目進行排序。
get-process | sort-object -property handles
此外,您也可以經由管線將任何物件輸出至格式化 Cmdlet (例如 Format-List 和
Format-Table)、Export Cmdlet (例如 Export-Clixml 和 Export-CSV),以及
Out Cmdlet (例如 Out-Printer)。
例如,您可以將 Winlogon 處理程序經由管線輸出至 Format-List Cmdlet,以清單顯
示處理程序的所有屬性。
get-process winlogon | format-list -property *
只要稍加練習,您會發現將幾個簡單命令組合成管線可以節省時間和打字,並讓您的
指令碼更有效率。
管線的運作方式
當您經由「管線」輸出物件時,代表將一個命令的輸出物件傳送給另一個命令,
Windows PowerShell 會嘗試將管線物件與接收端 Cmdlet 的其中一個參數產生關聯。
為了執行這項操作,負責將輸入物件與 Cmdlet 參數產生關聯的 Windows PowerShell
「參數繫結」元件會嘗試尋找符合下列條件的參數:
-- 參數必須接受來自管線的輸入 (並非全都是)
-- 參數必須接受要傳送的物件類型,或該物件可轉換的類型。
-- 參數不能正由命令使用中。
例如,Start-Service Cmdlet 有許多參數,但其中只有兩個參數 (Name 和
InputObject) 接受管線輸入。Name 參數接受字串,InputObject 參數接受服務
物件。因此,您可以將字串和服務物件 (以及具有可轉換為字串和服務物件之屬
性的物件) 經由管線輸出至 Start-Service。
如果 Windows PowerShell 的參數繫結元件無法將管線物件與接收端 Cmdlet 的參
數產生關聯,則命令會失敗,並且 Windows PowerShell 會提示您遺失參數值。
您無法強制參數繫結元件將管線物件與特定參數產生關聯,甚至不能提出建議的參
數。相反地,管線輸出是由元件的邏輯盡可能有效率地進行管理。
一次傳遞一個的處理程序
經由管線將物件輸出至命令,類似於使用命令的參數來提交物件。
例如,經由管線將代表電腦服務的物件輸出至 Format-Table 命令,如下所示:
get-service | format-table -property name,
dependentservices
類似於將服務物件儲存在變數中,然後使用 Format-Table 的 InputObject 參數來
提交服務物件。
$services = get-service
format-table -inputobject $services -property name,
dependentservices
或者將命令嵌入參數值中。
format-table -inputobject (get-service wmi) -property
name, dependentservices
不過,有一項重要差異。當您經由管線將多個物件輸出至命令時,
Windows PowerShell 會一次一個地將物件傳送給命令。使用命令參數時,會
是將物件視為單一陣列物件來傳送。
這項技術上的差異可能會造成有趣 (有時候也很有用) 的結果。
例如,如果您經由管線從 Get-Process Cmdlet 將多個處理程序物件輸出至
Get-Member Cmdlet,Windows PowerShell 會一次傳送一個處理程序物件至
Get-Member。
Get-Member 會顯示處理程序物件的 .NET 類別 (型別),以及其屬性和方法
(Get-Member 會刪除重複項目,所以如果物件都是同一種型別,則只會顯示一種物
件型別)。
在此例中,Get-Member 會顯示每個處理程序物件 (亦即 System.Diagnostics.
Process 物件) 的屬性和方法。
get-process | get-member
TypeName: System.Diagnostics.Process
名稱 MemberType 定義
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
然而,如果您使用 Get-Member 的 InputObject 參數,則 Get-Member 會收到視
同一個單位的 System.Diagnostics.Process 物件陣列,並顯示此物件陣列的屬性
(請注意 System.Object 型別名稱後面出現的陣列符號 [])。
get-member -inputobject (get-process)
TypeName: System.Object[]
名稱 MemberType 定義
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
...
這個結果可能不是您要的,但當您了解其涵義後,仍然可以使用。例如,處理程序物
件的陣列具有 Count 屬性,可以用來計數電腦的處理程序數目。
(get-process).count
這項區別很重要,所以請記住,當您經由管線將物件輸出至 Cmdlet 時,是一次傳遞
一個物件。
接受管線輸入
為了接收管線中的物件,接收端 Cmdlet 必須具有接受管線輸入的參數。您可以使用
Get-Help 命令搭配 Full 或 Parameter 參數,判斷哪個 Cmdlet 參數 (若有的話)
接受管線輸入。
在 Get-Help 的預設顯示中,[接受管線輸入] 項目會出現在參數屬性表格中。您必
須使用 Get-Help Cmdlet 的 Full 或 Parameter 參數,才會出現此表格。
例如,若要判斷 Start-Service Cmdlet 的哪些參數接受管線輸入,請輸入:
get-help start-service -full
get-help start-service -parameter *
例如,Start-Service Cmdlet 的說明顯示 Name 和 InputObject 參數接受管線輸
入 ("true")。所有其他參數在 [接受管線輸入?] 列中的值都是 "false"。
-name <string[]>
指定要啟動之服務的服務名稱。
參數名稱為選擇性。可使用 "-Name" 或其別名 "-ServiceName",亦可省略
參數名稱。
必要? true
位置? 1
預設值
--> 接受管線輸入? true (ByValue, ByPropertyName)
接受萬用字元? true
-inputObject <ServiceController[]>
指定表示要啟動之服務的 ServiceController 物件。請輸入包含物件的變
數,或輸入可取得物件的命令或運算式。
必要? false
位置? named
預設值
--> 接受管線輸入? true (ByValue)
接受萬用字元? false
這表示您可以透過管線將物件 (PsObjects) 傳送至 Where-Object Cmdlet,並且
Windows PowerShell 會將物件與 InputObject 參數產生關聯。
接受管線輸入的方法
Cmdlet 參數可以接受兩種管線輸入方法的其中一種:
-- ByValue:「根據值」來接受輸入的參數,可以接受參數值具有相同 .NET 型別
的管線物件,或可轉換為該型別的物件。
例如,Start-Service 的 Name 參數即根據值接受管線輸入, 它可以接受字串物
件或可轉換為字串的物件。
-- ByPropertyName:「根據屬性名稱」來接受輸入的參數,只有在管線物件的某個
屬性具有與該參數相同的名稱時,才會接受該物件。
例如,Start-Service 的 Name 參數可以接受具有 Name 屬性的物件。
(若要列出物件的屬性,請經由管線將物件輸出至 Get-Member)。
有些參數可以根據值來接受物件,也可以根據屬性名稱。這些參數就是為了能夠輕
鬆接受來自管線的輸入而設計。
調查管線錯誤
如果命令因為管線錯誤而發生失敗,您可以調查失敗原因並重新撰寫
命令。
例如,下列命令會使用 Get-Item Cmdlet 取得目的地路徑,然後經由管線將路徑輸
出至 Move-ItemProperty 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
這個命令會失敗,Windows PowerShell 會顯示下列錯誤訊息:
Move-ItemProperty : 輸入物件無法繫結到該命令的任何參數,可能是因為該命
令不接受管線輸入,或者此輸入及其屬性不符合任何接受管線輸入的參數。
位於第 1 行,第 23 個字元
+ $a | move-itemproperty <<<< -path
hklm:\software\mycompany\design -name product
若要進行調查,請使用 Trace-Command Cmdlet 追蹤 Windows PowerShell 的參數繫
結元件。下列命令會在命令進行處理時追蹤參數繫結元件。它使用 -pshost 參數將
結果顯示在主控台,並使用 -filepath 命令將這些結果傳送至 debug.txt 檔案,供
日後參考之用。
trace-command -name parameterbinding -expression {get-item -path
hklm:\software\mycompany\sales | move-itemproperty -path
hklm:\software\mycompany\design -name product} -pshost -filepath
debug.txt
追蹤結果很冗長,但會顯示將繫結至 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 的 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 參數的屬性。下
列命令會取得 Destination 參數的詳細資訊。
get-help move-itemproperty -parameter destination
結果顯示,Destination 只接受「根據屬性名稱」的管線輸入。
也就是說,管線物件必須具有名為 Destination 的屬性。
-destination <字串>
指定目的地位置的路徑。
必要? true
位置? 2
預設值
接受管線輸入? true (ByPropertyName)
接受萬用字元? true
若要查看將經由管線輸出至 Move-ItemProperty Cmdlet 之物件的屬性,請經由管線
將該物件輸出至 Get-Member Cmdlet。下列命令會將命令第一個部分的結果經由管線
輸出至 Get-Member Cmdlet。
get-item -path hklm:\software\mycompany\sales | get-member
輸出顯示此項目是 Microsoft.Win32.RegistryKey,不具有 Destination 屬性。
這說明了命令失敗的原因。
若要修正命令,必須在 Move-ItemProperty Cmdlet 中指定目的地。我們可以使用
Get-ItemProperty 命令來取得路徑,但必須在命令的 Move-ItemProperty 這部分
中指定名稱和目的地。
get-item -path hklm:\software\mycompany\design |
move-itemproperty -dest hklm:\software\mycompany\design -name product
若要確認命令是否執行成功,請使用 Get-ItemProperty 命令:
get-itemproperty hklm:\software\mycompany\sales
結果顯示 Product 登錄項目已移至 Sales 機碼中。
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\
software\mycompany\sales
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\
software\mycompany
PSChildName : sales
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
Product : 18
請參閱
about_objects
about_parameters
about_command_syntax
help about_foreach