I have a batch file that starts two programs :
#echo off
start "" "C:\Program Files (x86)\Kodi\Kodi.exe"
start "" "C:\Program Files\OpenVPN\bin\openvpn-gui.lnk"
Now when i close program "Kodi", i want that it close automatically first the task "openvpn-gui.exe" and then "openvpn.exe"
Thank you !
What about this:
start "" "C:\Program Files\OpenVPN\bin\openvpn-gui.exe"
start "" "C:\Program Files\OpenVPN\bin\openvpn.exe"
start "" /WAIT "C:\Program Files (x86)\Kodi\Kodi.exe"
taskkill /IM "openvpn.exe"
taskkill /IM "openvpn-gui.exe"
Not tested, but give a try :
#echo off
Title Killing two process automatically after closing one program manually
set "RunningProcess=Kodi.exe"
set "Process2Kill=openvpn-gui.exe openvpn.exe"
tasklist /fi "imagename eq %RunningProcess%" /nh |find /i /c "%RunningProcess%"|findstr "^1$" >nul
If "%Errorlevel%" EQU "1" (
For %%a in (%Process2Kill%) do Call :KillProcess "%%a"
) else (
echo %RunningProcess% is still running
)
pause & exit
:KillProcess
Taskkill /f /im "%~1">nul 2>&1
goto :eof
Related
Here's my script in my bat file:
cd "C:\Program Files (x86)\Steam\Steamapps\common\F13game\"
Start F13theGameRemap.exe
cd "C:\Program Files (x86)\Steam\steamapps\common\F13Game\SummerCamp\Binaries\Win64\"
Start /WAIT SummerCamp.exe
Start /WAIT Taskkill /f /im F13theGameRemap.exe
exit
All I want is to run the first program, then the 2nd. When the 2nd program "summercamp.exe" exits, i want the first program "F13thegameremap.exe" to exit.
The way this script works now is that Taskkill immediately ignores the start /wait command of summercamp.exe and closes F13theGameRemap.exe immediately.
How do I fix this?
Something like this:
#Echo off
Cd /D "C:\Program Files (x86)\Steam\Steamapps\common\F13game\"
Start F13theGameRemap.exe
Cd /D "C:\Program Files (x86)\Steam\steamapps\common\F13Game\SummerCamp\Binaries\Win64\"
Set "App2=SummerCamp.exe"
Start /WAIT %App2%
:loop
Timeout /t 1 >NUL
tasklist.exe /FI "ImageName eq %App2%" /NH |find /i "%App2%" >NUL && Goto :loop
Start /WAIT Taskkill /f /im F13theGameRemap.exe
The :loop will check with 1 second delay if %App2% aka SummerCamp.exe is still running.
I have a program which has following flow. Problem is the windows batch file doesn't properly checks errorlevel and doesn't set KILLSTS value. Could you please let me know what's wrong with this program and how to fix this?
Ask user to open an exe
if Yes
check exe is running or not
if running, ask user whether to close that exe
if yes close exe
run the exe
else
exit
Here is the sample batch file.
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P AREYOUSURE="Open Spring STS [y/n]>"
set AREYOUSURE=%AREYOUSURE:~0,1%
ECHO AREYOUSURE=%AREYOUSURE:~0,1%
IF /I %AREYOUSURE% == N (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" |find ":" > nul
ECHO Error %errorlevel%
IF %errorlevel% neq 0 (
SETLOCAL
SET /P KILLSTS="Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set KILLSTS=%KILLSTS:~0,1%
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
ENDLOCAL
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
I am getting below error
You need to learn how to properly format if statements.
You are formatting them as:
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
When they should be formatted as:
if /i "%KILLSTS%"=="Y" (TASKKILL /f /im STS.exe)
The formatting doesn't really matter as such in simple batch files, but it's best to use the correct syntax which can handle special characters such as SPACES, AMPERSANDS, QUOTES, PIPE for when more complex variables are involved.
Updated script:
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P "AREYOUSURE=Open Spring STS [y/n]>"
set "AREYOUSURE=%AREYOUSURE:~0,1% "
echo "AREYOUSURE=%AREYOUSURE:~0,1%"
IF /I "%AREYOUSURE%"=="N" (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" | find ":" > nul
ECHO Error %errorlevel%
IF "%errorlevel%" neq "0" (
call :escapeexpansion
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
exit /b
:escapeexpansion
SETLOCAL
SET /P "KILLSTS=Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set "KILLSTS=%KILLSTS:~0,1%"
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I "%KILLSTS%"=="Y" TASKKILL /f /im "STS.exe"
ENDLOCAL
goto :EOF
The entire structure seems wrong to me; as well as pointlessly using SET /P instead of CHOICE.
#ECHO OFF
TASKLIST /FI "IMAGENAME eq STS.exe"|FIND ":">NUL 2>&1&&GOTO ASKIF
CHOICE /M "Spring STS is running. Kill STS Process"
IF ERRORLEVEL 2 GOTO ENDIT
TASKKILL /F /IM "STS.exe"
TIMEOUT 3 /NOBREAK>NUL
:ASKIF
CHOICE /M "Open Spring STS"
IF ERRORLEVEL 2 GOTO ENDIT
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
:ENDIT
Echo=Exiting Batch
TIMEOUT 3 /NOBREAK>NUL
I'm trying to write code which loops and tells if a certain process is opened or not. It should be a loop that will show me in real time if the process is opened or not. In other words, a text will change when the program is opened and change again when it's closed. Instead what I got was a flood with the same text and it doesn't show the 'echos' below it.
I tried this:
#echo off
goto xera
:start
tasklist /FI "IMAGENAME eq notepad.exe" | find /I "notepad.exe" > nul
IF %ERRORLEVEL% equ 0 ECHO is opened
IF %ERRORLEVEL% equ 1 ECHO isnt opened
:xera
set /p "=Status: " <nul &call :start //the code got 'stuck' here
ECHO Text 2 (doesnt show)
pause>nul
You are not terminating your sub-routine :start correctly. Try the following:
#echo off
goto xera
:start
tasklist /FI "IMAGENAME eq notepad.exe" | find /I "notepad.exe" > nul
IF %ERRORLEVEL% equ 0 ECHO is opened
IF %ERRORLEVEL% equ 1 ECHO isnt opened
exit /b
:xera
set /p "=Status: " <nul &call :start
ECHO Text 2 (doesnt show)
pause>nul
I inserted exit /b which tells the command interpreter to return to the command after the call statement that actually called it. You could also use goto :EOF instead. Type call /? for more information on how to call sub-routines in batch.
The past few days I have been working on a script that I thought would be rather easy but it seems not, and I do understand why. My problem is how to get around it.
The batch script I need explained:
I have a script that runs in cmd.exe that does a bunch of things like moving a huge amount of files from a location to another. Lets call it
movefile.cmd. This script works, but happens to stop sometimes (very rarely - lets not go into why and that script). Its important that this script always runs, so my idea here was to create a batch that exits cmd.exe and then re-opens the script each hour or so. Lets call this script restartcmd.bat
Sounds perfectly easy as I could do this:
#echo off
:loop
start c:\script\movefile.cmd
Timeout /nobreak /t 3600
Taskkill cmd.exe
goto loop
But obviously this doesn't work because my new script also runs in cmd.exe, so it would kill this process as well.
What I've tried:
So I made a copy of cmd.exe and renamed it into dontkillthis.exe. I run dontkillthis.exe and then open the restardcmd.bat from dontkillthis.exe - this works perfectly! But I need to be able to just dobbleclick my script instead of doing that. Why? Because its supposed to be as easy as possible and I want my restartcmd.bat to be in my startup folder.
I've been looking at the ideas of getting the exact process ID of cmd.exe and shutting that so that my dontkillthis.exe will remain, but I can't seem to nail it. Tried all thats written in here how to kill all batch files except the one currently running , but I can't get it to work.
I'm not sure if I'm being confused or if it actually is a bit hard to do this.
I'd really appreciate some help here.
Best Regards
MO
first you'll need the PID of the current CMD instance. The topic has been discussed here . I will offer you my solution - getCmdPID.bat
and here's the script (getCmdPID should in the same directory ):
#echo off
call getCmdPID
set "current_pid=%errorlevel%"
for /f "skip=3 tokens=2 delims= " %%a in ('tasklist /fi "imagename eq cmd.exe"') do (
if "%%a" neq "%current_pid%" (
TASKKILL /PID %%a /f >nul 2>nul
)
)
Normally with the following command I should be able to find the PID. Unfortunately this is not the case.
title exclude &tasklist /NH /v /fo csv /FI "WINDOWTITLE ne exclude*" /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"
So to achieve my goal, I used the following command:
FIND /I "exclude" 1>NUL
#echo off
TITLE exclude
(for /f "usebackq tokens=*" %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"`) do (
(
echo %%a | FIND /I "exclude" 1>NUL
) || (
for /f "usebackq tokens=2 delims=," %%i in (`echo %%a`) do (
echo TASKKILL /PID %%~i /f
)
)
)
)>_output-taskill.txt
TYPE _output-taskill.txt
Another approach to kill all the processes in a single line is to use filters on the command taskkill with filters should look like:
TASKKILL /F /FI "PID ne XXXX" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe
eq (equal)
ne (not equal)
gt (greater than)
lt (lesser than)
#echo off
TITLE exclude
(for /f "usebackq tokens=2 delims=," %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running" ^| FIND /I "exclude"`) do (
echo TASKKILL /F /FI "PID ne %%~a" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe
)
)>_output-taskill.txt
TYPE _output-taskill.txt
I have found a solution that utilizes text files to keep track of all previous PIDs the bat file has had. It attempts to kill them silently and then adds the current PID to the list after.
If you don't want it to kill the old, already existing process, simply replace the line that has "taskkill" with whatever you were wanting to do with it.
(might require you to run as admin in order to have permissions to kill the duplicate process. see permission elevation code below for optional implementation if you don't want to have to run as admin every time.)
#echo off
set WorkingDir=%cd%
if exist MostRecentPID.txt ( del "PIDinfo.txt" /f /q ) > nul
cd ..\..\..\..\..\..\..
title mycmd
tasklist /v /fo csv | findstr /i "mycmd" > %WorkingDir%\PIDinfo.txt
set /p PIDinfo=<%WorkingDir%\PIDinfo.txt
REM below, the 11 means get substring starting a position 11 with length of 5 characters. The tasklist command gives a long and verbose value so this will get just the PID part of the string.
set PID5chars=%PIDinfo:~11,5%
set PID4chars=%PIDinfo:~11,4%
if exist PreviousPIDs.txt (
for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
goto CheckIfFourCharPID
)
:CheckIfFourCharPID
if %PID4chars% gtr 8100 (
for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
echo %PID4chars% >> "PreviousPIDs.txt"
) else (
echo %PID5chars% >> "PreviousPIDs.txt"
)
Explanation: (warning: very technical)
-This solution gets a substring of the tasklist command to get just the PID. There will not be a PID for cmd.exe that is greater than 18100 so check if PID4chars is greater than 8100 so we know if it's a 4 digit or 5 digit number
case 1: a 5 digit PID like 17504 has a PID5chars val 17504 and a PID4chars val of 1750, so we add PID5chars to the text files of PIDs to kill
case 2: a 4 digit PID like 8205 has a PID5chars val of 8205" and a PID4chars val of 8205, so we add PID4chars to the text files of PIDs to kill
case 3: a 4 digit PID like 4352 has a PID5chars val of 4352" and a PID4chars val of 4352, so we add PID4chars to the text files of PIDs to kill
OPTIONAL PERMISSION ELEVATION CODE
(put this at the top of your bat file and it will auto-run it as admin.)
#echo off
setlocal DisableDelayedExpansion
set "batchPath=%~0"
for %%k in (%0) do set batchName=%%~nk
cd ..\..\..\..\..\..\..\..
if exist %cd%\Temp (
set temp=%cd%\Temp
goto vbsGetPrivileges
)
if exist %cd%\Windows\Temp (
set temp=%cd%\Windows\Temp
goto vbsGetPrivileges
)
set temp=%cd%
:vbsGetPrivileges
set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
setlocal EnableDelayedExpansion
:CheckIfRunningAsAdmin
net session >nul 2>&1
if %ERRORLEVEL% == 0 (
goto gotPrivileges
) else ( goto ElevatePermissions )
:ElevatePermissions
if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
ECHO args = "ELEV " >> "%vbsGetPrivileges%"
ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
ECHO args = args ^& strArg ^& " " >> "%vbsGetPrivileges%"
ECHO Next >> "%vbsGetPrivileges%"
ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
"%SystemRoot%\System32\WScript.exe" "%vbsGetPrivileges%" %*
exit /B
:gotPrivileges
setlocal & pushd .
cd /d %~dp0
if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul & shift /1)
net session >nul 2>&1
if %ERRORLEVEL% == 0 (
goto Continue
) else (
REM unable to elevate permissions so tell user to run file as admin manually
echo Please re-run this file as administrator. Press any key to exit...
pause > nul
goto Exit
)
:Continue
<insert rest of code here>
It would be much better to get the PID of your movefile.cmd. If you can edit it, add a title MyMoveFileProcess and get it's PID with
for /f "tokens=2" %%i in ('tasklist /v ^|find "MyMoveFileProcess"') do set PID=%%i
Then you can kill it with taskkill /pid %pid%
Instead of changing your movefile.cmd, you can also just start it with an title:
start "MyMoveFileProcess" c:\script\movefile.cmd
A couple of lines will help you achieve this:
TITLE exclude
taskkill /IM cmd.exe /FI "WINDOWTITLE ne exclude*"
I would like to use a batch file to compare the number of processes named "standard.exe", that are running on my Windows 7 machine, with the number of processes named "basic.exe". If the amount of processes called "standard.exe" equals the amount of processes called "basic.exe" nothing should happen, if the numbers are unequal, basic.exe should be restarted.
Any ideas? Already found the following code to check whether a process is running, but now I would like to count the number of processes carrying the same name.
tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /N "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Programm is running
Thanks in advance!
Using your example simply replace the /N in find with /C to return the count of processes.
tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /C "myapp.exe"
Then you can just reduce it down to :
tasklist | find /I /C "myapp.exe"
Although as Andriy M points out it will match both myapp.exe and notmyapp.exe.
As for the second part of your question, simply do this:
set a=tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /C "myapp.exe"
set b=tasklist /FI "IMAGENAME eq myapp2.exe" 2>NUL | find /I /C "myapp2.exe"
if not a==b do (
stuff
)
If you don't want to write a file, replace the tasklist and set var1 commands with
for /f "tokens=1,*" %%a in ('tasklist ^| find /I /C "standard.exe"') do set var1=%%a
same for the second ones.
for /f "tokens=1,*" %%a in ('tasklist ^| find /I /C "basic.exe"') do set var2=%%a
There is probably a neater way to do it, but the following code seems to do the trick:
:begin
tasklist | find /I /C "standard.exe">D:\tmpfile1.txt
tasklist | find /I /C "basic.exe">D:\tmpfile2.txt
set /p var1= <D:\tmpfile1.txt
set /p var2= <D:\tmpfile2.txt
if %var1% LSS %var2% goto restart
if %var1% EQU %var2% goto wait
:wait
echo waiting..
ping -n 300 127.0.0.1 > nul
goto begin
:restart
echo error has occured, all processes will be restarted
taskkill /f /im standard.exe
taskkill /f /im basic.exe
ping -n 30 127.0.0.1 > nul
goto begin
Cheers!