The task is very unclear.
- Is
proc1.exe
started outside of the batch file or also by the batch file?
- Is
proc1.exe
a Windows console or a Windows GUI application and does it open files for read/write operations or makes it registry reads/writes or does it open connections to other processes or even other devices?
- Is
proc2.exe
a Windows console or a Windows GUI application and does it open files for read/write operations or makes it registry reads/writes or does it open connections to other processes or even other devices?
- Is it possible to start
proc2.exe
a second before proc1.exe
or does proc2.exe
depend on an already running proc1.exe
for a successful start?
- Can be more instances of
proc1.exe
and/or proc2.exe
already running before the batch file starts just proc2.exe
or both applications?
- Is it possible that even more instances of
proc1.exe
or proc2.exe
are started by a user or any other process while the batch file observes the one or two processes started during execution of the batch file.
- Is it really okay forcing a brutal kill of all running instances of
proc2.exe
by the operating system by using TASKKILL with the options /F /IM proc2.exe
giving none of the running proc2
processes the chance to gracefully terminate with closing connections, finishing all read/write operations, saving unsaved data and closing files?
Let me assume the answers on these seven questions are as follows:
- The batch file always starts
proc1.exe
.
- It is unknown what
proc1.exe
is and what it does.
- It is unknown what
proc2.exe
is and what it does.
- Yes,
proc2.exe
starts also successful on proc1.exe
not already running.
- Yes, that is indeed possible.
- Yes, that is possible, too.
- No, that is not okay.
proc2.exe
should close itself and should not be killed by the OS.
In this case can be used the following commented batch file:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define the two programs to run which can be even twice the same program.
set "ProgStart_FullName=%SystemRoot%\Notepad.exe"
set "ProgWait_FullName=%SystemRoot%\Notepad.exe"
rem Get just the file name of the first program with file extension.
for %%I in ("%ProgStart_FullName%") do set "ProgStart_FileName=%%~nxI"
rem Delete all environment variables of which name starts with
rem #PID_ in the local environment of this batch file context.
for /F "delims==" %%I in ('set #PID_ 2^>nul') do "set %%I="
rem Get all process identifiers of all already running processes
rem of the executable which is started next by the the batch file.
for /F "tokens=2" %%I in ('%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %ProgStart_FileName%" /NH') do set "#PID_%%I=1"
rem Start the program which should run as separate process.
start "" "%ProgStart_FullName%"
rem Find out the process identifier of just started program. There are
rem hopefully not started two instances of this program at the same time.
for /F "tokens=2" %%I in ('%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %ProgStart_FileName%" /NH') do if not defined #PID_%%I set "#PID_OBSERVE=%%I" & goto StartNext
echo ERROR: Failed to start "%ProgStart_FullName%"!& echo(& pause & goto EndBatch
:StartNext
rem Start the next program and wait for its self-termination.
"%ProgWait_FullName%"
rem Check if the first started program is still running and send it in
rem this case the WM_CLOSE message for a graceful self-termination giving
rem the process the chance to close all connections, finish all file and
rem registry accesses with saving all unsaved data and close all files.
%SystemRoot%\System32\tasklist.exe /FI "PID eq %#PID_OBSERVE%" | %SystemRoot%\System32\find.exe /I "%ProgStart_FileName%" >nul || goto EndBatch
%SystemRoot%\System32\taskkill.exe /PID %#PID_OBSERVE% >nul 2>nul
rem Wait five seconds for the self-termination of the first started program.
rem A Windows GUI program should get even more time, especially if a user uses
rem that GUI program and the program asks the user if unsaved data should be
rem saved before exiting. How much time to wait depends on the application.
echo Wait for exit of "%ProgStart_FileName%" with PID %#PID_OBSERVE%" ...
set "LoopCount=5"
:WaitLoop
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul
%SystemRoot%\System32\tasklist.exe /FI "PID eq %#PID_OBSERVE%" | %SystemRoot%\System32\find.exe /I "%ProgStart_FileName%" >nul || goto EndBatch
set /A LoopCount-=5
if not %LoopCount% == 0 goto WaitLoop
rem Force a brutal kill of the first started program by the operating system.
%SystemRoot%\System32\taskkill.exe /F /PID %#PID_OBSERVE% >nul 2>nul
:EndBatch
endlocal
This batch file demonstrates the process management by starting two instances of Windows Notepad. A user can start other Notepad instances before running the batch file and can also start even more Notepad processes while the two instances of Notepad started by the Windows Command Processor during processing of the batch file are still running and wait for user actions. The user can close the first batch started instance and later the second batch started instance of Notepad, but the opposite is also possible. If the user entered text into new file of first batch started instance without saving that text and closes first the second batch started instance, the first batch started instance of Notepad prompts the user if the unsaved text should be saved now. The user has five seconds time for the choice as otherwise the batch file runs TASKKILL with option /F
to force a kill of the first batch started Notepad resulting in a loss of the input text.
The batch file as is cannot be used for executables with a space in file name.
The batch file cannot be used as posted here if ProgStart_FullName
is %CompSpec%
or %SystemRoot%\System32\cmd.exe
.
The environment variable ProgStart_FullName
must be defined with the fully qualified file name of proc2.exe
while the environment variable ProgWait_FullName
must be defined with the fully qualified file name of proc1.exe
. So, proc2.exe
is started first as separate, parallel running process and next is started proc1.exe
on which cmd.exe
halts the batch file execution until proc1.exe
exits itself. Then the batch file terminates also proc2.exe
on still running or finally kills it if proc2.exe
does not close itself within five seconds for whatever reason.
The task became more clear with the additional information added to the question.
The seven questions are answered as follows:
- The batch file always starts
proc1.exe
.
- The application
proc1.exe
is a Windows GUI application.
- The application
proc2.exe
is a Windows console application.
proc2.exe
must be started after proc1.exe
.
- There is neither
proc1.exe
nor proc2.exe
started before batch file execution.
- There are running never more than one
proc1.exe
one proc2.exe
.
proc2.exe
should close itself and should not be killed by the OS.
The commented batch file for this task with proc1.exe
and proc2.exe
in subdirectory bin
of the batch file directory could be:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FullNameProcess1=%~dp0bin\proc1.exe"
set "FullNameProcess2=%~dp0bin\proc2.exe"
rem Get just the file name of the two programs with file extension.
for %%I in ("%FullNameProcess1%") do set "FileNameProcess1=%%~nxI"
for %%I in ("%FullNameProcess2%") do set "FileNameProcess2=%%~nxI"
rem Start the GUI program which should run as separate process in foreground.
start "" "%FullNameProcess1%" 2>nul
rem Could the first program not be started at all?
if errorlevel 9059 echo ERROR: Failed to start "%FullNameProcess1%"!& echo(& pause & goto EndBatch
rem Start the console program which should run as separate process
rem without opening a console window.
start "" /B "%FullNameProcess2%"
rem Define an endless running loop searching once per second in the
rem task list if the first started GUI application is still running.
:WaitLoop
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %FileNameProcess1%" /NH | %SystemRoot%\System32\find.exe "%FileNameProcess1%" >nul && goto WaitLoop
rem The first started GUI program is not running anymore. Check now if the
rem console program is still running and if that is the case, send it the
rem message to close itself.
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %FileNameProcess2%" /NH | %SystemRoot%\System32\find.exe "%FileNameProcess2%" >nul || goto EndBatch
%SystemRoot%\System32\taskkill.exe /IM "%FileNameProcess2%" >nul 2>nul
rem Wait one second and check if the console program really terminated itself.
rem Otherwise force a brutal kill of the console program by the operating system.
%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK >nul
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq %FileNameProcess2%" /NH | %SystemRoot%\System32\find.exe "%FileNameProcess2%" >nul && %SystemRoot%\System32\taskkill.exe /F /IM "%FileNameProcess2%" >nul 2>nul
:EndBatch
endlocal
The batch file as is cannot be used for executables with a space in file name.
The batch file cannot be used if proc2.exe
is in real cmd.exe
because of taskkill.exe /IM "cmd.exe"
results in termination of all running cmd
processes including the one processing the batch file.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
find /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
start /?
taskkill /?
tasklist /?
timeout /?
Read the Microsoft documentation about Using command redirection operators for an explanation of >nul
and 2>nul
and |
. The redirection operators >
and |
must be escaped with caret character ^
on the FOR command lines to be interpreted as literal characters when Windows command interpreter processes these command lines before executing command FOR which executes the embedded command line with using a separate command process started in background with %ComSpec% /c
and the command line within '
with ^
appended as additional arguments.
See also single line with multiple commands using Windows batch file for an explanation of unconditional command operator &
and conditional command operator ||
and correct syntax for an IF condition with an ELSE branch. The usage of "%ERRORLEVEL%"=="0"
is neither described by the usage help of command IF nor is it ever a good idea to use this string comparison for exit code evaluation in a batch file.