You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

[scriptblock]::Create()生成的脚本块调用GetSteppablePipeline时绑定到哪个SessionState?

PowerShell脚本块SessionState绑定问题分析

Jason Shirk 指出:
若使用{ ... }语法创建脚本块,它会立即绑定到SessionState;若通过其他方式(如[ScriptBlock]::Create())创建,则会在首次调用时绑定到当前活跃的SessionState。

这一描述是正确的,有相关讨论线程深入探讨了此行为,还有带注释的示例演示PowerShell作用域、.和&运算符、模块与SessionState之间的交互。

请考虑以下代码:通过[scriptblock]::Create()生成的两个相同脚本块实例,分别使用调用运算符&和SteppablePipeline进行调用:

function Invoke-Call {
    [CmdletBinding()]
    param(
        [scriptblock]
        $ScriptBlock,
        $a
    )
    & ([scriptblock]::Create({ param ($sb,$__a) . $sb $__a })) `
      $ScriptBlock $a
}
function Invoke-Steppable {
    [CmdletBinding()]
    param(
        [scriptblock]
        $ScriptBlock,
        $a
    )
    $pipe = [scriptblock]::Create({ param ($sb,$__a) . $sb $__a }).
            GetSteppablePipeline(
                $MyInvocation.CommandOrigin,
                @($ScriptBlock,$a))
    $pipe.Begin($PSCmdlet)
    $pipe.End()
}

Invoke-Call      -a 'c' -ScriptBlock { param($x) [pscustomobject]@{function = 'Invoke-Call'; x=$x; a=$a; __a=$__a }}
Invoke-Steppable -a 's' -ScriptBlock { param($x) [pscustomobject]@{function = 'Invoke-Steppable'; x=$x; a=$a; __a=$__a }}

该代码输出如下:

function         x a __a
--------         - - ---
Invoke-Call      c c c
Invoke-Steppable s s

关于上述输出,有以下几点值得注意:

  • $a在两种调用-ScriptBlock的方式下都可访问。这是因为函数和-ScriptBlock都绑定到同一个SessionState,函数的参数$a所在的作用域是-ScriptBlock的祖先作用域,因此$a可见。
  • 当-ScriptBlock通过Invoke-Call调用时,$__a是可访问的。这与前一点类似:[scriptblock]::Create()生成的脚本块调用时绑定到Invoke-Call的SessionState,与-ScriptBlock的SessionState相同,因此$__a可见。
  • 当-ScriptBlock通过Invoke-Steppable调用时,$__a不可访问。

这表明通过SteppablePipeline调用的[scriptblock]::Create()生成的脚本块,并未绑定到与-ScriptBlock相同的SessionState。

问题解答

通过SteppablePipeline调用的[scriptblock]::Create()生成的脚本块,会绑定到全局SessionState(即PowerShell最顶层的会话状态,而非函数的局部SessionState)。

原因在于:GetSteppablePipeline方法在创建可步进管道时,会将脚本块绑定到与当前执行上下文的顶层会话状态关联的作用域,而非调用该方法的函数的局部SessionState。在示例中,Invoke-Steppable函数的局部变量$__a属于函数的局部作用域,而通过可步进管道执行的脚本块处于全局SessionState,无法跨作用域访问函数的局部变量,因此$__a不可见。

这种差异的核心是:调用运算符&会在当前函数的局部SessionState上下文执行脚本块,而SteppablePipeline的创建逻辑会将脚本块绑定到全局会话状态,脱离了函数的局部作用域上下文。

内容的提问来源于stack exchange,提问作者alx9r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:22:15