考虑以下调用站点:
$modifiedLocal = 'original local value'
'input object' | SomeScriptblockInvoker {
$modifiedLocal = 'modified local value'
[pscustomobject] @{
Local = $local
DollarBar = $_
}
}
$modifiedLocal
我想实施SomeScriptblockInvoker
以便
- 它在模块中定义,并且
- 脚本块在调用方的上下文中调用。
调用站点上的函数输出如下所示:
Local DollarBar
----- ---------
local input object
modified local value
PowerShell似乎有能力做到这一点。 例如,用ForEach-Object
替换SomeScriptblockInvoker
可以产生所需的输出。
我使用以下定义接近:
New-Module m {
function SomeScriptblockInvoker {
param
(
[Parameter(Position = 1)]
[scriptblock]
$Scriptblock,
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
$InputObject | . $Scriptblock
}
}
} |
Import-Module
使用该定义的调用站点的输出如下所示:
Local DollarBar
----- ---------
local
modified local value
请注意,DollarBar
在应该input object
时为空。
(纠缠测试的要点,以检查正确的行为)
一般来说,你不能。 脚本块的调用方无法控制与该脚本块关联的 SessionState,并且 SessionState 确定(部分)执行脚本块的上下文(有关详细信息,请参阅"范围"部分)。 根据定义脚本块的位置,其 SessionState 可能与调用方的上下文匹配,但可能不匹配。
范围
关于执行脚本块的上下文,有两个相关的注意事项:
- 与脚本块关联的会话状态。
- 调用方法是否将作用域添加到 SessionState 的作用域堆栈。
这是对它如何工作的很好的解释。
$_
自动变量
$_
包含管道中的当前对象。 提供给%
的脚本块与.
和&
提供的脚本块的解释不同:
'input_object' | % {$_}
-$_
的值'input_object'
,因为脚本块绑定到%
的-Process
参数。 该脚本块为管道中的每个对象执行一次。'input_object' | . {process{$_}}
和'input_object' | & {process{$_}}
-$_
的值'input_object'
,因为脚本块中的$_
位于process{}
块内,该块对管道中的每个对象执行一次。
请注意,在 OP 中,当使用.
调用脚本块时,$_
为空。 这是因为脚本块不包含process{}
块。 脚本块中的每个语句都是脚本块end{}
块的隐式部分。 运行end{}
块时,管道中不再有任何对象,$_
为 null。
.
vs&
vs%
.
、&
和%
分别使用脚本块的 SessionState 调用脚本块,但根据下表存在一些差异:
+---+-----------------+-----------+-------------------+----------------------+
| | Name | Kind | interprets {} as | adds scope to stack |
+---+-----------------+-----------+-------------------+----------------------+
| % | ForEach-Object | Command | Process block | No |
| . | dot-source | Operator | scriptblock | No |
| & | call | Operator | scriptblock | Yes |
+---+-----------------+-----------+-------------------+----------------------+
%
命令具有对应于Begin{}
和End{}
块的其他参数。- 要使脚本块进行的变量赋值对与脚本块关联的 SessionState 产生副作用,请使用不向堆栈添加作用域的调用方法。 否则,变量赋值只会影响新创建的作用域,并在脚本块完成执行后消失。
最可行的选择
在 OP 中通过测试的两个最可行的选项如下。 请注意,两者都不会严格在调用方的上下文中调用脚本块,而是在使用与脚本块关联的 SessionState 的上下文中调用脚本块。
选项 1
更改调用站点,以便脚本块包含process{}
:
$modifiedLocal = 'original local value'
'input object' | SomeScriptblockInvoker {
process {
$modifiedLocal = 'modified local value'
[pscustomobject] @{
Local = $local
DollarBar = $_
}
}
}
$modifiedLocal
并在 OP 中使用SomeScriptblockInvoker
调用脚本块。
选项 2
按照 PetSeral 的建议使用%
调用脚本块。