主題 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