Powershell运行脚本块-范围,点源

时间:2018-11-14 22:11:04

标签: function powershell scope

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

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不使用点源语法,因此似乎有可能。

1 个答案:

答案 0 :(得分:1)

documentation on working with lists of data(他不愿意这样做)在对问题的简短评论中提供了关键的指针:

将函数放入模块中,以及基于点的脚本块参数调用解决了该问题:

set_label_text

上面的代码产生$null = New-Module { function Wrapper { param($ScriptBlock) . $ScriptBlock } } $a = 1 Wrapper { $a++ } $a ,证明脚本块在调用者的范围内执行。

有关为何可行以及为什么有必要的解释,请参见PetSerAl的相关问题。

注意:以上方法并未扩展到管道的使用,在这种情况下,您需要传递希望使用自动变量2的脚本块以引用当前的对象(例如
$_;要支持此用例,需要一种解决方法-请参见this answer