How can I check if an application is running from a batch (well cmd) file?
I need to not launch another instance if a program is already running. (I can\'t change th
I like Chaosmaster's solution! But I looked for a solution which does not start another external program (like find.exe or findstr.exe). So I added the idea from Matt Lacey's solution, which creates an also avoidable temp file. At the end I could find a fairly simple solution, so I share it...
SETLOCAL EnableExtensions
set EXE=myprog.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto FOUND
echo Not running
goto FIN
:FOUND
echo Running
:FIN
This is working for me nicely...
Building on vtrz's answer and Samuel Renkert's answer on an other topic, I came up with the following script that only runs %EXEC_CMD%
if it isn't already running:
@echo off
set EXEC_CMD="rsync.exe"
wmic process where (name=%EXEC_CMD%) get commandline | findstr /i %EXEC_CMD%> NUL
if errorlevel 1 (
%EXEC_CMD% ...
) else (
@echo not starting %EXEC_CMD%: already running.
)
As was said before, this requires administrative privileges.
I used the script provided by Matt (2008-10-02). The only thing I had trouble with was that it wouldn't delete the search.log
file. I expect because I had to cd
to another location to start my program. I cd
'd back to where the BAT file and search.log
are, but it still wouldn't delete. So I resolved that by deleting the search.log
file first instead of last.
del search.log
tasklist /FI "IMAGENAME eq myprog.exe" /FO CSV > search.log
FOR /F %%A IN (search.log) DO IF %%-zA EQU 0 GOTO end
cd "C:\Program Files\MyLoc\bin"
myprog.exe myuser mypwd
:end
I like the WMIC
and TASKLIST
tools but they are not available in home/basic editions of windows.Another way is to use QPROCESS
command available on almost every windows machine (for the ones that have terminal services - I think only win XP without SP2 , so practialy every windows machine):
@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
:: QPROCESS can display only the first 12 symbols of the running process
:: If other tool is used the line bellow could be deleted
set process_to_check=%process_to_check:~0,12%
QPROCESS * | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
QPROCESS command is not so powerful as TASKLIST
and is limited in showing only 12 symbols of process name but should be taken into consideration if TASKLIST
is not available.
More simple usage where it uses the name if the process as an argument (the .exe
suffix is mandatory in this case where you pass the executable name):
@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
:: .exe suffix is mandatory
set "process_to_check=%~1"
QPROCESS "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
The difference between two ways of QPROCESS
usage is that the QPROCESS *
will list all processes while QPROCESS some.exe
will filter only the processes for the current user.
Using WMI
objects through windows script host exe instead of WMIC
is also an option.It should on run also on every windows machine (excluding the ones where the WSH is turned off but this is a rare case).Here bat file that lists all processes through WMI classes and can be used instead of QPROCESS
in the script above (it is a jscript/bat hybrid and should be saved as .bat
):
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
cscript //E:JScript //nologo "%~f0"
exit /b
************** end of JSCRIPT COMMENT **/
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
WScript.Echo( process.processID + " " + process.Name );
}
And a modification that will check if a process is running:
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
cscript //E:JScript //nologo "%~f0" | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
exit /b
************** end of JSCRIPT COMMENT **/
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
WScript.Echo( process.processID + " " + process.Name );
}
The two options could be used on machines that have no TASKLIST
.
The ultimate technique is using MSHTA
. This will run on every windows machine from XP and above and does not depend on windows script host settings. the call of MSHTA
could reduce a little bit the performance though (again should be saved as bat):
@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
mshta "about:<script language='javascript' src='file://%~dpnxf0'></script>" | find /i "%process_to_check%" >nul 2>&1 && (
echo process %process_to_check% is running
) || (
echo process %process_to_check% is not running
)
endlocal
exit /b
************** end of JSCRIPT COMMENT **/
var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);
var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes = new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
var process=processes.item();
fso.Write( process.processID + " " + process.Name + "\n");
}
close();
I needed a solution with a retry. This code will run until the process is found and then kill it. You can set a timeout or anything if you like.
Notes:
:: Set programm you want to kill
:: Fileextension is mandatory
SET KillProg=explorer.exe
:: Set waiting time between 2 requests in seconds
SET /A "_wait=3"
:ProcessNotFound
tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
IF "%ERRORLEVEL%"=="0" (
TASKKILL.EXE /F /T /IM %KillProg%
) ELSE (
timeout /t %_wait%
GOTO :ProcessNotFound
)
taskkill.bat
:
:: Get program name from argumentlist
IF NOT "%~1"=="" (
SET "KillProg=%~1"
) ELSE (
ECHO Usage: "%~nx0" ProgramToKill.exe & EXIT /B
)
:: Set waiting time between 2 requests in seconds
SET /A "_wait=3"
:ProcessNotFound
tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
IF "%ERRORLEVEL%"=="0" (
TASKKILL.EXE /F /T /IM %KillProg%
) ELSE (
timeout /t %_wait%
GOTO :ProcessNotFound
)
Run with .\taskkill.bat ProgramToKill.exe
I usually execute following command in cmd prompt to check if my program.exe is running or not:
tasklist | grep program