Register trackingevent for all background jobs?

Viewed 172

Good afternoon,

I've been working with trying to register an event based on when all jobs are completed. Im able to successfully register one, but id like to get a message pop-up once all background jobs are completed. Anyone familiar with how to do so?

I attempted the following, but it errors out saying jobs is null:

1..10 | ForEach-Object -Process {
    Start-Job { Start-Sleep $_ } -Name "$_" | Out-Null} -OutVariable $jobs

Register-ObjectEvent $jobs StateChanged -Action {
    [System.Windows.MessageBox]::Show('Done')
        $eventSubscriber | Unregister-Event
        $eventSubscriber.Action | Remove-Job
    } | Out-Null

I feel like a Do{}Until() loop can do it but, im not sure how to register that to check until the job has completed. Also tried to follow along with some ways other people have done it using different languages, but, I cant pick it up.

I don't want to post everything ive tried so this post doesn't bore anyone. Searched on google as well but, I couldn't find much on registering an object for multiple jobs.

EDIT Heres what does work:

$job = Start-Job -Name GetLogFiles { Start-Sleep 10 }

Register-ObjectEvent $job StateChanged -Action {
    [System.Windows.MessageBox]::Show('Done')
        $eventSubscriber | Unregister-Event
        $eventSubscriber.Action | Remove-Job
} | Out-Null

Which is what id like to happened, but to evaluate all jobs, not just one.

1 Answers

This is what a personally use when monitoring running jobs:

$jobs= 1..10 | ForEach-Object -Process {
    Start-Job { Start-Sleep $using:_ ; "job {0} done" -f $using:_ } -Name "$_"
}

do{
    $i = (Get-Job -State Completed).count
    $progress = @{
        Activity = 'Jobs completed'
        Status = "$i of {0}" -f $jobs.Count
        PercentComplete = $i / $jobs.count *  100
    }
    Write-Progress @progress
    Start-Sleep -Milliseconds 10
}
until($i -eq $jobs.Count)

$result = Get-Job | Receive-Job

$jobs | Remove-Job

Of course, under certain scenarios where I know some jobs might fail I change the until(...) condition for something different and the do {...} contains the logic for restarting failing jobs.

Edit 1:

It's worth mentioning that Start-Job is not worth your time if you're interested in multithreading, it has been proven to be slower than a linear loop in many scenarios. You should be looking at the ThreadJob Module

Edit 2:

After some testing, this worked for me:

# Clear the Event queue
Get-EventSubscriber|Unregister-Event

# Clear the Job queue
Get-Job|Remove-Job

1..10 | ForEach-Object -Process {
    $job = Start-Job { Sleep -Seconds (1..20|Get-Random) } -Name "$_"
    
    Register-ObjectEvent -InputObject $job -EventName StateChanged -Action {
        $eventSubscriber | Unregister-Event
        $eventSubscriber.Action | Remove-Job
        if(-not (Get-EventSubscriber))
        {
            [System.Windows.MessageBox]::Show('Done')
        }
    } | Out-Null
}

At first I didn't even know this was possible so thanks for pointing this out. Great question :)

Related