PowerShell函数与参数化脚本块

时间:2012-10-02 10:00:45

标签: powershell

我想创建一个枚举一些数据的PowerShell函数,并在所有出现的情况下触发一个脚本块。

到现在为止(这不是实际的代码,但它说明了我的问题):

function Invoke-TenTimes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [ScriptBlock]$Action
    )
    process
    {
        $digits = 0..10
        $digits | % {
            $Action.Invoke($_);
        }
    }
}

我把这个功能放在我的模块中。但是,当我打电话时,我没有得到任何结果:

Invoke-TenTimes { $_ }

输出为空白(不显示任何内容)。

如果我打电话

Invoke-TenTimes { $_ -eq $null }

我得到10 true。事实上,我发现$_为空。

填充$_的正确方法是什么?

让我疯狂的是,如果我将此函数和调用放在同一个ps1文件中,它可以正常工作(但我想按需传递脚本块):

function Invoke-TenTimes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [ScriptBlock]$Action
    )
    process
    {
        $digits = 0..10
        $digits | % {
            $Action.Invoke($_);
        }
    }
}


Invoke-TenTimes { $_ }

4 个答案:

答案 0 :(得分:5)

我们走了:

$scriptblock = {param($number) Write-Host "Current Number is $number"} 

function Invoke-TenTimes
{
    [CmdletBinding()]
    param
    (
       [Parameter(Mandatory=$true, Position=0)]
       [ScriptBlock]$Action
    )
    $digits = 1..10
    $digits | ForEach-Object{Invoke-Command -ScriptBlock $Action -Args $_}
 }

使用:

Invoke-TenTimes $scriptblock

答案 1 :(得分:3)

该问题是已知的,并且特定于模块。也许这甚至是一个错误。请看一下这个问题:Strange behavior with Powershell scriptblock variable scope and modules, any suggestions?

至于您的具体情况,请按以下方式调用您的函数:

Invoke-TenTimes { $args[0] }

这样它应该按预期工作。

答案 2 :(得分:2)

这是一个范围问题,传入的scriptblock属于与执行位置不同的范围。如果传入的scriptblock不必从其上下文引用变量,则可以简单地克隆scriptblock以强制它在您运行它的范围内。与

$action = [scriptblock]::Create($action)

有趣的是它只在ACCIDENT首先发挥作用。它是从脚本块所属的父作用域获取$ _,它恰好位于你的foreach-object里面,这很好。

但请使用原始版本,然后运行此

"gotcha" | % {
Invoke-TenTimes {  $_ }
}

并且你会发现你会得到10次,因为$ _在你的来电者范围内不是空的,但是有些东西。

答案 3 :(得分:0)

这比每个人都要容易得多。

考虑$ A和$ B在全局级别定义,并且在模块级别仅定义$ B.您的脚本块是第3个范围。在其中,您指的是$ A并获得全局价值。类似地,如果您引用$ B,则会获得模块级别值,因为它会覆盖全局实例。

问题:如果您尝试写入 - 则创建本地实例。

答案:

([ref]$A).value = 'Something malicious'

请注意“([ref] $ {name})”是一个引用对象,因此需要“.value”才能到达实际变量。所以

([ref]$B).value.Length

相同
$B.Length

在任何一种情况下,您都无法直接控制范围。你得到了你想读的实例。因此,第一个示例修改全局$ A,第二个示例引用$ B的模块级实例。