gpt4 book ai didi

powershell - 什么时候 ScriptBlock 不是 ScriptBlock?

转载 作者:行者123 更新时间:2023-12-03 21:15:26 29 4
gpt4 key购买 nike

我并不是要让这个问题听起来太可爱,但这确实是眼前的问题。考虑安装在 $env:PSModulePath 下的 PowerShell 模块 Test.psm1 中定义的以下两个函数:

function Start-TestAsync
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
Start-Job { Start-Test -Name $using:Name -Block $using:Block }
}

function Start-Test
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
# do some work here, including this:
Invoke-Command -ScriptBlock $Block
}

导入模块后,我可以运行同步功能...

PS> Start-Test -Name "My Test" -Block { ps | select -first 9 }

...并显示 Get-Process 的适当输出。

但是,当我尝试运行异步版本时...

PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }

...然后查看其输出...

PS> Receive-Job $testJob

...它无法将参数引入 Start-Test 函数,报告它无法将 String 转换为 ScriptBlock。因此,-Block $using:Block 传递的是字符串而不是 ScriptBlock!

经过一些实验,我确实找到了解决方法。如果我修改 Start-Test,使 $Block 参数的类型为 [string] 而不是 [ScriptBlock] —— 然后将该字符串转换回 block 以提供给 Invoke-Command...

function Start-Test
{
[CmdletBinding()]
param([string]$Block, [string]$Name = '')
$myBlock = [ScriptBlock]::Create($Block)
Invoke-Command -ScriptBlock $myBlock
}

当我从上面运行相同的命令时,我得到了正确的结果:

PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }
PS> Receive-Job $testJob

using 范围在我的初始示例中是否正常工作(将 ScriptBlock 转换为字符串)?关于它的有限文档(about_Remote_Variablesabout_Scopes)提供的指导很少。最后,当 Start-Test 的 $Block 参数被键入为 [ScriptBlock] 时,有没有办法让 Start-Test 工作?

最佳答案

这显然是设计使然:https://connect.microsoft.com/PowerShell/feedback/details/685749/passing-scriptblocks-to-the-job-as-an-argument-cannot-process-argument-transformation-on-parameter

解决方法(来自上面的链接)是使用[ScriptBlock]::Create():

This happens because the $ScriptToNest scriptblock is getting converted into a string because of how PowerShell serialization works. You can work around this by explicitly creating the scriptblock. Replace the param() block in your $OuterScriptblock with the following ($ip is the input):

[scriptblock]$OuterScriptblock = {
param($ip)
[ScriptBlock]$ScriptToRun = [ScriptBlock]::Create($ip)

这将是您的解决方法(如您所见):

function Start-TestAsync
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
Start-Job { Start-Test -Name $using:Name -Block $using:Block }
}

function Start-Test
{
[CmdletBinding()]
param($Block, [string]$Name = '')
# do some work here, including this:
$sb = [ScriptBlock]::Create($Block)
Invoke-Command -ScriptBlock $sb
}

关于powershell - 什么时候 ScriptBlock 不是 ScriptBlock?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25728616/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com