【问题标题】:Function Not Recognized When Receiving Job Multiple Times in Loop在循环中多次接收作业时无法识别功能
【发布时间】:2019-04-02 16:28:08
【问题描述】:

这是我第一次在 powershell 中使用 Jobs。我已将一个函数放入作业中,并且我有一个显示 ETA 倒计时的 while 循环。如果倒计时达到预定义的时间并且功能尚未完成处理,我希望倒计时暂停/调整。

我已成功创建倒计时,但尝试了 Receive-JobGet-Job 的变体。我还创建了一个全局变量,该变量在函数完成时从 0 变为 1。 while 循环当前正在无限循环中查看变量,直到它发生变化

$Completion = "0"
$TWOLength = "10"
$ScanFunction = {InitiateScan -Type "Auto"}
$ScanJob = Start-Job -ScriptBlock $ScanFunction

$iTWO=1
Do {
    $TLlabel.Text = "Scanning Computer        ETA: "+$LoadProVal+" Seconds"
    $TLPB.Value = -($LoadProVal-$LoadProMax)
    $TLform.Refresh()
    $LoadProVal--
    $iTWO++
    $TLform.Refresh()
    Start-Sleep 1
}
While ($iTWO -le $TWOLength)

While ($Completion -ne "1"){
    #Do Loop Infinite until Variable Changes
    Receive-Job $ScanJob -Keep
    Write-Host $InitialScan
        Start-Sleep 5
}

当该代码运行时,一旦它开始处理 Receive-Job $ScanJob -Keep While 循环,我就会收到错误消息 The term 'InitiateScan' in not recognized。 如果我将 Receive-Job 放在 While 循环之前,则不会发生错误,这就是我添加 -Keep 参数的原因

期望的最终结果应该是:
- 在作业中开始扫描
-开始倒计时
-当到达$TWOLength时,检查工作$Completion变量
-如果$Completion不是1,等待再检查
- 如果$Completion 为1,则结束循环并继续

【问题讨论】:

  • 该函数之前与其余代码内联运行,没有任何问题。之所以将其放入作业中,是因为在处理过程中,加载栏会变得无响应。
  • 那么. InitiateScan -Type "Auto" 不行吗?
  • 如果函数在它自己的文件中怎么办?那我可以叫它不同的名字吗?
  • 不,(点源)不能直接工作,尽管您可以将函数定义写入文件,然后从后台进程中点源;但是,有一个更简单的解决方案 - 请参阅我的答案。

标签: powershell


【解决方案1】:
  • 要让后台作业查看函数,它必须定义为其脚本块的一部分(或者是自动加载模块的一部分/从模块导入)。

  • 后台作业作为单独的 PowerShell 进程运行(不加载用户的 $PROFILE)。

一种选择是将函数的定义传递给脚本块以在后台执行并重新定义在那里
请注意,您必须类似地重新定义此函数调用的其他函数(如果有)。

一个简化的例子:

# Define the function to use in the background job.
function Initiate-Scan { "hi: $args" }

# Start the job and (re)define the function in the script block, via
# passing the function body as an argument.
$jb = Start-Job { 
  ${function:Initiate-Scan} = $args[0]; Initiate-Scan -Type Auto 
} -Args ${function:Initiate-Scan}

# Get the job's output.
Receive-Job $jb -Wait -AutoRemoveJob

以上产生hi: -Type Auto,表明该函数已在后台作业中成功重新定义。


替代方法是在传递给-InitializationScript参数的脚本块中定义函数:

# Define the function to use in the background job.
function Initiate-Scan { "hi: $args" }

# Start the job and (re)define the function in the initialization script
# script block, so that the main script block can use it.
$jb = Start-Job -InitializationScript (
    [scriptblock]::Create("function Initiate-Scan { ${function:Initiate-Scan} }")
  ) -ScriptBlock { 
    Initiate-Scan -Type Auto 
  }

# Get the job's output.
Receive-Job $jb -Wait -AutoRemoveJob

注意:脚本块必须使用[scriptblock]::Create() 从字符串 创建,因为 - 由于存在错误 - $using: 从调用者范围内引用值在 PowerShell 中不起作用7.0 - 见this GitHub issue

一旦错误得到修复,您可以执行以下操作:

# !! Doesn't work as of PowerShell 7.0
-InitializationScript { ${function:Initiate-Scan} = ${using:function:Initiate-Scan} }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-06
    • 1970-01-01
    • 2015-07-05
    • 2010-12-29
    • 2022-10-24
    • 2021-01-22
    相关资源
    最近更新 更多