I saw this question and this question but couldn't find solution to my problem.
So here is the situation: I have two functions DoWork and DisplayMessage in a script (.ps1) file. Here is the code:
### 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 ###
I am creating 3 background jobs (using $array with 3 elements) and using event to pass messages from background jobs to the host. I would expect the powershell host to display "Processing Starts" and "Processing Ends" 1 time and "Starting work" and "Ending work" 3 times each. But instead I am not getting "Starting work"/"Ending work" displayed in console.
Event is also treated as a job in powershell, so when I do Get-Job, I can see following error associated with the event 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.}
My question: How can we reuse (or reference) a function (DisplayMessage in my case) defined in the same script from where I am calling Start-Job? Is it possible? I know we can use -InitializationScript to pass functions/modules to Start-Job, but I do not want to write DisplayMessage function twice, one in script and another in InitializationScript.
An easy way to include local functions in a background job:
$init=[scriptblock]::create(@"
function DoWork {$function:DoWork}
"@)
Start-Job -Name "DoActualWork" $ScriptBlock -ArgumentList $array -InitializationScript $init | Out-Null