Last active
November 8, 2022 19:19
-
-
Save inkychris/e9b7bd1eb4caf710cc60c53a8d6f4bfb to your computer and use it in GitHub Desktop.
Timeout process wrapper for Powershell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param( | |
[int][Parameter(Mandatory)]$Timeout, | |
[int][Parameter(Mandatory)]$KillTimeout, | |
[string[]][Parameter(Mandatory, ValueFromRemainingArguments)]$Arguments | |
) | |
$ErrorActionPreference = "stop" | |
$ArgumentsString = $Arguments[1..$Arguments.Length] -replace "^|$", "`"" -join " " | |
$timeout_reached = $null | |
$process = Start-Process $Arguments[0] -NoNewWindow -PassThru -ArgumentList $ArgumentsString | |
$process | Wait-Process -Timeout $Timeout -ErrorAction SilentlyContinue -ErrorVariable timeout_reached | |
if ($timeout_reached) { | |
Write-Host "[$($process.id)] ${Timeout}s timeout reached: sending ctrl-C event ..." -ForegroundColor DarkYellow | |
Start-Job -ArgumentList $process.id -ScriptBlock { | |
param([int]$process_id) | |
write-host "job pid $process_id" | |
$MemberDefinition = ' | |
[DllImport("kernel32.dll")]public static extern bool FreeConsole(); | |
[DllImport("kernel32.dll")]public static extern bool AttachConsole(uint p); | |
[DllImport("kernel32.dll")]public static extern bool GenerateConsoleCtrlEvent(uint e, uint p); | |
public static void SendCtrlC(uint p) { | |
FreeConsole(); | |
if (AttachConsole(p)) { | |
GenerateConsoleCtrlEvent(0, p); | |
FreeConsole(); | |
} | |
AttachConsole(uint.MaxValue); | |
}' | |
Add-Type -Name 'Cleanup' -Namespace 'Process' -MemberDefinition $MemberDefinition | |
[Process.Cleanup]::SendCtrlC($process_id) | |
} | Out-Null | |
} | |
$kill_timeout_reached = $null | |
$process | Wait-Process -Timeout $KillTimeout -ErrorAction SilentlyContinue -ErrorVariable kill_timeout_reached | |
if ($kill_timeout_reached) { | |
Write-Host "[$($process.id)] ${KillTimeout}s kill-timeout reached: killing process ..." -ForegroundColor DarkRed | |
$process.kill($true) | |
exit 1 | |
} | |
exit $process.ExitCode |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Huge thanks to everyone in this Stackoverflow thread that provided all the important bits!
I'd gotten stuck for a while with having the calling Powershell process being terminated too, until I tried calling
SendCtrlC
from a separate process too. Got that idea from the Python solution, which was spawning a subprocess for the script.To properly work correctly with any sub-process, this script should be called like so:
to avoid powershell trying and sometimes failing to parse program arguments, e.g.
-i
.