【问题标题】:Powershell running a scriptblock - scope, dot-sourcing运行脚本块的 Powershell - 范围,点源
【发布时间】:2019-04-17 23:14:33
【问题描述】:

我想编写一个函数,它接受一个脚本块作为参数,并在调用它的范围内执行该脚本块。

Measure-Command 是我想要的行为示例。脚本块在与 Measure-Command 本身相同的范围内运行。如果脚本块引用此范围内的变量,则脚本可以更改它。

附加的是增加 $a 变量的示例脚本块。当被 Measure-Command 调用时,变量会递增。但是当被 Wrapper 函数调用时,该变量不会增加 - 除非我对 Wrapper 函数的调用和 Wrapper 函数本身都使用点源进行点源。

function Wrapper1
{
    param( $scriptBlock )
    $startTime = Get-Date
    Write-Output ( "{0:HH:mm:ss} Start script" -f $startTime )
    & $scriptBlock
    $endTime = Get-Date
    Write-Output ( "{0:HH:mm:ss} End script - {1:c} seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
}

function Wrapper2
{
    param( $scriptBlock )
    $startTime = Get-Date
    Write-Output ( "{0:HH:mm:ss} Start script" -f $startTime )
    . $scriptBlock
    $endTime = Get-Date
    Write-Output ( "{0:HH:mm:ss} End script - {1:c} seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
}

$a = 1
Write-Output "Initial state: `$a = $a"

Measure-Command { $a++ } | Out-Null
Write-Output "Measure-Command results: `$a = $a"

Wrapper1 { $a++ }
Write-Output "Wrapper1 results: `$a = $a"

. Wrapper1 { $a++ }
Write-Output "dot-sourced Wrapper1 results: `$a = $a"

Wrapper2 { $a++ }
Write-Output "Wrapper2 results: `$a = $a"

. Wrapper2 { $a++ }
Write-Output "dot-sourced Wrapper2 results: `$a = $a"

运行这段代码的结果是:

Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3

虽然最后一个选项有效,但我想避免调用 Wrapper2 的点源语法。这可能吗? Measure-Command 不使用 dot-source 语法,所以它似乎是可能的。

【问题讨论】:

  • 将包装函数放入模块中。

标签: function powershell scope


【解决方案1】:

PetSerAl,正如他惯常做的那样,在对该问题的简短评论中提供了关键指针:

将函数放在一个模块中,连同脚本块参数的点源调用,解决了这个问题:

$null = New-Module {
  function Wrapper {
    param($ScriptBlock)
    . $ScriptBlock
  }
}

$a = 1
Wrapper { $a++ }

$a

以上产生2,证明脚本块在调用者的范围内执行。

如需了解为什么这样做以及为什么需要这样做,请参阅this answer 的相关问题。

注意:上述方法不会扩展到 管道 使用,您需要传递预期使用自动变量 $_ 的脚本块来引用手头的对象(例如,
1, 2, 3 | Wrapper { $_ ... };为了支持此用例,需要一种解决方法 - 请参阅this answer

【讨论】:

    猜你喜欢
    • 2012-01-21
    • 1970-01-01
    • 2017-10-01
    • 2020-11-06
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多