使用范围重新创建 PowerShell 脚本块
Recreate PowerShell Script Block Using Scope
我有以下 cmdlet 来调用任意脚本块(通常调用 exe)并处理 return 代码。这里的目标是打印一个命令行,运行它,然后如果失败就抛出一个错误....
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
}
我有以下 cmdlet 来调用任意脚本块(通常调用 exe)并处理 return 代码。这里的目标是打印一个命令行,运行它,然后如果失败就抛出一个错误....
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
}