Search code examples
batch-filebatch-processing

Check with batch if the process is answering or not


:loop
>nul timeout /t 600 /nobreak
powershell -ExecutionPolicy Unrestricted -c "Get-Process -Name programm | Where-Object -FilterScript {$_.Responding -eq $false}"
if not errorlevel 1 goto loop

This is not working, I think the errorlevel is the problem, but I cant solve it. I want to check if the process is answering or not. If not I want to check the process again after a timeout.

I thank you in advance for your help.


Solution

  • Read Errorlevel and Exit codes:

    Almost all applications and utilities will set an Exit Code when they complete/terminate. The exit codes that are set do vary, in general a code of 0 (false) will indicate successful completion.

    When an external command is run by CMD.EXE, it will detect the executable's Return or Exit Code and set the ERRORLEVEL to match. In most cases the ERRORLEVEL will be the same as the Exit code, but there are some cases where they can differ.

    It's Exit Code for PowerShell as shown in the following examples:

    • Unsuccessful completion ( errorlevel 1 ):
    ==> powershell -noprofile -c "Get-Process -Name invalid_programm"
    Get-Process : Cannot find a process with the name "invalid_programm". Verify the process name and call the cmdlet again.
    At line:1 char:1
    + Get-Process -Name invalid_programm
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (invalid_programm:String) [Get-Process],ProcessCommandException
        + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=1
    
    • Successful completion ( errorlevel 0 )
    ==> powershell -noprofile -c "return 1"
    1
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=0
    
    • Successful completion ( errorlevel set explicitly using the exit keyword)
    ==> powershell -noprofile -c "exit 2"
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=2
    

    Hence, you could use the following code snippet (which should always successfully complete):

    try { 
        $x = @(Get-Process -Name programm -ErrorAction Stop | 
                 Where-Object -FilterScript {-not $_.Responding})
        exit $x.Count
    } catch { 
        exit 5000          # or other `absurd` value
    }
    

    Rewriting the above as an one-liner (using aliases), you could meet following scenarios:

    1. A process with specified name not found
    ==> powershell -noprofile -c "try{$x=@(gps programm -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=5000
    
    1. A process with specified name found & responding
    ==> powershell -noprofile -c "try{$x=@(gps cmd -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=0
    
    1. One process with specified name found & NOT responding
    ==> powershell -noprofile -c "try{$x=@(gps HxOutlook -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=1
    
    1. More processes with specified name found & NOT responding
    ==> powershell -noprofile -c "try{$x=@(gps -EA Stop|? {-not $_.Responding});exit $x.Count} catch {exit 5000}"
    
    ==> echo errorlevel=%errorlevel%
    errorlevel=4
    

    Please note incompleteness of above enumeration: we could imagine scenario where run more processes with specified name, some of them responding while other not-responding.
    (In other words, found & NOT responding does not imply that there does not exist another found & responding of the same name…)