0

When I break out of a PowerShell 7 script using Ctrl-C I'll get any jobs running, left running. I might also leave files I've been working with in state that is not desirable.

I did find a way to detect the key press, but either it's consuming to much CPU or is very unresponsive (or both).

See

When using the example below, the detection of Ctrl-C is very sluggish or will consume a lot of CPU resources (or both).

[Console]::TreatControlCAsInput = $true
sleep 1
$Host.UI.RawUI.FlushInputBuffer()

Start-ThreadJob {# Do something
  sleep 5
} -Name 'SomeJob'

Start-ThreadJob {# Do another thing
  sleep 5
} -Name 'OtherJob'

while (Get-Job | where State -ne 'Stopped') {# Run the main loop

  if (# Some key was pressed
    $Host.UI.RawUI.KeyAvailable -and
    ($Key = $Host.UI.RawUI.ReadKey("AllowCtrlC,NoEcho,IncludeKeyUp"))
  ) {
    if ([int]$Key.Character -eq 3) {# Ctrl-C pressed
      Get-Job | Remove-Job -Force

      [Console]::TreatControlCAsInput = $false

      return

    }#end Ctrl-C pressed

  }#end Some key was pressed

  # sleep -Milliseconds 200
  $Host.UI.RawUI.FlushInputBuffer()
  
}

Is there a good way to increase the responsiveness in the key detection?

Dennis
  • 871
  • 9
  • 29

1 Answers1

1

You're trying to solve the problem the wrong way, the finally block is designed specifically for this. See Freeing resources using finally.

Regarding high CPU and memory consumption with your current code, you already have the answer except that it should be uncommented (sleep -Milliseconds 200).

try {
    $jobs = @(
        Start-ThreadJob {
            Start-Sleep 10
        } -Name 'SomeJob'

        Start-ThreadJob {
            Start-Sleep 10
        } -Name 'OtherJob'
    )

    $jobs | Receive-Job -Wait -AutoRemoveJob
}
# this block will always run, even on CTRL+C
finally {
    $jobs | Remove-Job -Force
}

Get-Job # should be empty
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    Yes, this is the second solution I've seen. But using a 'try - catch' construct will trigger on any error. If an error really occurs, I would like to keep what ever is happening with the jobs... – Dennis Aug 30 '23 at 17:10
  • @Dennis can you explain what you mean by "I would like to keep what ever is happening with the jobs.." ? – Santiago Squarzon Aug 30 '23 at 17:11
  • On an error (other than Ctrl-C), I need to keep the state of the jobs for trouble shooting and not delete them... This way, the jobs will *always* be deleted, no matter what kind of error that occurs, – Dennis Aug 30 '23 at 17:13
  • what could be an error other than Ctrl+C ? @Dennis. if there was an error it would happen in the Job's scope, how are you planning to troubleshoot that ? also `$jobs | Stop-Job` instead of `$jobs | Remove-Job` is possible to use. – Santiago Squarzon Aug 30 '23 at 17:20
  • I usually pull the output stream from the jobs., to for example able to restart them if necessary based on the result. But my main loop might contain other code that might fail with a terminating error (especially when working with remote computers). I need a way to keep the state of my code in case of a real error occurs. – Dennis Aug 30 '23 at 17:28
  • Yes, `Get-Job | Stop-Job` would be a viable work around. And I can always start the main loop with first removing any leftover jobs from before :) – Dennis Aug 30 '23 at 17:29