title: Powershell: Updating GUI from background job results
body: <p><strong>EDIT :</strong> I was able to get it working, see below for my solution. The commenters below are correct that Powershell isn't really ideal for GUI's and threading, but it can be done.</p>
  
  <hr>
  
  <p>I've got a form in Powershell that uses Start-Job to run functions in the background without freezing the GUI. My goal is to continuously check the status of those jobs for their output. I managed to use the Windows Forms Timer to check the results of the job and update the GUI accordingly.</p>
  
  <p>It's all working fine, but it seems sloppy. Is this the best way to accomplish a GUI refresh? I'm relatively new to Powershell and I want to improve my coding.</p>
  
  <p>Example of what I'm doing:</p>
  
  <pre><code>$jobScript = {
      Start-Sleep 5
      Write-Output "The job has finished running"
  }
  
  $timerScript = {
      $timer.Stop()
      $jobResult = Get-Job | Receive-Job -Keep
      if ($jobResult) {
          $btn.text = $jobResult
      } else {
          $timer.Start()
      }
  }
  
  Add-Type -AssemblyName System.Windows.Forms
  $form             = New-Object System.Windows.Forms.Form
  $form.ClientSize  = '300,300'
  $form.topmost     = $true
  
  $btn              = New-Object System.Windows.Forms.Button
  $btn.Text         = "The job is still running"
  $btn.Width        = 300
  $btn.Height       = 300
  $form.Controls.Add($btn)
  
  $timer            = New-Object System.Windows.Forms.Timer
  $timer.Interval   = 100
  $timer.add_Tick($timerScript)
  $timer.Start()
  
  Start-Job -ScriptBlock $jobScript
  
  $form.ShowDialog()
  </code></pre>
  
  <hr>
  
  <p><strong>Update: My solution</strong></p>
  
  <p>Using <code>Register-ObjectEvent</code> did not work, it seemed like it was fighting with the GUI for the thread. Instead I was able to use <code>[System.Windows.Forms.Application]::DoEvents()</code>. This allows the GUI to be moved around, and once it's done being moved, the thread will resume. The big caveat here is that execution is paused as long as the GUI is being moved, so if your code needs to react to the background job on a time limit, this could cause errors.</p>
  
  <p>Example code block:</p>
  
  <pre><code>$jobScript =
  {
      Start-Sleep 5
      Write-Output "The job is completed"
  }
  
  Add-Type -AssemblyName System.Windows.Forms
  $form             = New-Object System.Windows.Forms.Form
  $form.ClientSize  = '300,300'
  $form.topmost     = $true
  
  $btn              = New-Object System.Windows.Forms.Button
  $btn.Text         = "..."
  $btn.Width        = 300
  $btn.Height       = 300
  $form.Controls.Add($btn)
  
  $btn.add_click({
      $btn.Text = "Starting job"
      $jobby = Start-Job -ScriptBlock $jobScript
      Do {[System.Windows.Forms.Application]::DoEvents()} Until ($jobby.State -eq "Completed")
      $btn.Text = Get-Job | Receive-Job
  })
  
  $form.ShowDialog()
  </code></pre>