我看到了this question和 this 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/