10

A script is executing the following steps in a loop, assume both steps take a long time to complete:

  1. $x = DoSomeWork;
  2. Start-Job -Name "Process $x" { DoSomeMoreWork $x; };

Step 1 blocks the script and step 2 does not, of course. I can easily monitor the progress/state of the loop and step 1 through the console.

What I'd also like to do is monitor the job status of jobs started by step 2 while the batch is still executing.

In general, it is possible to 'attach' or query another powershell session from another session? (Assuming the monitoring session does not spawn the worker session)

Serguei
  • 2,910
  • 3
  • 24
  • 34
  • 1
    You is a bad boy using method call syntax in your example. PowerShell functions do not use parentheses and are a parse error under strict mode parsing in v2 (which is not on by default.) – x0n Dec 01 '10 at 02:38
  • @x0n, nice catch! In my defense I was originally invoking the methods on .NET objects but decided to simplify in the example (at the cost of correctness!) =) – Serguei Dec 01 '10 at 02:44
  • Np, and I have answered below for you. – x0n Dec 01 '10 at 02:57

2 Answers2

6

If I'm following you, then you cannot share state between two different console instances. That is to say, it's not possible in the way you want to do it. However, it's not true that you cannot monitor a job from the same session. You can signal with events from within the job:

Start-Job -Name "bgsignal" -ScriptBlock {

    # forward events named "progress" back to job owner
    # this even works across machines ;-)
    Register-EngineEvent -SourceIdentifier Progress -Forward

    $percent = 0
    while ($percent -lt 100) {
        $percent += 10

        # raise a new progress event, redirecting to $null to prevent
        # it ending up in the job's output stream
        New-Event -SourceIdentifier Progress -MessageData $percent > $null

        # wait 5 seconds
        sleep -Seconds 5
    }
}

Now you have the choice to either use Wait-Event [-SourceIdentifier Progress], Register-EngineEvent -SourceIdentifier Progress [-Action { ... }] or plain old interactive Get-Event to see and/or act on progress from the same session (or a different machine if you started the job on a remote server.)

It's also entirely possible you don't need the Jobs infrastructure if all work is being done on the local machine. Take a look at an old blog post of mine on the RunspaceFactory and PowerShell objects for a rudimentary script "threadpool" implementation:

http://www.nivot.org/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators.aspx

Hope this helps,

-Oisin

x0n
  • 51,312
  • 7
  • 89
  • 111
2

State is easy to monitor:

$job = Start-Job -Name "Process $x" { DoSomeMoreWork $x }
$job.state

If you don't need to retrieve any output data from the function then you can write to output like so:

$job = Start-Job {$i=0; while (1) { "Step $i"; $i++; Start-Sleep -sec 1 }}
while ($job.State -eq 'Running')
{
    Receive-Job $job.id
}

If you do need to capture the output, then you could use the progress stream I think:

$job = Start-Job {$i=0; while (1) { 
                  Write-Progress Activity "Step $i"; $i++; Start-Sleep -sec 1 }}
while ($job.State -eq 'Running') {
    $progress=$job.ChildJobs[0].progress; 
    $progress | %{$_.StatusDescription}; 
    $progress.Clear(); Start-Sleep 1 }
x0n
  • 51,312
  • 7
  • 89
  • 111
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 4
    Yes, but the crux of my question is how do you populate get the $job variable from another powershell session? (e.g. another powershell window) I can't monitor the state from the same session because it's blocked by execution of {$x = DoSomeWork();} from the next iteration. – Serguei Nov 30 '10 at 22:59
  • Not answering the ops question. – JDuarteDJ Jun 21 '21 at 16:37