【问题标题】:How do I use a parameterized script block with Where-Object in Powershell?如何在 Powershell 中将参数化脚本块与 Where-Object 一起使用?
【发布时间】:2011-06-25 00:59:55
【问题描述】:

where-object 过滤器脚本中将信息传递到脚本块中是否有比使用父范围变量更好的方法?

背景:

我有一个脚本,用于查找未签入和/或修改的源文件与源代码管理,并有一个参数允许它进行更详尽的搜索。我在几个地方使用了where-object,脚本块对象包含在我根据脚本的输入参数自定义的脚本范围变量中。

因此,如果您要求彻底搜索,过滤器会将候选文件与所有 TFS 文件进行比较,以查看该文件是否不在源代码管理中,如果您选择不太彻底的搜索,过滤器将仅比较对照已签出的文件,查看文件是否已修改但未签出。

自定义脚本块是指脚本范围的变量,其中包含针对源代码管理执行查询的结果。

所以我的问题是我想摆脱一个全局(脚本级)变量,并将所有必要的信息作为脚本块的参数传递到脚本块中。如果我使用invoke-command,我会使用ArgumentList 参数来执行此操作。 Where-Object 似乎没有。在脚本块中使用父范围变量引用的一个缺点是我不能更改这些变量,所以我不能进行延迟初始化(或者至少我还没有弄清楚如何,不是专家Powershell 的范围规则。)

【问题讨论】:

    标签: powershell


    【解决方案1】:

    您可以创建一个临时范围并在脚本块上使用GetNewClosure() 方法,让它围绕脚本块中使用的变量创建一个闭包,例如:

    function FilterProcs([scriptblock]$scriptblock)
    {
        Get-Process | Where $scriptblock
    }
    
    $name = 'Notepad'
    
    & {
        $name = 'PowerShell'
        FilterProcs {$_.Name -eq $name}.GetNewClosure()
    }
    
    $name
    

    在这种情况下,$name 的内部修改只能在本地看到,而不是在脚本中看到 范围。可能有更好的方法,但我认为这对你有用。

    顺便说一句,这是另一种使用 Foreach-Object cmdlet 进行过滤的方法:

    function FilterProcs([scriptblock]$scriptblock, [object[]]$argumentList)
    {
        Get-Process | Foreach {if (&$scriptblock @argumentList){$_}}
    }
    
    FilterProcs {param($name, $id) ($_.Name -match $name -and $_.Id -eq $id)} `
                -ArgumentList 'PowerShell_ISE',$pid
    

    附:很高兴看到你跟上 PowerShellin'。 :-)

    【讨论】:

      【解决方案2】:

      只是为了扩展 Keith 提到的内容,您可以这样做:

      ps> $x=2
      ps> 1..5 | where (& {param($v); { $_ -eq $v }.getnewclosure() } $x )
      2
      

      我尝试关闭隐式 $args 以保存参数声明,但 $args 似乎免于捕获。更有可能它被捕获但只是被踩踏。

      $x 可以很容易地替换为另一个函数调用,例如 (get-x)

      本质上,我正在调用一个脚本块,该脚本块返回一个脚本块,该脚本块关闭外部脚本块参数。本质上与 Keiths 的实现相同,只是更简洁 [和迟钝] Lambdas 获胜。

      我只希望有一种更简洁的方法来获得闭包语义。也就是说,我很高兴该方法被采用而不是没有。

      -奥辛

      【讨论】:

      • 呵呵,是的,这是我在午餐时突然想到的。我还认为 FilterProcs 方法将采用 -ArgumentList 参数,该参数将提供给传入的过滤器脚本块。
      • $args 是否免于捕获,或者为脚本块创建新作用域会自动为该作用域初始化一个新的 $args,从而使父作用域中的 $args 不再可见?我在使用 select-object 的哈希表表达式时遇到了类似的行为。如果在哈希表表达式脚本块中使用了 $args,则它必须明确限定为 $script:args。本地 $args 为空。
      • “更有可能它被捕获但只是被踩踏。”是的。
      • @Oisin,您可以使用类型扩展来添加一个名称较短的方法,该方法调用 GetNewClosure()。
      • @jasonmarcher true,但我不是在寻找方法。我正在考虑为它提供母语支持。
      【解决方案3】:

      你不能关闭 $args 周围的现有脚本块,但你可以用它创建一个新的脚本块:

      $x=2
       1..5 | where (& {[scriptblock]::create('$_ -eq ' + $args) } $x )
      
      
       2
      

      奇怪的是,创建一个全新的脚本块似乎比在现有脚本块上调用 getnewclosure 更快。我将这两个场景都运行了 10000 次,使用 $args 创建一个新的脚本块需要 5.3 秒,使用参数声明的 getnewclosure 需要 7.9 秒。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-07
        • 1970-01-01
        • 2017-03-13
        • 2016-01-13
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多