2

On linux, there is the timeout command, which has a very nice and simple syntax:

timeout 120 command [args]

It's simple. It runs the command and kills it if the command runs over the time limit. Despite my best efforts, "solutions" on windows are multiple lines, don't display the output of the command to the terminal, and the cygwin "timeout" failed to kill the process if I increased the timeout to more than one minute (I have no explanation for this). Does anyone have a better idea?

xaav
  • 7,876
  • 9
  • 30
  • 47
  • 3
    Possible duplicate of [adding a timeout to batch/powershell](https://stackoverflow.com/questions/21176487/adding-a-timeout-to-batch-powershell) – Kory Gill Sep 23 '17 at 00:49
  • That linked solution doesn't display output to the screen as it is running. – xaav Sep 23 '17 at 01:00
  • You could do something like `for /f "tokens=3 delims=; " %I in ('wmic process call create "ping localhost -n 10" ^| find "ProcessId"') do >NUL (timeout /t 5 /nobreak && taskkill /im %I)` in the cmd console, or double the `%%` in a bat script. If you're putting this in a bat script, you can dress it up by putting it in a function then `call`ing the function. If console, you could set a `doskey` macro. – rojo Sep 23 '17 at 01:05
  • @rojo That's almost fine, but the stdout occurs in a new window. Is there any way to capture the stdout in the same window? – xaav Sep 23 '17 at 01:12
  • @xaav I was thinking maybe something with `start /b`, but there'd be no easy way to get the spawned process's PID. You'd have to `taskkill /im "imagename eq ping.exe"` or similar, which might have unfortunate effects of your executable is running in multiple concurrent windows. Also, that'd make the program non-interactive, if that matters. – rojo Sep 23 '17 at 01:15
  • Well, if the program was interactive, then it wouldn't need timeout. – xaav Sep 23 '17 at 01:16
  • It's fine, rojo. I'll write my own program for this. – xaav Sep 23 '17 at 01:18

1 Answers1

3

I mean there is timeout.exe but I don't think that gives you quite the same functionality that you are looking for.

I am not aware of a timeout equivalent for Windows. Following the suggestion in the linked answer PowerShell jobs would be a suggestion on how to replicate timeouts behavior. I rolled a simple sample function

function timeout{
    param(
        [int]$Seconds,
        [scriptblock]$Scriptblock,
        [string[]]$Arguments
    )

    # Get a time stamp of before we run the job
    $now = Get-Date 

    # Execute the scriptblock as a job
    $theJob = Start-Job -Name Timeout -ScriptBlock $Scriptblock -ArgumentList $Arguments

    while($theJob.State -eq "Running"){
        # Display any output gathered so far. 
        $theJob | Receive-Job

        # Check if we have exceeded the timeout.
        if(((Get-Date) - $now).TotalSeconds -gt $Seconds){
            Write-Warning "Task has exceeded it allotted running time of $Seconds second(s)."
            Remove-Job -Job $theJob -Force
        }
    }

    # Job has completed natually
    $theJob | Remove-Job -ErrorAction SilentlyContinue
}

This starts a job and keeps checking for its output. So you should get near live updates of the running process. You do not have to use -ScriptBlock and could opt for -Command based jobs. I will show an example using the above function and a script block.

timeout 5 {param($e,$o)1..10|ForEach-Object{if($_%2){"$_`: $e"}else{"$_`: $o"};sleep -Seconds 1}} "OdD","eVeN"

This will print the numbers 1 to 10 as well as the numbers evenness. Between displaying a number there will be a pause of 1 second. If the timeout is reached a warning is displayed. In the above example all 10 number will not be displayed since the process was only allowed 5 seconds.

Function could use some touching up and likely there is someone out there that might have done this already. My take on it at least.

Matt
  • 45,022
  • 8
  • 78
  • 119