不能在函数的 Where-Object 中使用变量

Cannot use variable in a Where-Object in a function

我正在尝试拥有一个函数,该函数可以根据传递给参数的 LatestStatus 值对作业进行计数。到目前为止我得到了什么:

Function JobCountStatus {
  Write-Output (Get-VBRJob | ?{$_.Info.LatestStatus -eq $args} | Measure-Object).Count
}

问题是,正如我在某处读到的那样,会有一个子 shell(?) 执行 where 所以参数没有被传递。

如果我将 $args 替换为特定字符串(如“Failed”),它将起作用。

有没有办法克服这个问题?我不想为所有可能的值编写单独的函数。

如有任何意见,我将不胜感激 - 谢谢

$args 是一个数组,不是单个值。在任何情况下,ScriptBlock {} 是一个未命名的函数,$args 在其中有其自身的含义,因此如果不对 Where-Object 进行一些修改就不能使用它.您必须将 $args 的元素存储为另一个变量或多个变量以在子 ScriptBlock 中引用。此函数的变化不大,但对于需要更多参数的函数,这可能会导致大量不必要的代码,难以维护。


在大多数情况下,我更愿意推荐定义命名参数,这比让父 $args 在子 ScriptBlock 中工作更简单的更改:

Function JobCountStatus {
  Param(
    [string]$Status
  )
  ( Get-VBRJob | Where-Object { $_.Info.LatestStatus -eq $Status } ).Count
}

我在这个功能上也做了一些改动,下面会说明:

  • 使用Param()按名称强定义参数。您可以使用更简单的 function JobCountStatus([string]$Status) {} 语法,但对于这种情况,使用哪种技术实际上是一个偏好问题。作为惯例,我建议使用 Param(),但是 您需要使用任何一种技术来获取命名参数
  • 我用 $Status 替换了 $args 引用。
  • 您对 Measure-Object 的使用无关紧要,因此我已将其删除。 Where-Object returns 已经有 Count 属性.
  • 的集合
  • 您可以根据需要使用 ?,但最好的做法是省略别名并在脚本和模块中使用完整的 cmdlet 名称,因此我将 ? 替换为 Where-Object .

请注意,您可以在有或没有参数的情况下调用 function/cmdlet(PowerShell 定义的 cmdlet 的差别很小),因为当您没有定义位置顺序时,顺序是自动确定的申报顺序:

# Either will work
JobCountStatus -Status Running
JobCountStatus Running

这里还有一些您可能会觉得有用的文档:

gives some more advanced examples of what you can do with param() which are mentioned in the the Advanced Functions link above. You cannot use advanced parameter attributes 使用我在第一个要点中提到的简单函数语法。

当你 运行 函数时,你可以直接命名值,因为 $args 是一个 Automatic Variable

JobCountStatus "Failed"

您可以使用带有参数的高级函数,无论是否命名:

function JobCountStatus {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]
        $Status
    )
    Process {
        (Get-VBRJob | Where-Object { $_.Info.LatestStatus -eq $Status } | Measure-Object).Count
    }
}

然后这样称呼它:

JobCountStatus -Status "Failed"

# OR

JobCountStatus "Failed"

后者与使用 $args 的最终结果相同。在这里指定您自己的参数的唯一可能的好处是您可以定义一个 ValidateSet 状态或一个状态值枚举,这样您就可以在它们之间切换。前者的一个例子是这样的:

function JobCountStatus {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateSet("Failed", "Running", "Successful", "Unknown")]
        [System.String]
        $Status
    )
    Process {
        (Get-VBRJob | Where-Object { $_.Info.LatestStatus -eq $Status } | Measure-Object).Count
    }
}