How to check if multiple processes is running via a batch script - batch-file

I got this script form stackoverflow and its working for me . and because i can't comment there im asking my question in new post.
This script check if exe is running in tasklist:
#echo off
SETLOCAL EnableExtensions
set EXE=notepad.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto ProcessFound
goto ProcessNotFound
:ProcessFound
echo %EXE% is running
goto END
:ProcessNotFound
echo %EXE% is not running
goto END
:END
echo Finished!
The question is :
How can I check multiple process is running on tasklist?
for example exe1 and exe2
thanks in advance

From your comments; if all you want to do is run a third executable if neither of two other executables are running then here is a single line complete batch file example for you:
#TaskList/NH /FI "Status Eq Running"|FindStr/IC:"first.exe" /C:"second.exe">Nul||Start "" "X:\PathTo\third.exe"
Note:Do not change anything other than the names first, second and X:\PathTo\third; all double quotes, ", are necessary!

I've organised your code a bit differently so it's easier to follow and has more functionality. Note: This means it will be slower if you have lots of processes. If you wish to only see if it exists, I'd recommend using findstr.
I've added REM (batch-file equivalent for comments) explaining what each section does.
#echo off
REM Create variable's for exe's and their counter
set exe_1=notepad.exe
set exe_2=explorer.exe
set exe_3=chrome.exe
set "count_1=0"
set "count_2=0"
set "count_3=0"
REM Store all tasklist findings in a temp file
>tasklist.temp (
tasklist /NH /FI "IMAGENAME eq %exe_1%"
tasklist /NH /FI "IMAGENAME eq %exe_2%"
tasklist /NH /FI "IMAGENAME eq %exe_3%"
)
REM Go through all finds and count for each task instance
for /f %%x in (tasklist.temp) do (
if "%%x" EQU "%exe_1%" set /a count_1+=1
if "%%x" EQU "%exe_2%" set /a count_2+=1
if "%%x" EQU "%exe_3%" set /a count_3+=1
)
REM Use variables to see instance count
Echo %exe_1%: %count_1%
Echo %exe_2%: %count_2%
Echo %exe_3%: %count_3%
REM Use GTR 0 to see if process exists
if %count_1% GTR 0 if %count_2% GTR 0 Echo Both notepad and explorer are open
REM Delete temp file once finished. (NB: Will still exist if your code crashes)
del tasklist.temp
Conditional if-statements
As requested from your comment:
if %count_1% GTR 0 if %count_2% GTR 0 (
Echo Both notepad and explorer are open
goto :finish
)
if %count_1% GTR 0 (
Echo Only notepad is open
goto :finish
)
if %count_2% GTR 0 (
Echo Only explorer is open
goto :finish
)
REM Not Finished means none are open
Echo Neither notepad nore explorer are open
:finish

Here is my solution, keeping a similar structure to that of your sample script. Modify the EXE variable to reference the IMAGENAMEs you're interested in checking.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET EXE=(notepad.exe wordpad.exe winword.exe thunderbird.exe outlook.exe greenshot.exe)
FOR %%i IN %EXE% DO (
TASKLIST /NH /FI "IMAGENAME EQ %%i" 2>NUL | FIND /I /N "%%i">NUL
IF !ERRORLEVEL! EQU 0 ( CALL :ProcessFound %%i ) ELSE ( CALL :ProcessNotFound %%i )
)
ECHO Finished^^!
EXIT /B 0
:ProcessFound
ECHO %1 is running
EXIT /B 0
:ProcessNotFound
ECHO %1 is not running
EXIT /B 1
If you want to start the program when the process is not found, insert START %1 after ECHO %1 is not running.

Related

Is there a way to do this less time consuling within one check?

I have this batch code and its working perfectly well, BUT:
every line take ~60 seconds to execute and I'm wondering, if I could do this faster...
Also the if Statements.. I want to check, if every Window is closed, and if so, I want to execute something. But if at least one window is still open, then it should check it again.
:loop
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server1%" /FO Table') do set #1=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server2%" /FO Table') do set #2=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server3%" /FO Table') do set #3=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server4%" /FO Table') do set #4=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server5%" /FO Table') do set #5=%%i
for /f %%i in ('tasklist /v /fi "WINDOWTITLE eq %server6%" /FO Table') do set #6=%%i
if not %#1%==cmd.exe (
if not %#2%==cmd.exe (
if not %#3%==cmd.exe (
if not %#4%==cmd.exe (
if not %#5%==cmd.exe (
if not %#6%==cmd.exe (
goto backup
)
)
)
)
)
) else (
echo back to loop
goto openWindow
)
Let me suggest a slightly different approach. Instead of all those if statements, you can just loop whenever one of the tasks exist:
:wait
timeout 1 >nul
for %%a in (%server1% %server2% %server3% %server4% %server5% %server6%) do (
tasklist /nh /fi "windowtitle eq %%a" |find " " >nul && goto :wait
)
echo all closed.
or
setlocal enabledelayedexpansion
:wait
timeout 1 >nul
for /l %%a in (1,1,6) do (
tasklist /nh /fi "windowtitle eq !server%%a!" |find " " >nul && goto :wait
)
echo all closed.
Note: find " " looks for two consecutive spaces, not a TAB)
If you choose your window titles wisely, you don't even need a for loop:
:wait
timeout 1 >nul
tasklist /nh /fi "windowtitle eq MySubWindow*" |find " " >nul && goto :wait
echo all closed.
where the window titles all start with a fixed string (MySubWindow here), like MySubWindow-1, MySubWindow-2 etc. (yes, tasklist is able to use a wildcard - but only at the end of the string). This is basically "if any window exists with a title that starts with MySubWindow then loop"
little optimization of Stephan answer.
This execute faster.
:wait
timeout 1 >nul
for %%a in (%server1% %server2% %server3% %server4% %server5% %server6%) do (
if not defined v%%a tasklist /nh /fi "windowtitle eq %%a" |find " " >nul && goto :wait
set v%%a=done
)
echo all closed.
You have not explained how your 6 Batch files are "open", but if they are open via START command, then there is a much simpler way to do the same:
(
start call batch1.bat
start call batch2.bat
start call batch3.bat
start call batch4.bat
start call batch5.bat
start call batch6.bat
) | pause
echo All 6 Batch files are closed
The previous code run the 6 Batch files in parallel and then the control flow is stopped at the pause command. When all the 6 Batch files terminates, this program continue.
Note that there is not any Batch code that check if the procesess ends; this is done automatically by the Operating System. In this way, the wait state of this program does not waste any CPU time. For a further explanation, see this answer
Without being able to test this, perhaps it would be quicker to run just one tasklist command per loop:
#Echo Off
SetLocal EnableExtensions
:Loop
For /F Tokens^=17^ Delims^=^" %%G In (
'%SystemRoot%\System32\tasklist.exe /Fi "ImageName Eq cmd.exe" /Fo CSV /NH /V 2^>NUL'
) Do Set /P "=%%G" 0<NUL | %SystemRoot%\System32\findstr.exe /I ^
"\<%server1%\> \<%server2%\> \<%server3%\> \<%server4%\> \<%server5%\> \<%server6%\>" 1>NUL && GoTo Loop
:Backup
The findstr.exe options may need to be adjusted depending upon the content of those variables.

Run bat files in parallel and wait until they are finished before run new set of bat files

I have a series of bat files that I want to run in parallel, for example:
start program1_1.bat
start program1_2.bat
start program1_3.bat
wait until program1 finished then
start program2_1.bat
start program2_2.bat
start program2_3.bat
wait until program2 finished then
...
So far, what I've tried is this function:
:waitForFinish
set counter=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe') do set /a counter=counter+1
if counter GTR 2 Goto waitForFinish
But it just launched the first 3 bat files and stop... How can I solve this problem?
Thanks,
EDIT: This is the content of program1_i.bat file:
program1.exe input_i.txt
It will run program1.exe for each input file. The same for program2_i.bat.
Your question is a little vague on the exact expected results.
I am however assuming that you want to do something like this.
start /wait program1_1.bat | start /wait program1_2.bat | start /wait program1_3.bat
start /wait program2_1.bat | start /wait program2_2.bat | start /wait program2_3.bat
The single pipe separators let's us launch the first three commands in parallel and only start the next three commands once the first three has all completed, simply because the next 3 commands are in the next batch line the use of start /wait
* Update *
The solution provided here works nicely to achieve parallel running of subprograms without needing user entry (pause) or a fixed length Timeout between program groups.
Combined with the original answer:
#echo off
:controller
Call :launcher "program1_1.bat" "program1_2.bat" "program1_3.bat"
Call :launcher "program2_1.bat" "program2_2.bat" "program2_3.bat"
pause
EXIT
:launcher
For %%a in (%*) Do (
Start "+++batch+++" "%%~a"
)
:loop
timeout /t 1 >nul
tasklist /fi "windowtitle eq +++batch+++*" |find "cmd.exe" >nul && goto :loop
GOTO :EOF
Original Answer:
This is a simple way to ensure each group of programs is finished before the next. The fault in the tasklist method is that if there's other cmd.exe processes running, the If condition may not be true when expected, causing the script to hang.
The start /wait option is not ideal, as you intend on running multiple programs simultaneously - and if the subprogram you wait on finishes before the other subs, you're back to square 1.
#echo off
:controller
Call :launcher "program1_1.bat" "program1_2.bat" "program1_3.bat"
Call :launcher "program2_1.bat" "program2_2.bat" "program2_3.bat"
pause
EXIT
:launcher
For %%a in (%*) Do (
Start "" "%%~a"
)
pause
GOTO :EOF
Ok, here is what worked for me:
#echo off
setlocal enableextensions enabledelayedexpansion
call :InitDos
start program1_1.bat
start program1_2.bat
start program1_3.bat
call :waitForFinish
start program2_1.bat
start program2_2.bat
start program2_3.bat
call :waitForFinish
Goto:eof
: waitForFinish
set /a counter=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe"') do (
set /a counter+=1
)
if !counter! GTR !init_count! Goto waitForFinish
goto :eof
: InitDos
set /a init_count=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe"') do (
set /a init_count+=1
)
goto :eof
Try /WAIT switch on start command. I guess if you wrap bats into script called with wait switch, it could work.

Missing operator error using batch file

I've been trying to create a little batchscript to get the usages of your browser. So far so good everything works, it does what it should. Then I moved the file to another pc and now I'm getting "Missing Operator" errors eventho the program runs like it should. Any idea's?
#echo off
set date = %date
set time = %time
set sum=0
for /f "tokens=5 delims=," %%x in ('tasklist /fo csv /fi "imagename eq firefox.exe"') do (
for /f "tokens=1-5 delims=.K " %%a in ("%%~x") do set /a sum+=%%a%%b%%c%%d
)
echo %date%, %time%, firefox.exe, %sum%K > FirefoxDumpResult.csv
pause
:start
set date = %date
set time = %time
set sum=0
for /f "tokens=5 delims=," %%x in ('tasklist /fo csv /fi "imagename eq firefox.exe"') do (
for /f "tokens=1-5 delims=.K " %%a in ("%%~x") do set /a sum+=%%a%%b%%c%%d
)
echo %date%, %time%, firefox.exe, %sum%K >> FirefoxDumpResult.csv
set choice=
set /p choice="Do you want to log another one? Press 'y' and enter for Yes: "
if not '%choice%'=='' set choice=%choice:~0,1%
if '%choice%'=='y' goto start
You have not placed the closing percent characters on your %DATE% and %TIME% variables.
Additionally you shouldn't be creating variables which already exist and which don't need setting anyhow.
You have also pointlessly repeated a section of your code.
Finally you have not used the simpler code I provided for you in an earlier reply to another similar question using chrome.exe.
Try this:
#Echo Off
If /I Not "%CD%\" Equ "%~dp0" CD /D %~dp0
>FirefoxDumpResult.csv Type Nul
:Start
Set "_sum=0"
For /F "Tokens=6-7 Delims=., " %%a In (
'TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A _sum+=%%a%%b
Echo=%DATE%, %TIME%, firefox.exe, %_sum%K>>FirefoxDumpResult.csv
Echo=
Echo=Firefox process information logged
Echo=
Choice /M "Do you want to log another one?"
If ErrorLevel 2 Exit/B
GoTo :Start
These are the outputs from both your and my versions:
::-------------------------------- Akorna Output -------------------------------
Type Nul 1>FirefoxDumpResult.csv
Set _sum=0
For /F "Tokens=6-7 Delims=., " %a In ('TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A "_sum+=%a%b"
Set/A "_sum+=414 032K" Missing operator.
Echo=wo 07/09/2016, 16:39:43,48, firefox.exe, 414K 1>>FirefoxDumpResult.csv
::------------------------------------------------------------------------------
::-------------------------------- Compo Output --------------------------------
Type Nul 1>FirefoxDumpResult.csv
Set "_sum=0"
For /F "Tokens=6-7 Delims=., " %a In ('TaskList /NH /FI "ImageName Eq firefox.exe"') Do Set/A _sum+=%a%b
Set/A _sum+=333232
Echo=09/09/2016, 10:23:22.56, firefox.exe, 333232K 1>>FirefoxDumpResult.csv
::------------------------------------------------------------------------------
You have clearly altered the script; please make sure, at least, that line five in the script you're using matches the one I posted.

Batch file check if a program is running only once and close duplicate instances or launch it if none is running

I'm trying to realize a batch file that checks if a program is running and if not launch it, and more if is it launched more than one time close all the duplicate instances.
this is the code I implemented using also some tips found here in stackoverflow:
:check
tasklist /fi "imagename eq notepad.exe" /nh |find /i /c "notepad.exe" > "%temp%\variable.txt" #here I count how many instances are running
set /p value=<"%temp%\variable.txt" #and save the value in the variable.txt file
##check and choose action
if %value% equ nul goto none
if %value% geq 2 goto more
if %value% equ 1 goto one
:more
for /f "tokens=2" %%x in ('tasklist ^| findstr notepad.exe') do set PIDTOKILL=%%x
taskkill /F /PID %PIDTOKILL%
goto check
:none
start notepad.exe
goto check
:one
timeout 10 > nul
goto check
But some strange behavior happens when I test it...
if only one instances is running all fine, but if I close notepad while the batch file is running the routine goes to the :more label apparently without any reason...what I'm doing wrong?
thanks for any help
stupid error ... this is the working code:
:check
timeout 10 > nul
tasklist /fi "imagename eq notepad.exe" /nh |find /i /c "notepad.exe" > "%temp%\variable.txt"
set /p value=<"%temp%\variable.txt"
if %value% equ 0 goto none
if %value% geq 2 goto more
if %value% equ 1 goto check
:more
for /f "tokens=2" %%x in ('tasklist ^| findstr notepad.exe') do set PIDTOKILL=%%x
taskkill /F /PID %PIDTOKILL%
goto check
:none
start notepad.exe
goto check

Exit status of tasklist in batch file?

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?
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
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
)
%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
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!
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

Resources