7

我想创建一个枚举一些数据的 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 }

我得到十个true。事实上,我看到那$_是空的。

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

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

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


Invoke-TenTimes { $_ }
4

4 回答 4

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
于 2012-10-02T12:17:28.760 回答
3

该问题是已知的,并且特定于模块。也许这甚至是一个错误。请看一下这个问题:Powershell scriptblock variable scope and modules的奇怪行为,有什么建议吗?

至于您的特定情况,请像这样调用您的函数:

Invoke-TenTimes { $args[0] }

这样,它应该可以按预期工作。

于 2012-10-02T12:05:18.817 回答
2

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

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

有趣的是,它最初只在 ACCIDENT 中起作用。它是从脚本块所属的父范围中获取 $_ 的,它恰好在你的 foreach-object 内部,这很好。

但是拿你的原始版本,然后运行这个

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

你会看到你会得到 10 次陷阱,因为 $_ 在你的调用者范围内不是空的,而是一些东西。

于 2012-10-02T21:13:39.670 回答
0

这比每个人都容易得多。

考虑 $A 和 $B 是在全局级别定义的,而只有 $B 是在模块级别定义的。您的脚本块是第三个范围。在其中您引用 $A 并获取全局值。同样,如果您引用 $B 您将获得模块级别的值,因为它掩盖了全局实例。

问题:如果您尝试写入其中任何一个 - 将创建一个本地实例。

回答:

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

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

([ref]$B).value.Length

是相同的

$B.Length

In either case you have no direct control over scope. You get the instance you would read from. So the first example modifies the Global $A and the second example references the module level instance of $B.

于 2018-02-21T22:41:14.080 回答