iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0

在本章中,我們會深入探索管線,並挖掘一些更強大的能力,讓你能以更省力的方式,正確地在各個命令之間傳遞資料。

在 PowerShell 中,commandA | commandB 是透過管道( pipeline )進行資料的傳遞,而這個過程就是「管道參數綁定」( Pipeline Parameter Binding )。這個機制讓前一個指令的輸出自動地傳遞給下一個指令,而不需要額外的變數或參數傳遞,實現自動化處理流程。

Pipeline Parameter Binding 工作原理

管道參數綁定的核心在於 PowerShell 會嘗試將前一個命令的輸出( commandA )與下一個命令的參數( commandB )自動匹配。這個匹配過程主要有兩種方式:

ByValue(按值匹配)

PowerShell 會檢查 commandB 的參數是否可以直接接受 commandA 的輸出類型。如果匹配成功,就直接將資料傳遞給該參數。

範例說明

以下範例中,Get-Process 輸出的是 System.Diagnostics.Process 物件,Stop-Process 可以接受 Process 類型的物件作為參數,因此它們可以直接按值匹配。

# 取得正在執行的 notepad 進程並停止
Get-Process -Name Telegram | Stop-Process

解釋

  1. Get-Process -Name notepad 取得名稱為 notepad 的進程,輸出的是 Process 物件。
    # 使用 Get-Process 並查看其輸出物件的類型,
    PS /Users/kanglin/code/30days> Get-Process Telegram | gm
    
       TypeName: System.Diagnostics.Process
    
  2. Stop-Process 的 -InputObject 參數可以直接接受 Process 類型的物件,這就是 ByValue 的匹配過程。
    # 查看 Stop-Process 指令的參數資訊,特別是 InputObject
    PS /Users/kanglin/code/30days> Get-Help Stop-Process -Parameter InputObject
    
    -InputObject <System.Diagnostics.Process[]>
        Specifies the process objects to stop. 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
    

一般來說,具有相同名詞的命令(如 Get-Process 和 Stop-Process),通常都能夠以 ByValue 方式將資料傳輸給彼此。

ByPropertyName(按屬性名稱匹配)

如果 commandA 輸出的對象是物件,PowerShell 會檢查物件的屬性名稱是否與 commandB 參數名稱相同。若找到相同的名稱,就將相應的屬性值傳遞給該參數。

範例說明

以下範例中,Select-Object 用來建立一個包含 Id 和 Name 屬性的自定義物件,然後將其傳遞給 Stop-Process,其中 Id 屬性會匹配到 Stop-Process 的 -Id 參數。

# 建立一個自定義物件,然後使用 Stop-Process 按物件屬性名稱停止進程
$processInfo = Get-Process -Name Telegram | Select-Object Id, Name
$processInfo | Stop-Process

解釋

  1. Get-Process -Name notepad | Select-Object Id, Name 取得 notepad 進程並選取 Id 和 Name 屬性,輸出自定義物件。
  2. 當自定義物件通過管道傳遞給 Stop-Process 時,PowerShell 檢查輸出的物件是否有 Id 屬性,並將其值綁定到 Stop-Process 的 -Id 參數,這就是 ByPropertyName 的匹配過程。

當 Cmdlet 沒有提供 InputObject 屬性,建議手順

透過 Get-Command 查看參數的詳細資訊

PS /Users/kanglin/code/30days> (Get-Command Stop-Process).Parameters

Key                 Value
---                 -----
Name                System.Management.Automation.ParameterMetadata
Id                  System.Management.Automation.ParameterMetadata
InputObject         System.Management.Automation.ParameterMetadata
PassThru            System.Management.Automation.ParameterMetadata
Force               System.Management.Automation.ParameterMetadata
Verbose             System.Management.Automation.ParameterMetadata
Debug               System.Management.Automation.ParameterMetadata
ErrorAction         System.Management.Automation.ParameterMetadata
WarningAction       System.Management.Automation.ParameterMetadata
InformationAction   System.Management.Automation.ParameterMetadata
ProgressAction      System.Management.Automation.ParameterMetadata
ErrorVariable       System.Management.Automation.ParameterMetadata
WarningVariable     System.Management.Automation.ParameterMetadata
InformationVariable System.Management.Automation.ParameterMetadata
OutVariable         System.Management.Automation.ParameterMetadata
OutBuffer           System.Management.Automation.ParameterMetadata
PipelineVariable    System.Management.Automation.ParameterMetadata
WhatIf              System.Management.Automation.ParameterMetadata
Confirm             System.Management.Automation.ParameterMetadata

檢查管道輸入屬性

# 顯示 cmdlet 所有參數,並檢查其管道輸入屬性

PS /Users/kanglin/code/30days> (Get-Command Stop-Process).Parameters.GetEnumerator() | ForEach-Object {
>>     [PSCustomObject]@{
>>         Name             = $_.Key
>>         AcceptsPipeline  = $_.Value.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | Select-Object -ExpandProperty ValueFromPipeline
>>         AcceptsProperty  = $_.Value.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | Select-Object -ExpandProperty ValueFromPipelineByPropertyName
>>     }
>> }

Name                AcceptsPipeline AcceptsProperty
----                --------------- ---------------
Name                          False            True
Id                            False            True
InputObject                    True           False
PassThru                      False           False
Force                         False           False
Verbose                       False           False
Debug                         False           False
ErrorAction                   False           False
WarningAction                 False           False
InformationAction             False           False
ProgressAction                False           False
ErrorVariable                 False           False
WarningVariable               False           False
InformationVariable           False           False
OutVariable                   False           False
OutBuffer                     False           False
PipelineVariable              False           False
WhatIf                        False           False
Confirm                       False           False

  • AcceptsPipeline:顯示是否支援按值綁定(ByValue)。
  • AcceptsProperty:顯示是否支援按屬性名稱綁定(ByPropertyName)。

這可以幫助你清楚地看到哪些參數支援管道輸入,即使 Get-Help 沒有明確說明。


自定義 Aliase

透過這個案例,理解如何將 Import-CSV 的 output 透過 pipeline 使用 PropertyName 傳遞給 New-Alias

建立 CSV 格式的 txt file

PS /Users/kanglin/code/30days> cat ./aliases.txt
Name,Value
d,Get-ChildItem
sel,Select-Object
go,Invoke-Command

透過 Import-CSV 將文件內容轉化成 Object

# 匯入
PS /Users/kanglin/code/30days> Import-Csv ./aliases.txt

Name Value
---- -----
d    Get-ChildItem
sel  Select-Object
go   Invoke-Command

# 檢查屬性
PS /Users/kanglin/code/30days> Import-Csv ./aliases.txt | gm

   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Name        NoteProperty string Name=d
Value       NoteProperty string Value=Get-ChildItem

透過 New-Alias 接收 Import-CSV 傳遞的物件並建立新的 alias

透過 get-help 檢查 New-Alias 的 Syntax

-Name & -Value 對應著 Import-CSV 的 output object 屬性裡的 Name & Valuee

PS /Users/kanglin/code/30days> get-help New-Alias

NAME
    New-Alias

SYNOPSIS
    Creates a new alias.

SYNTAX
    New-Alias [-Name] <System.String> [-Value] <System.String> [-Description <System.String>] [-Force] [-Option {None | ReadOnly | Constant | Private | AllScope | Unspecified}] [-PassThru] [-Scope <System.St
    ring>] [-Confirm] [-WhatIf] [<CommonParameters>]

檢查 -Name & -Value 是否能接受 ByPropertyName 方式所輸入的內容

PS /Users/kanglin/code/30days> get-help New-Alias -Parameter Name

-Name <System.String>
    Specifies the new alias. You can use any alphanumeric characters in an alias, but the first character cannot be a number.

    Required?                    true
    Position?                    0
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

PS /Users/kanglin/code/30days> get-help New-Alias -Parameter Value

-Value <System.String>
    Specifies the name of the cmdlet or command element that is being aliased.

    Required?                    true
    Position?                    1
    Default value                None
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

建立 alias

Import-Csv ./aliases.txt | New-Alias

結果會產生三個全新的別名,名為 d、sel 和 go,分別對應 Get-ChildItem、Select-Object、Invoke-Command 的命令。


總結

今天探討了 PowerShell 的管道參數綁定機制,展示了如何透過 ByValue 和 ByPropertyName 自動匹配前後命令的輸入和輸出。這種自動化的資料傳遞方式大大簡化了命令的使用,省去了手動處理變數和參數的麻煩。特別是當命令間具有相似結構或屬性時,這些匹配機制顯得更加方便和直觀。


明日主題

Day 11 - 深度探索管線 Part 2


上一篇
Day 9 - 物件:另一種形式的資料
下一篇
Day 11 - 深度探索管線 Part 2
系列文
《30天挑戰精通 PowerShell:從 Windows Server 到 Azure DevOps 自動化之旅》30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言