powershell - 如何从 Start-Job 调用脚本中的 powershell 函数?

标签 powershell start-job

我看到了this questionthis question但找不到我的问题的解决方案。

所以情况如下:
我在脚本 (.ps1) 文件中有两个函数 DoWork 和 DisplayMessage。这是代码:

### START OF SCRIPT ###
function DoWork
{
  $event = Register-EngineEvent -SourceIdentifier NewMessage -Action {
      DisplayMessage($event.MessageData)
  }

  $scriptBlock =  {

    Register-EngineEvent -SourceIdentifier NewMessage -Forward

    $message = "Starting work"
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message

    ### DO SOME WORK HERE ###

    $message = "Ending work"
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message

    Unregister-Event -SourceIdentifier NewMessage
  }

  DisplayMessage("Processing Starts")

  $array = @(1,2,3)
  foreach ($a in $array)
  {
      Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array | Out-Null
  }

  #$jobs = Get-Job -Name "DoActualWork"
  While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" } )
  {
      Start-Sleep 1
  }

  DisplayMessage("Processing Ends")

  Get-Job -Name "DoActualWork" | Receive-Job
}

function DisplayMessage([string]$message)
{
    Write-Host $message -ForegroundColor Red
}

DoWork

### END OF SCRIPT ###

我正在创建 3 个后台作业(使用具有 3 个元素的 $array)并使用事件将消息从后台作业传递到主机。我希望powershell主机显示“处理开始”和“处理结束”1次,“开始工作”和“结束工作”各3次。但相反,我没有在控制台中显示“开始工作”/“结束工作”。

事件也被视为 powershell 中的作业,因此当我执行 Get-Job 时,我可以看到与事件作业相关的以下错误:

{The term 'DisplayMessage' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.}



我的问题:我们如何重用(或引用)在我调用 Start-Job 的同一脚本中定义的函数(在我的例子中为 DisplayMessage)?是否可以?
我知道我们可以使用 -InitializationScript 将函数/模块传递给 Start-Job,但我不想编写两次 DisplayMessage 函数,一个在脚本中,另一个在 InitializationScript 中。

最佳答案

后台作业在单独的进程中运行,因此您使用 Start-Job 创建的作业除非您将它们包含在 $scriptblock 中,否则无法与函数交互.

即使您在 $scripblock 中包含该函数, Write-Host在您使用 Get-Job | Receive-Job 之前不会将其内容输出到控制台接收作业结果。

编辑 问题是您的 DisplayMessage函数在本地脚本范围内,而您的事件处理程序在不同的父范围内运行(例如全局,即 session 范围),因此它找不到您的函数。如果您在全局范围内创建函数并从全局范围内调用它,它将起作用。

我已经修改了您的脚本来执行此操作。我还修改了 scriptblock 并在脚本完成后取消注册事件,因此当您多次运行脚本时不会收到 10x 消息 :-)

无标题1.ps1

function DoWork
{
  $event = Register-EngineEvent -SourceIdentifier NewMessage -Action {
      global:DisplayMessage $event.MessageData
  }

  $scriptBlock =  {

    Register-EngineEvent -SourceIdentifier NewMessage -Forward

    $message = "Starting work $args"
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message

    ### DO SOME WORK HERE ###

    $message = "Ending work $args"
    $null = New-Event -SourceIdentifier NewMessage -MessageData $message

    Unregister-Event -SourceIdentifier NewMessage
  }

  DisplayMessage("Processing Starts")

  $array = @(1,2,3)
  foreach ($a in $array)
  {
      Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $a | Out-Null
  }

  #$jobs = Get-Job -Name "DoActualWork"
  While (Get-Job -Name "DoActualWork" | where { $_.State -eq "Running" } )
  {
      Start-Sleep 1
  }

  DisplayMessage("Processing Ends")

  #Get-Job -Name "DoActualWork" | Receive-Job
}

function global:DisplayMessage([string]$message)
{
    Write-Host $message -ForegroundColor Red
}

DoWork

Get-EventSubscriber | Unregister-Event

测试
PS > .\Untitled1.ps1
Processing Starts
Starting work 1
Starting work 2
Ending work 1
Ending work 2
Starting work 3
Ending work 3
Processing Ends

关于powershell - 如何从 Start-Job 调用脚本中的 powershell 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15520404/

相关文章:

Powershell 作业内存消耗问题

powershell - 重新提交挂起作业 (start-job)

powershell - 将文件夹日期添加到文件夹名称

powershell - 使用 PowerShell 在复制之前删除部分文件名

windows - PowerShell v3安装错误

java - 如何使用 Twitter4J 进行身份验证?

Powershell Job "Completed"但没有完成它的任务

git - Powershell 在加载 ssh-agent/git 时需要很长时间才能启动

Powershell Start-job 同步输出