1

I have a command running in PowerShell, and it will unpredictably error out (whenever the network connection becomes saturated, it errors)

After it errors, it will no longer function as intended, but continue to run. The error is also not printed as an error, just as standard text.

I would like to have the command running in a loop that detects when it errors, then kills it, and restarts it, but I have been unable to find anything about parsing the output of a command in real-time.

For example: foo.ps1 outputs a number every second, but will randomly begin outputting "ERROR: CONNECTION SATURATED" once every second instead. How can I create a loop that detects that, kills the process, and restarts it?

EDIT: command erroring This is what the command erroring looks like. As you can see, the error (Warning: ring buffer overflow!!!) is printed as stdout, not as an error.

dfsek
  • 13
  • 1
  • 4

3 Answers3

0

you can use trap keyword to detect the error and handle it, i.e.

function Test {
    Write-Host "Doing something..."
    trap {
        Write-Host "Error found:"
        break
    }

    Write-Host "Code should not reach here"
}

to catch a specific exception, you can specify what you want to trap as

...
trap [TheExceptionYouWantToCatch]{
...
}
...
Simas Joneliunas
  • 2,890
  • 20
  • 28
  • 35
  • I have tried using trap, but the "error" that the command gives is not an actual trap-able error, it is just regular stdout, the only way to differentiate it from regular behavior is that it is always the same text, which is different than normal behavior (the exact text is `Ring buffer overflow!!!`, that string never occurs in normal behavior) – dfsek Jan 03 '20 at 02:35
  • I have not had to work much with capturing stdout, but a quick search has led me to this(https://stackoverflow.com/a/11549817/3986395) answer, maybe it can help you to get your stdout into `try`/`trap` block – Simas Joneliunas Jan 03 '20 at 02:42
0

This is peculiar, but "select -first 1" kills the pipeline when it finds an answer. Like this will only run for only 5 seconds.

& { foreach ($i in 1..10) { $i; sleep 1 } } | where { $_ -eq 5 } | 
  select -first 1  
js2010
  • 23,033
  • 6
  • 64
  • 66
0

It should go without saying that you cannot use the standard PowerShell error handling mechanisms since your command neither raises an exception nor writes to the error stream. As such, you must parse the command's output as it is generated (i.e. asynchronously).

The easiest way to run a command and access its output asynchronously is by using a job. As such, the following script should accomplish what you are asking for:

param(
    # Specifies the commands to run in the job.
    [ScriptBlock] $ScriptBlock,

    # Specifies the text for which to search in each line of the output.
    [string] $Pattern = '^\s*(Warning|Error)',

    # Specifies how long to sleep in seconds between output searches.   
    [int] $Seconds = 1
)

while ($true) {
    $job = Start-Job $ScriptBlock
    while ($job.State -eq 'Running') {
        $output = Receive-Job $job
        if ($output -match $Pattern) {
            break
        }
        Start-Sleep $Seconds
    }
    Stop-Job $job
}

Depending on your requirements, you may also want to:

  • Expand the set of acceptable job states.
  • Terminate the script entirely (i.e. without restarting the job) if some particular job state or other output pattern is encountered.
Travis
  • 2,135
  • 17
  • 29