问题描述
我具有以下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-@R_906_4045@ion "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
@H_404_5@只要Invoke-ScriptBlock cmdlet不在模块内部,此方法就很好用。如果是这样,我将丢失“调用命令”消息中捕获的变量的闭包。
Import-Module .\Util.psm1 $comment = 'acomment' Invoke-ScriptBlock { git commit -m $comment } # prints Invoking command: git commit -m
@H_404_5@有没有一种方法可以使用传入的$ 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 }