0

I am executing a script which starts an executable proc1.exe. When proc1.exe is running, the batch file has to start another executable proc2.exe.

Example: File A.bat runs proc1.exe with following requirements.

  1. When proc1.exe is running, proc2.exe should run.
  2. When proc1.exe is closed, proc2.exe should be terminated.

I tried this code:

tasklist /fi "ImageName eq proc1.exe" /fo csv 2>NUL|find /I "proc1.exe">NUL

if "%ERRORLEVEL%"=="0" 
echo proc1.exe  is running
start /wait proc2.exe

else

taskkill /F /IM proc2.exe 

When I run the script, the command window displays the error message:

The syntax of tasklist command is incorrect.

What is the issue with the above tasklist command line?

I am not sure whether the else part would be achieved. How do I come back to else part in the script and kill proc2.exe after proc1.exe is terminated.

How could this be achieved?


Here are more information after post of first version of Mofi´s answer.

This is what I have tried and I think, I am near to the solution but need your support.

Batch file A.bat is modified to:

start bin\proc1.exe 2>&1
rem proc1.exe is running. Proc1.exe is a GUI application with buttons and
rem widgets. The cmd window and the GUI application window are opened now.

start /wait proc2.exe 2>&1
rem proc2.exe is running now too. It is a Windows console application.
rem A second console window is opened for that reason.
rem Both proc1.exe and proc2.exe are running as processes.
    
rem Now I want to check whether Proc1.exe is running or not.
rem If it is running do nothing, else terminate proc2.exe.
rem I have written a loop for that purpose. The issue is that
rem the control is not coming to the loop.

rem When I close the GUI application, the ELSE part should
rem be executed and proc2.exe should be terminated/killed.

rem How do I bring the control to loop label or how 
rem to signal proc1.exe is closed and run taskkill?

:loop
tasklist /FI "IMAGENAME eq proc1.exe" 2>NUL | find /I /N "proc1.exe">NUL
if "%ERRORLEVEL%"=="0" (
    timeout /T 1 /NOBREAK >NUL
    goto loop
) else (
    taskkill /F /IM proc2.exe  >NUL
)
Mofi
  • 46,139
  • 17
  • 80
  • 143
Kumar
  • 11
  • 4

2 Answers2

-1

The task is very unclear.

  1. Is proc1.exe started outside of the batch file or also by the batch file?
  2. 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?
  3. 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?
  4. 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?
  5. Can be more instances of proc1.exe and/or proc2.exe already running before the batch file starts just proc2.exe or both applications?
  6. 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.
  7. 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:

  1. The batch file always starts proc1.exe.
  2. It is unknown what proc1.exe is and what it does.
  3. It is unknown what proc2.exe is and what it does.
  4. Yes, proc2.exe starts also successful on proc1.exe not already running.
  5. Yes, that is indeed possible.
  6. Yes, that is possible, too.
  7. 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:

  1. The batch file always starts proc1.exe.
  2. The application proc1.exe is a Windows GUI application.
  3. The application proc2.exe is a Windows console application.
  4. proc2.exe must be started after proc1.exe.
  5. There is neither proc1.exe nor proc2.exe started before batch file execution.
  6. There are running never more than one proc1.exe one proc2.exe.
  7. 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.

Mofi
  • 46,139
  • 17
  • 80
  • 143
-1
This is I want I tried and I am near to the solution but need your support.

A.bat file
start bin\proc1.exe 2>&1
::proc1.exe gets running. Proc1.exe is a gui application with buttons and widgets. cmd window and gui application gets opened.
start /wait proc2.exe 2>&1
    ::proc2.exe gets running it is a windows console, a cmd windows gets 
    opened. Both proc1.exe and proc2.exe are running as process
    
    Now I want to check whether Proc1.exe is running or not if it is running do nothing, else kill proc2.exe
    for that I have written a loop, the issue is control
 is not coming to loop.
    
    when I close the gui application, else part to be executed and proc2. exe should be terminated/killed.
 How do I bring the control to loop lable or how 
    to signal , proc1.exe is closed , u run loop.

:loop
tasklist /FI "IMAGENAME eq proc1.exe" 2>NUL | find /I /N "proc1.exe">NUL
if "%ERRORLEVEL%"=="0" (
    timeout /T 1 /NOBREAK >NUL
    goto loop
) else (
    taskkill /F /IM proc2.exe  >NUL
)
Kumar
  • 11
  • 4
  • 1
    You should not post additional information in an __answer__. That information and batch file code does not answer your question. You should edit your __question__ by clicking on gray displayed __Edit__ link below the blue displayed tags of your question and add there the additional information. Then click on gray displayed __Delete__ link here at bottom of your __answer__ to delete it (in real just hide it for most Stack Overflow users). I will look on your additional information and will update my answer accordingly. But it can take 24 hours before my answer is updated, please be patient. – Mofi Jun 02 '23 at 05:12
  • `start /wait` will wait for the program to end before continuing the code. The solution might be as simple as removing `/wait`. – Stephan Jun 02 '23 at 06:48
  • @Stephan. Thank you for the solution. The control is now coming to loop but tasklist /FI "IMAGENAME eq proc1.exe" 2>NUL | find /I /N "proc1.exe">NUL if "%ERRORLEVEL%"=="0" . though proc1.exe is running the env variable errorlevel always returns 1. what is the reason why it is not returning 0 though proc1.exe is running. – Kumar Jun 02 '23 at 12:14
  • unknown - works for me. Temporarily remove `2>nul` and `>nul` to check what's going on. – Stephan Jun 02 '23 at 14:57
  • @Stephan. After removing 2>nul and > nul, it doesn't work for me. and tasklist command and env variable always returns 1. what is the reason and how to fix it. – Kumar Jun 03 '23 at 07:12
  • "doesn't work" isn't helpful. What exactly is it (not) doing? What's the exact output you get? – Stephan Jun 03 '23 at 07:18
  • @Stephan, it is going to else part and killing proc2.exe, not coming to if part though the proc1.exe is running – Kumar Jun 03 '23 at 08:37
  • [*sigh*] What's the output of `tasklist /FI "IMAGENAME eq proc1.exe" | find /I /N "proc1.exe"`? – Stephan Jun 03 '23 at 08:56