3

考虑以下调用站点:

$modifiedLocal = 'original local value'
'input object' | SomeScriptblockInvoker {
    $modifiedLocal = 'modified local value'
    [pscustomobject] @{
        Local = $local
        DollarBar = $_
    }
}
$modifiedLocal

我想实现SomeScriptblockInvoker这样

  1. 它在一个模块中定义,并且
  2. 在调用者的上下文中调用脚本块。

调用站点的函数输出如下:

Local DollarBar   
----- ---------   
local input object
modified local value

PowerShell 似乎能够做到这一点。例如,替换SomeScriptblockInvokerForEach-Object恰好产生所需的输出。

我已经接近使用以下定义:

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

(检查正确行为的 Pester 测试要点)

4

1 回答 1

3

一般来说,你不能。脚本块的调用者无法控制与该脚本块关联的SessionState,并且该 SessionState (部分)确定了执行脚本块的上下文(有关详细信息,请参阅范围部分)。根据脚本块的定义位置,它的 SessionState 可能与调用者的上下文匹配,但也可能不匹配。

范围

关于脚本块执行的上下文,有两个相关的考虑:

  1. 与脚本块关联的 SessionState。
  2. 调用方法是否向 SessionState 的范围堆栈添加范围。

这是一个很好的解释这是如何工作的

自动$_变量

$_包含管道中的当前对象。提供给的脚本块%的解释与提供的脚本块不同,.并且&

  • 'input_object' | % {$_}- 的值$_'input_object'因为脚本块绑定到%-Process参数。该脚本块对管道中的每个对象执行一次。
  • 'input_object' | . {process{$_}}'input_object' | & {process{$_}}- 的值$_'input_object'因为脚本块$_中的 位于一个process{}块内,该块对管道中的每个对象执行一次。

请注意,$_当使用 调用脚本块时,OP 中为空.。这是因为脚本块不包含任何process{}块。脚本块中的每个语句都隐含地成为脚本end{}块块的一部分。到end{}运行块时,管道中不再有任何对象并且$_为空。

.对比&对比%

., &, 和%每一个都使用脚本块的 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

并调用SomeScriptblockInvoker在 OP 中使用的脚本块。

选项 2

%按照 PetSerAl 的建议使用脚本块调用

于 2018-02-09T02:23:07.993 回答