使用范围重新创建PowerShell脚本块

问题描述

我具有以下cmdlet来调用任意脚本块(通常调用exe)并处理返回代码。这里的目标是打印一个命令行,运行它,然后在失败时抛出一个错误....


function Invoke-ScriptBlock {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [scriptblock]$Block
    )

    $ErrorActionPreference = 'Continue'

    $stringBlock = "@`"`n" + $Block.ToString().Trim() + "`n`"@"
    $stringValue = . ([scriptblock]::create($stringBlock))

    Write-information "Invoking command: $stringValue"

    . $Block
    if ($lastexitcode -ne 0) { Write-Error "Command exited with code $lastexitcode" -EA Stop }
}

$comment = 'acomment'
Invoke-ScriptBlock { git commit -m $comment }
# prints Invoking command: git commit -m acomment

只要Invoke-ScriptBlock cmdlet不在模块内部,此方法就很好用。如果是这样,我将丢失“调用命令”消息中捕获的变量的闭包。

Import-Module .\Util.psm1
$comment = 'acomment'
Invoke-ScriptBlock { git commit -m $comment }
# prints Invoking command: git commit -m

有没有一种方法可以使用传入的$ Block中的原始上下文重新创建脚本块?

解决方法

没有受支持的方法,但是您可以通过将会话状态引用从原始$Block复制到重新创建的脚本块中来进行反射:

function Invoke-ScriptBlock {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [scriptblock]$Block
    )

    # To prove local and module-scoped variables won't affect the new script block
    $comment = ''

    # Obtain a reference to the relevant internal ScriptBlock property 
    $ssip = [scriptblock].GetProperty('SessionStateInternal',[System.Reflection.BindingFlags]'NonPublic,Instance')

    # Copy the value from $Block
    $ssi = $ssip.GetMethod.Invoke($Block,@())

    # Create new block with the same content 
    $newBlock = [scriptblock]::create("@`"`n" + $Block.ToString().Trim() + "`n`"@")

    # Overwrite session state value with the one with copied from $Block
    $ssip.SetMethod.Invoke($newBlock,@($ssi))

    $stringValue = & $newBlock

    Write-Information "Invoking command: $stringValue"
    & $Block
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...