6

I am executing following command in a label inside a batch file:

tasklist.exe /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2" 2>nul && echo errorl:%errorlevel%

%1 is process running and %2 is its PID. Even if process and its PID matches or doesnt matches, I m getting "errorl:1" in o/p.

I am not sure whats wrong here. Any idea?

jeb
  • 78,592
  • 17
  • 171
  • 225
user613114
  • 2,731
  • 11
  • 47
  • 73

5 Answers5

9

You could pipe tasklist through the find command and get an errorlevel off of it.

Example:

tasklist | find "firefox.exe"
echo Error level = %ERRORLEVEL%

REM If firefox is running, the errorlevel is set to 0
REM If firefox is not running, errorlevel is set to 1
Bill
  • 91
  • 1
  • 2
7

In my opinion, you can't use errorlevel at all,
because tasklist always returns a 0 even if the pid isn't found.

I suppose, you have to parse the output of tasklist.
To fetch the output of a command, FOR /F is a good choice.

To avoid problems wth the quoting in the FOR /F, I build first a cmd variable which is expanded with delayed expansion to avoid any side effects of special characters.

@echo off
setlocal enableDelayedExpansion

set "cmd=tasklist.exe /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2""

for /F "delims=*" %%p in ('!cmd! ^| findstr "%2" ') do (
  echo found %%p
)
jeb
  • 78,592
  • 17
  • 171
  • 225
  • Hello Jeb, Your modification worked perfectly :D Thank you very much. – user613114 Feb 11 '11 at 14:04
  • This code is somewhat shorter than mine, but I prefer to run with enableDelayedExpansion turned off to reduce string expansion problems, also FINDSTR is XP+ – Anders Feb 11 '11 at 22:06
  • @jeb It would be good to explain why a FOR loop is used here, and secondly explain the role of delayed expansion in this context. For example, wouldn't `FOR /F "delims=*" %%P IN ('tasklist.exe /NH /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2"') DO ECHO found %%P` yield exactly the same output? – Jimadine Dec 29 '19 at 18:38
  • @Jimadine Thanks for the hint. I edited the answer. To your question: I suppose you need the `... | findstr "%2"` to be sure to find only matches, but not messages like `there is no such process`. But currently I can't retest this, as I'm on Ubuntu (most of the time) – jeb Dec 29 '19 at 19:40
  • @jeb Thanks for adding the explanation. You are right, `findstr` filters out tasklist's `INFO: No tasks are running which match the specified criteria.` messages – Jimadine Dec 30 '19 at 10:46
2

%variables% are expanded before executing the line, so %errorlevel% will expand to some old value. (The fact that the code after && executes at all is your clue that the command returned 0)

You options are:

  • Use %errorlevel% or the more correct IF errorlevel 1 ... on the next line
  • Call setlocal ENABLEDELAYEDEXPANSION first and then use !errorlevel!

Edit: I guess tasklist is buggy and/or stupid when it comes to exit codes, I wrote some code that does not use the exit code at all:

@echo off
if "%~1"=="SOTEST" (
    start calc
    ping -n 2 localhost >nul
    for /F "tokens=1,2 skip=3" %%A in ('tasklist /FI "IMAGENAME eq calc.exe"') do (
        call "%~0" %%A %%B
    )
    call "%~0" dummy.exe 666
    goto :EOF
)
goto main


:IsTaskRunning
setlocal ENABLEEXTENSIONS&set _r=0
>nul 2>&1 (for /F "tokens=1,2" %%A in ('tasklist /FO LIST %*') do (
    if /I "%%~A"=="PID:" set _r=1
))
endlocal&set IsTaskRunning=%_r%&goto :EOF

:main
call :IsTaskRunning /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2"
if %IsTaskRunning% gtr 0 (echo.%1:%2 is running) else (echo.%1:%2 is NOT running)

Run it as test.cmd SOTEST and it prints:

calc.exe:4852 is running
dummy.exe:666 is NOT running
Anders
  • 97,548
  • 12
  • 110
  • 164
  • But: IF errorlevel 1 is true, if the errorlevel is 1 or greater 1, this could be unexpected behaviour, I prefer IF %errorlevel% EQU 1 or IF %errorlevel% GTR 1 – jeb Feb 11 '11 at 14:00
  • Hi Anders,I am already using setlocal ENABLEDELAYEDEXPANSION in my batch script and accessing the params the same way you described. But it didnt work. – user613114 Feb 11 '11 at 14:03
  • @user613114: Just setting ENABLEDELAYEDEXPANSION is not enough, are you using !errorlevel! and not %errorlevel%? – Anders Feb 11 '11 at 20:00
  • But even !errorlevel! doesn't work, as errorlevel only gets 1, if the parameter format is wrong – jeb Feb 11 '11 at 21:33
1

Easy solution to this, given that

 1) you can't get an errorlevel from tasklist, and
 2) you can't directly pipe it to a FIND

Just write it to a file using output redirection and use FIND to check the file. Each time this is run, it will overwrite the previous iteration, so no need to even do any file cleanup. Amazing how many bat/cmd file limitations can be overcome with a simple scratchpad file!!

:TOP
rem swap rems from good to bad to test
set findvar=goodfile.exe          
rem set findvar=badfile.exe
set scratchfile=scratch.txt
tasklist /fi "status eq running" /fi "imagename eq %findvar%">%scratchfile%
type %scratchfile%
pause
echo Looking for %findvar%
find "%findvar%" %scratchfile%
echo Error level = %errorlevel%
pause
IF errorlevel 1 GOTO BAD
IF errorlevel 0 GOTO GOOD
GOTO OTHER

:BAD
 echo Errrlevel 1 - task not found
 PAUSE     
 GOTO TOP
:GOOD
 echo Errrlevel 0 - task is running
 pause
 GOTO TOP
:OTHER
 echo something else ????? you blew it somewhere!
Jimbocous
  • 11
  • 2
0

tasklist returns 0 when executes successfully:
If you're looking for existence of some process or some attribute of a process, one method is to supply the attributes to tasklist and check if it returned any process names. If no matching processes are found, it'll return "INFO: No tasks are running which match the specified criteria."

The result of tasklist may be checked either via for command embedding (and parse command output) or filter via find or findstr, which accepts regular expressions & wildcards.

eg. To check if the any process is running with following criteria:

tasklist.exe /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FI "IMAGENAME eq %1" /FI "PID eq %2" | find /v "No task" >nul && (echo process exists) || (echo na man).

Above method can also find if any document (window) is open, in addition to the underlying process, like "firefox.exe".
eg. close high speed vpn ad window if/when it pops up without notice:

tasklist /fi "windowtitle eq High-Speed*" | find /v "No task" >nul && (taskkill /fi "windowtitle eq High-Speed*")

Tested on Win 10 CMD

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Zimba
  • 2,854
  • 18
  • 26