脚本编程:Powershell:Powershell Advanced Function 踩坑记

tlin82大约 4 分钟Scripting Language脚本编程PowershellPowershell踩坑记

前言

最近使用Powershell踩了一个坑,后来回想起来,这个坑上回不也踩过吗?也是来回摸索很长时间。记性不如烂笔头,记录一下。

正文

我的一个函数使用一个参数从管道接收一个对象集合或是数组(又多个对象),结果每次只处理一个输入对象,真奇怪啊.调试了半天,百思不得其解。

关键字管道接收对象集合

示例代码:

Function Get-MyUserNameById {

param(
        [Parameter(ValueFromPipeline=$true)]      
        [string[]]$EmployeeId
        )


$EmployeeId | ForEach-Object { Write-Host "User name is : $_"}

}

"E01","E02","A08" | Get-MyUserNameById

以上是一个很简单的函数。定义了一个输入参数EmployeeId,该参数使用[Parameter(ValueFromPipeline=$true)] 属性允许从管道接收输入值(字符串集合), 然后使用ForEach-Ojbect 遍历打印输出3个字符串。 可是它没按预期打印出3个字符串,而是只打印出一个:

User name for Id A08 is : User-A08

为什么呢? 直接上答案

"如果函数参数设置为接受管道输入且未定义process块,则记录逐条处理将失败。"

意思是说,

  • 凡来自管道的对象集合,一定要在process代码块里来实现遍历,否则只会处理一条。这就解释了以上奇怪现象,即使使用了ForEach也只打印一条;

  • 了解到,「重要」process代码块内置一个专门枚举器enumerator 来专门处理管道输入的自动输入对象,即$_。这样,process里面处理管道输入,可以不使用foreach

因此,

  • 如果我們的函數需要處理管道的多個對象,則一定要有process。否則函數只處理一個對象。

  • 如果我們函數只通过其他传参(非管道),我们的函数可以不需要process,使用普通的遍历循环也可以处理多個對象;

  • 如何希望函数既能处理管道输入,也能处理普通传参,可以在process代码块使用foreach来覆盖process的枚举行为。像這樣:

Function Get-MyUserNameById {

    param(  
            [string[]]$EmployeeId
            )

    Process {
    
        foreach ($id in $EmployeeId) {
            write-host $id
        }
      
      }

    
}

#函數可以這樣 (普通傳參數):

$IDs = "E01","E02","A08"
Get-MyUserNameById -EmployeeId $IDs

#也可以這樣:從管道接收

"E01","E02","A08" |Get-MyUserNameById

最後,這個函數則提供更多靈活性。

參考

这篇文章深入探讨了PowerShell中的Begin、Process和End块,这些块是PowerShell高级函数内置的控制流,有助于开发者维护代码工作流程。文章通过比喻和示例,解释了每个块的具体目的和常见用例。

  1. Begin块:用于设置函数,包括指定变量和数组,这些变量和数组将在函数中使用。Begin块是可选的,如果只使用Process或End块,则不需要它。Begin块中的所有内容只会在函数调用时运行一次,类似于日常工作中的准备阶段。

  2. Process块:这是PowerShell高级函数中完成工作的地方。它处理参数和通过管道输入到函数中的数据。Process块可以单独使用,不需要Begin或End块。如果函数接受单个参数值,则Process块将只处理该单个值。如果函数接受管道输入,则Process块将处理每个传入的值。文章通过示例展示了如何处理单个值和通过管道传递的数组。

  3. End块:用于执行必要的清理工作。如果在Begin或Process块中创建了对象、变量、文件等,则应在End块中清理这些资源。End块也是可选的,如果只使用Process或Begin块,则不需要它。与Process块不同,无论通过管道传递了多少个数组元素,End块中的代码都只会执行一次。

文章通过比喻和例子强调了每个块的作用,如将一天的开始比作Begin块的初始化,将处理日常任务比作Process块的工作,将结束一天的工作并回家比作End块的清理。文章还提到了PowerShell函数应该做好一件事,并强调了将函数分解为Begin、Process和End块的重要性,以实现清晰的逻辑分离和更好的维护性。