279

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 the app to make it single instance only.)

Also the application could be running as any user.

Keng
  • 48,571
  • 31
  • 77
  • 109
Matt Lacey
  • 64,328
  • 10
  • 87
  • 143
  • Possible duplicate of [Batch program to to check if process exists](http://stackoverflow.com/questions/15449034/batch-program-to-to-check-if-process-exists) – phuclv Nov 29 '16 at 08:27
  • 16
    duplicate of a question asked five years later? – Matt Lacey Dec 06 '16 at 21:34
  • @LưuVĩnhPhúc they are not even relatively close. – Cardinal System Apr 01 '17 at 18:00
  • @JackKirby who said that it's not related? – phuclv Apr 02 '17 at 01:32
  • @LưuVĩnhPhúc I did. He's asking how to check if a program is running from batch script, while that other question asks how to get a task list. – Cardinal System Apr 02 '17 at 02:41
  • @JackKirby then you should read again. Where in the other question that the OP said he wants to get a task list? He wants to check if a process is running – phuclv Apr 02 '17 at 07:53
  • @Lưu Vĩnh Phúc He asked first. – oopsdazie May 18 '17 at 13:58
  • 5
    @oopsdazie yeah I may be wrong in this case but [the general rule is to keep the question with the best collection of answers, and close the other one as a duplicate](https://meta.stackexchange.com/q/10841/230282), irrespective of time – phuclv May 18 '17 at 14:38

19 Answers19

344

Another possibility I came up with, which does not require to save a file, inspired by using grep is:

tasklist /fi "ImageName eq MyApp.exe" /fo csv 2>NUL | find /I "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running
  • /fi "" defines a filter of apps to find, in our case it's the *.exe name
  • /fo csv defines the output format, csv is required because by default the name of the executable may be truncated if it is too long and thus wouldn't be matched by find later.
  • find /I means case-insensitive matching and may be omitted

See the man page of the tasklist command for the whole syntax.

chwarr
  • 5,726
  • 1
  • 24
  • 52
  • 8
    this worked for me nicely (windows XP SP3). IMHO this is the most elegant way of all proposed here, using just the tools shipped with windows – hello_earth Jul 08 '10 at 15:30
  • 3
    I had syntax problem with this command line. I changed it to `tasklist /FI "IMAGENAME eq winword.exe" 2>NUL | find /I /N "winword.exe">NUL` / `if %ERRORLEVEL%==1 goto wordnotrunning` in order to make it works (suspecting the quote around the if parts – Steve B Oct 19 '11 at 07:17
  • Works for me on Windows Server 2003! :) – Enrico Jul 05 '12 at 13:36
  • 1
    Thanks alot, man genius, can you please provide with code, if it is running then close aplication. – Mowgli Sep 15 '12 at 21:47
  • 4
    Please remember that in other language versions of XP the filter names were translated in code but not but in help `/?` screen. So for example `IMAGENAME` in polish version is `NAZWA_OBRAZU`. – rsk82 Nov 30 '12 at 15:44
  • 3
    Under Win7 I had to change it to `tasklist /FI "IMAGENAME eq myapp.exe" /NH | find /I /N "myapp.exe" >NUL` The first NUL seems unnecessary, I have no idea what the '2' is for, the /NH is optional. – Jan Doggen Nov 08 '13 at 09:17
  • 13
    tasklist always exits with status 0 whether or not it finds any matching tasks, which is why it's useless on its own. Since you have to use find (or findstr) to check its output anyway, there's no point using tasklist's filters. Just do tasklist | find "myprog.exe" >nul: && goto foundit or somesuch. You might need the /v (verbose) option to tasklist. – Denis Howe Jun 07 '14 at 12:32
  • 1
    Actually calling external find.exe is avoidable. See my reduced version nearby... – TrueY Aug 21 '14 at 10:21
  • @rsk82 In Win7 this seems to be pure English again (?) - at least on Polish Windows, `IMAGENAME` is working, while `NAZWA_OBRAZU` is not... – akavel Jan 08 '15 at 09:14
  • as stated by jan doggen, didn't work as is for me. The answer below by matt lacey worked for me without modifications. – Fractal Feb 18 '16 at 17:49
  • What happened to @ChaosMaster? – mtyson Sep 29 '16 at 22:55
  • I have no idea why, but I had to use `if errorlevel 0`, instead of `if "%ERRORLEVEL%"=="0"`. Oddly, using `%ERRORLEVEL%` works as expected if I issue the commands directly in `cmd.exe`, but if I try to do the same in a `.bat` script, `%ERRORLEVEL%` always evaluates to zero. FWIW, the script uses `setlocal enableextensions`; not sure if it's related to the observed behavior. This is on Windows 7 x64. – Ben Johnson Jul 10 '17 at 15:43
  • [should mention](https://stackoverflow.com/a/50299150/1037948) that if your taskname is too long the whole name won't appear in the results, so check for the opposite message instead – drzaus May 11 '18 at 19:40
  • A lot of superfluous bits. `tasklist | find /i "notepad.exe" > nul` is more than enough. – Jason Mar 22 '19 at 22:57
  • Just wanted to note down that I had gitbash installed and was seeing inconsistent results. Eventually tracked it down to VSCode running a node command had swapped system32 find for gitbash find. Solved once I used `C:\\Windows\\System32\\find.exe` I know it is a little verbose, but may be safest in the longrun. – WORMSS Feb 17 '20 at 00:14
  • @DenisHowe passing the whole task list to Find is noticeably slower than using TaskList's filter. – Richard Payne Mar 12 '20 at 15:34
  • @RichardPayne When exactly is the difference in speed worth the added complexity of filtering twice? – Denis Howe Mar 31 '20 at 10:29
  • @WORMSS The Windows findstr command is less likely to clash with added Unix commands. – Denis Howe Mar 31 '20 at 10:32
61

Here's how I've worked it out:

tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

FOR /F %%A IN (search.log) DO IF %%~zA EQU 0 GOTO end

start notepad.exe

:end

del search.log

The above will open Notepad if it is not already running.

Edit: Note that this won't find applications hidden from the tasklist. This will include any scheduled tasks running as a different user, as these are automatically hidden.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Matt Lacey
  • 64,328
  • 10
  • 87
  • 143
  • 2
    Changing the tasklist format to CSV or anything but table is important because it tasklist default layout (table) truncates long image names which breaks the logic. – Scott White Jun 22 '11 at 14:56
  • 4
    This solution will not work on Vista because TASKLIST produces some output even if the process is not found. I presume the same is true for Windows 7. – dbenham Jan 28 '12 at 16:39
  • does not work in Windows 10. search.log contains "INFO: No tasks are running which match the specified criteria." and no notepad is started – Sergey May 30 '18 at 08:21
49

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...

TrueY
  • 6,748
  • 1
  • 36
  • 43
  • This solution works well - tested in Windows 8.1. I did notice that it is case-sensitive. – m-smith Dec 02 '14 at 11:18
  • @LordScree As I work on un*x systems case sensitivity is good for me! I even set the file system to enable case sensitive file names. ;) – TrueY Dec 02 '14 at 12:42
  • Works well for me to - tested in windows 7 X64 – Mr Rubix Mar 15 '16 at 18:21
  • This doesn't work if the application has a space in the name as %x ends up being part of the application name up to the first space. – Chris Jun 14 '19 at 14:21
  • A possible solution would be to check if the application is not found instead by checking if %x == INFO: but I don't know which versions of Windows this would work on or if there's a better solution. – Chris Jun 14 '19 at 14:38
  • @Chris: This is also a good solution. If `%x == INFO`, it means that the program not found and Windows states `INFO: No tasks are running which match the specified criteria.`. But IMHO this is a bit less talkative. You can use both solution, of course! – TrueY Jun 17 '19 at 12:21
27

The suggestion of npocmaka to use QPROCESS instead of TASKLIST is great but, its answer is so big and complex that I feel obligated to post a quite simplified version of it which, I guess, will solve the problem of most non-advanced users:

QPROCESS "myprocess.exe">NUL
IF %ERRORLEVEL% EQU 0 ECHO "Process running"

The code above was tested in Windows 7, with a user with administrator rigths.

aldemarcalazans
  • 969
  • 9
  • 15
  • I just used this idea to stop an automated process firing twice and it worked like a charm! – Davy C Mar 14 '18 at 10:23
  • I must say that unlike this command, the tasklist solutions not only look too complicated for such a simple query, but they also run a second or so and use tons of cpu! This is much better, also worked with no admin permissions (Windows Server 2012). – Eugene Marin Jun 21 '18 at 15:36
  • This seems to be the simplest and best solution (at least for me) as it works as-is when the application has spaces in the name. I'm curious what the limitations of this solution are and why it doesn't have more votes. – Chris Jun 14 '19 at 14:41
  • simple and practical – focus zheng Jun 28 '20 at 10:36
20

Under Windows you can use Windows Management Instrumentation (WMI) to ensure that no apps with the specified command line is launched, for example:

wmic process where (name="nmake.exe") get commandline | findstr /i /c:"/f load.mak" /c:"/f build.mak" > NUL && (echo THE BUILD HAS BEEN STARTED ALREADY! > %ALREADY_STARTED% & exit /b 1)

vtrz
  • 529
  • 1
  • 5
  • 12
  • Note that WMIC requires administrative privileges; if you don't have it, then `Only the administrator group members can use WMIC.EXE.` followed by `Reason:Win32 Error: Access is denied.` – Jeroen Wiert Pluimers Feb 14 '12 at 09:48
  • i think this is best solution, because wmic gives you a complete command line launched and milion other informations... – Glavić May 23 '12 at 15:42
19
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
  • 3
    This actually works great. Simple! Just be aware it's case sensitive unless you add `/i`. – Jason Mar 25 '19 at 16:21
8

TrueY's answer seemed the most elegant solution, however, I had to do some messing around because I didn't understand what exactly was going on. Let me clear things up to hopefully save some time for the next person.

TrueY's modified Answer:

::Change the name of notepad.exe to the process .exe that you're trying to track
::Process names are CASE SENSITIVE, so notepad.exe works but Notepad.exe does NOT
::Do not change IMAGENAME
::You can Copy and Paste this into an empty batch file and change the name of
::notepad.exe to the process you'd like to track
::Also, some large programs take a while to no longer show as not running, so
::give this batch a few seconds timer to avoid a false result!!

@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!

Anyway, I hope that helps. I know sometimes reading batch/command-line can be kind of confusing sometimes if you're kind of a newbie, like me.

kayleeFrye_onDeck
  • 5,531
  • 5
  • 56
  • 62
8

I use PV.exe from http://www.teamcti.com/pview/prcview.htm installed in Program Files\PV with a batch file like this:

@echo off
PATH=%PATH%;%PROGRAMFILES%\PV;%PROGRAMFILES%\YourProgram
PV.EXE YourProgram.exe >nul
if ERRORLEVEL 1 goto Process_NotFound
:Process_Found
echo YourProgram is running
goto END
:Process_NotFound
echo YourProgram is not running
YourProgram.exe
goto END
:END
6

The answer provided by Matt Lacey works for Windows XP. However, in Windows Server 2003 the line

 tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

returns

INFO: No tasks are running which match the specified criteria.

which is then read as the process is running.

I don't have a heap of batch scripting experience, so my soulution is to then search for the process name in the search.log file and pump the results into another file and search that for any output.

tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

FINDSTR notepad.exe search.log > found.log

FOR /F %%A IN (found.log) DO IF %%~zA EQU 0 GOTO end

start notepad.exe

:end

del search.log
del found.log

I hope this helps someone else.

Community
  • 1
  • 1
benmod
  • 361
  • 6
  • 10
5

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();
npocmaka
  • 51,748
  • 17
  • 123
  • 166
2

I don't know how to do so with built in CMD but if you have grep you can try the following:

tasklist /FI "IMAGENAME eq myApp.exe" | grep myApp.exe
if ERRORLEVEL 1 echo "myApp is not running"
Motti
  • 99,411
  • 44
  • 178
  • 249
2

Just mentioning, if your task name is really long then it won't appear in its entirety in the tasklist result, so it might be safer (other than localization) to check for the opposite.

Variation of this answer:

:: in case your task name is really long, check for the 'opposite' and find  the message when it's not there
tasklist /fi "imagename eq yourreallylongtasknamethatwontfitinthelist.exe" 2>NUL | find /I /N "no tasks are running">NUL
if "%errorlevel%"=="0" (
    echo Task Found
) else (
    echo Not Found Task
)
drzaus
  • 21,536
  • 14
  • 123
  • 183
0

I'm assuming windows here. So, you'll need to use WMI to get that information. Check out The Scripting Guy's archives for a lot of examples on how to use WMI from a script.

NotMe
  • 84,830
  • 27
  • 167
  • 241
0

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.

Community
  • 1
  • 1
Calimo
  • 6,230
  • 3
  • 31
  • 52
0

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
Community
  • 1
  • 1
Nin
  • 11
0

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:

  • The ".exe" is mandatory
  • You could make a file runnable with parameters, version below
    :: 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

Patrick
  • 45
  • 5
0

If you have more than one .exe-file with the same name and you only want to check one of them (e.g. you care about C:\MyProject\bin\release\MyApplication.exe but not C:\MyProject\bin\debug\MyApplication.exe) then you can use the following:

@echo off

set "workdir=C:\MyProject\bin\release"
set "workdir=%workdir:\=\\%"

setlocal enableDelayedExpansion
for /f "usebackq tokens=* delims=" %%a in (`
    wmic process  where 'CommandLine like "%%!workdir!%%" and not CommandLine like "%%RuntimeBroker%%"'   get CommandLine^,ProcessId  /format:value
`) do (
    for /f "tokens=* delims=" %%G in ("%%a")  do (
        if "%%G" neq "" (
rem            echo %%G
            set "%%G"
rem            echo !ProcessId!
            goto :TheApplicationIsRunning
        )
    )
) 

echo The application is not running
exit /B

:TheApplicationIsRunning
echo The application is running
exit /B
arnold_w
  • 37
  • 8
-1

You should check the parent process name, see The Code Project article about a .NET based solution**.

A non-programmatic way to check:

  1. Launch Cmd.exe
  2. Launch an application (for instance, c:\windows\notepad.exe)
  3. Check properties of the Notepad.exe process in Process Explorer
  4. Check for parent process (This shows cmd.exe)

The same can be checked by getting the parent process name.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
prakash
  • 55,001
  • 25
  • 87
  • 114
-1

I usually execute following command in cmd prompt to check if my program.exe is running or not:

tasklist | grep program
Rajeev Jayaswal
  • 949
  • 11
  • 20