【问题标题】:Cannot use variable in a Where-Object in a function不能在函数的 Where-Object 中使用变量
【发布时间】:2021-09-03 05:01:11
【问题描述】:

我正在尝试创建一个函数,该函数可以根据我将传递参数的 LatestStatus 值计算作业。到目前为止我得到了什么:

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

问题是,正如我在某处所读到的,将会有一个 subshel​​l(?) 执行 where,因此不会传递参数。

如果我用“失败”之类的特定字符串替换 $args,它将起作用。

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

感谢任何 cmets - 谢谢

【问题讨论】:

  • $args 是一个automatic variable,其中包含传递给函数、脚本或脚本块的未声明参数值的数组。你把它当作一个标量..
  • @BendertheGreatest,我已经修复了问题中的语法错误。
  • 谢谢。我尽量不修复问题示例中的语法错误,但考虑到没有提及错误,我想这很明显不是 OP 的问题

标签: function powershell parameters veeam


【解决方案1】:

您可以在运行函数时将值命名为 $argsAutomatic 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
    }
}

【讨论】:

  • “您可以使用带有参数的高级函数,无论是否命名”是什么意思?如果要定义参数,则必须为参数命名,即使是简单的函数定义。
  • 如示例所示我在执行命令时没有命名-Status,它是由它的位置拾取的。
  • 哦,我明白你的意思了,当调用,而不是定义。值得一提的是,您不必定义位置顺序,它将按照参数声明的顺序自动确定。我通常只推荐使用带有许多参数的 cmdlet 的方法,尽管这样做的有效性并没有降低。
  • 这就是我认为named and positional parameters - "A named parameter requires that you type the parameter name and argument when calling the cmdlet." 的意思。
  • 我只是被你的措辞弄糊涂了,现在说得通了。困惑在于我,而不是您的答案。
【解决方案2】:

$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(),但您需要使用任何一种技术来获取命名参数
  • 我将 $args 引用替换为 $Status
  • 您对Measure-Object 的使用无关紧要,因此我已将其删除。 Where-Object 返回一个已经具有 Count 属性的集合。
  • 如果需要,您可以使用 ?,但最好的做法是在脚本和模块中省略别名并使用完整的 cmdlet 名称,因此我将 ? 替换为 Where-Object

请注意,您可以使用或不使用参数来调用函数/cmdlet(PowerShell 定义的 cmdlet 差异很小),因为当您不定义位置顺序时,顺序会自动按照声明的顺序确定:

# Either will work
JobCountStatus -Status Running
JobCountStatus Running

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

@Ash's answer 提供了一些更高级的示例,说明您可以使用param() 执行哪些操作,这些示例在上面的Advanced Functions 链接中有所提及。您不能将advanced parameter attributes 与我在第一个要点中提到的简单函数语法一起使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2021-12-07
    • 1970-01-01
    • 2020-06-12
    • 2018-01-09
    • 1970-01-01
    相关资源
    最近更新 更多