如何在Powershell中将参数化脚本块与Where-Object一起使用?

时间:2011-02-10 17:38:26

标签: powershell

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

背景:

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

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

自定义脚本块指的是包含对源代码控制执行查询的结果的脚本范围变量。

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

3 个答案:

答案 0 :(得分:7)

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

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

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

$x可以轻松替换为(get-x)等其他函数调用。

基本上我正在调用一个脚本块,该脚本块返回一个脚本块,该脚本块关闭外部scriptblocks参数。与Keiths基本上相同的实现,只是更多的succint [和迟钝。] Lambdas为胜利。

我只希望有一种更简洁的方法来获得闭包语义。也就是说,我很高兴这种方法得到了投入而不是投入。

-Oisin

答案 1 :(得分:5)

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

function FilterProcs([scriptblock]$scriptblock)
{
    Get-Process | Where $scriptblock
}

$name = 'Notepad'

& {
    $name = 'PowerShell'
    FilterProcs {$_.Name -eq $name}.GetNewClosure()
}

$name

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

BTW这是另一种使用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

P.S。很高兴看到你保持PowerShellin'。 : - )

答案 2 :(得分:3)

您无法关闭$ args周围的现有脚本块,但您可以使用它创建一个新的脚本块:

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


 2

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