我想创建一个枚举一些数据的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 { $_ }
答案 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的模块级实例。