Can you fork in Windows batch file? - batch-file

I want to start two programs from the batch file, (also batch files) - they will execute few seconds. Then in the main batch file I want to wait while both are finished and then continue main execution. Is that possible at all?

You can, sort of:
#echo off
set Token=MAIN_%RANDOM%_%CD%
start "%Token%_1" cmd /c child1.cmd
start "%Token%_2" cmd /c child2.cmd
:loop
ping -n 2 localhost >nul 2>nul
tasklist /fi "WINDOWTITLE eq %Token%_1" | findstr "cmd" >nul 2>nul && set Child1=1 || set Child1=
tasklist /fi "WINDOWTITLE eq %Token%_2" | findstr "cmd" >nul 2>nul && set Child2=1 || set Child2=
if not defined Child1 if not defined Child2 goto endloop
goto loop
:endloop
echo Both children died.
child1 and child2 were just executing pause. This uses a more or less unique token to identify the child batch files. They are started in an own window with start and each one is given a specific window title. Using that window title we can find them again using tasklist and determine whether they are still running.
It gets a little tricky figuring out whether the batch files are still running. tasklist with the window title filter does what it's supposed to do, but it won't return a sensible errorlevel. That's why we have to pipe through findstr to pick up the process name (to avoid being language-sensitive by picking up the error message).

Related

Batch Detecting Program Not Responding

I am trying to write a batch script that detects if an .exe is not responding, and if it isn't, it will run a piece of code that kills it and then does some other things as well. I know how I can kill the process and restart it if it is not responding in one line, but I am not sure how I can do more than just restart it by converting this into an if statement, or calling a goto.
taskkill /im "exeName.exe" /fi "STATUS eq NOT RESPONDING" /f >nul && start "" "pathToExe"
I have come across other Stack Overflow posts that are similar to this, however they only check the error level of the process and do not check if the program is not responding and how to perform code after that.
How would I go about this? Thanks in advance.
Assuming I am interpreting your question correctly and you want to test without killing a task, how about this:
tasklist /fi "status eq not responding" /nh | find "exeName.exe" >NUL
if %errorlevel% == 0 (
echo Oops, we've hung...
)
tasklist takes the same /fi status options as taskkill, even though the documentation states only RUNNING is allowed - taskkill /? on Windows 8 at least shows the full options. We then use find to check that the executable is in the list of not responding tasks.
BTW, if you want to use PowerShell instead:
$foo = get-process exeName
if (!$foo.Responding) {
echo "Oops, we've hung..."
}
Can be done more easily:
taskkill /FI "STATUS eq NOT RESPONDING" /IM "yourexe.exe" /F | findstr /c:"SUCCESS" >nul
if %errorlevel% EQU 0 (echo Successfully detected and terminated "yourexe.exe" which didn't respond) else (echo Ooops! We didn't find or could not terminate process "yourexe.exe")
If you want to just detect if process is not responding, then use tasklist:
tasklist /FI "STATUS eq NOT RESPONDING" | findstr /c:"yourexe.exe">nul
if %errorlevel% EQU 0 (echo We have detected that process with image name "yourexe.exe" is not responding.) else (echo We didn't found process with image name "yourexe.exe" because it doesn't exist.)
In both cases we use findstr command because even if process not found/terminated taskkill/tasklist will return errorlevel 0.

Batch script to find if program is not responding and then start another application else exit batch job

I want a batch script that checks if the program is in running or not responding state. If it is in running state exit the batch script, else kill the program start the other application.
I tried using the following code but it is executing opening application even though the program is in running state. Please help me in finding a solution
#echo off
TASKLIST/IM jusched.exe /FI "STATUS eq NOT RESPONDING">nul /T /F && start "" notepad.exe
You appear to be mixing up the TaskKill and TaskList syntax. (Enter TaskList/? and TaskKill/? at the command prompt for usage information). Also I think TaskList output is always successful so it would probably need to be checked using something which does register if unsuccessful, e.g. Find.exe.
Here is a basic step by step example for you.
#Echo Off
Rem Setting name of target process
Set "TP=jusched.exe"
Rem Setting name of new process
Set "NP=notepad.exe"
Rem Setting TaskList filters to reduce line length
Set "F1=ImageName eq %TP%"
Set "F2=Status eq Not Responding"
Rem Check target process status and exit if no match
TaskList /FI "%F1" /FI "%F2%" /NH|Find /I "%TP%">Nul||Exit/B
Rem Kill unresponsive process and wait a little
TaskKill /IM "%TP%" /T /F>Nul 2>&1&&Timeout 3 /NoBreak>Nul
Rem Open new process
Start "" "%NP%"

Close a batch window only by typing "exit"?? disable the close "X" button on the top right of batch window

I run a batch file which carries out some task for hours. BY mistake users happen to close the terminal window in which the batch file is executing by pressing the top right "X" close button.
I want to disable it and want to close the batch file window only by typing "exit" inside the window..is this possible?
This can't be done using only one batch file. But there might be a really dirty way for this. You will need three batch files:
EDIT: Here is the solution. Put these three files into the same folder.
controller.bat:
#ECHO OFF
TITLE CONTROLLER
IF NOT EXIST hiddenrunner.vbs (
echo CreateObject^("WScript.Shell"^).Run Wscript.Arguments^(0^), 0, False>hiddenrunner.vbs
)
tasklist /V|findstr "MONITOR"
IF %ERRORLEVEL%==1 hiddenrunner.vbs monitor.bat
:INPUTLOOP
CLS
SET /P input=Type 'exit' to exit:
IF /i NOT %input%==exit GOTO INPUTLOOP
ECHO ok, exiting
taskkill /F /FI "WindowTitle eq Administrator: WORK" /T
taskkill /F /FI "WindowTitle eq Administrator: MONITOR" /T
ping localhost -n 2
del /Q hiddenrunner.vbs
monitor.bat:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
TITLE MONITOR
hiddenrunner.vbs work.bat
:LOOP
tasklist /V|findstr "CONTROLLER"
IF !errorlevel!==1 START controller.bat
ping localhost -n 2
GOTO LOOP
work.bat:
#ECHO OFF
title WORK
ping -t localhost
In your case, the work-file will be your original batch you want to execute. You'll have to adjust the window titles (like TITLE CONTROLLER and WindowTitle eq Administrator: WORK) to fit your setup. However, this works for me. If the user closes the input console, it is being restarted after one second. All processes are being terminated after the user inputs exit in the input console.

start command in batch file

I am wanting to run a batch file which builds visual studio project in another window and then return to original window and execute later commands.
but following command immediately prints LetterTwo without waiting for complete solution building
echo LetterOne
start /WAIT msbuild sim.sln
echo LetterTwo
According to the comments to the question, it seems, msbuild doesn't behave, like one would guess. So your only way is to "wait manually":
start "MyUglyApplication" msbuild sim.sln
:loop
timeout 1 >nul
tasklist /v | find "MyUglyApplication" && goto :loop
echo finished.
Give the new window a unique name, test if the process is running and if yes, continue testing.
i have able to solve the problem by modifying #stephan code a little bit
#echo off
start msbuild <solution>
:loop
timeout 1 >nul
tasklist /FI "IMAGENAME eq msbuild.exe" 2>NUL | find /I /N "msbuild.exe">NUL
if "%ERRORLEVEL%"=="0" goto loop
echo finished.

Waiting for parallel batch scripts

I have 4 batch files. I want to run one.bat and two.bat at once, concurrently. After completion of these two batch files, three.bat and four.bat should run at once, in parallel. I tried with many ways but mot works fine.
Can anyone help me over this?
This is easily done using a much simplified version of a solution I provided for Parallel execution of shell processes. Refer to that solution for an explanation of how the file locking works.
#echo off
setlocal
set "lock=%temp%\wait%random%.lock"
:: Launch one and two asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" one.bat
start "" cmd /c 9>"%lock%2" two.bat
:Wait for both scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
( rem
) 9>"%lock%%%N" || goto :Wait
) 2>nul
::delete the lock files
del "%lock%*"
:: Launch three and four asynchronously
start "" cmd /c three.bat
start "" cmd /c four.bat
I had this same dilemma. Here's the way I solved this issue.
I used the Tasklist command to monitor whether the process is still running or not:
:Loop
tasklist /fi "IMAGENAME eq <AAA>" /fi "Windowtitle eq <BBB>"|findstr /i /C:"<CCC>" >nul && (
timeout /t 3
GOTO :Loop
)
echo one.bat has stopped
pause
You'll need to tweak the
<AAA>, <BBB>, <CCC>
values in the script so that it's correctly filtering for your process.
Hope that helps.
Create a master.bat file that starts one.bat and two.bat. When one.bat and two.bat end correctly, they echo to file they have finished
if errorlevel 0 echo ok>c:\temp\OKONE
if errorlevel 0 echo ok>c:\temp\OKTWO
Then the master.bat wait for the existence of the two files
del c:\temp\OKONE
del c:\temp\OKTWO
start one.bat
start two.bat
:waitloop
if not exist c:\temp\OKONE (
sleep 5
goto waitloop
)
if not exist c:\temp\OKTWO (
sleep 5
goto waitloop
)
start three.bat
start four.bat
Another way is to try with the /WAIT flag
start /WAIT one.bat
start /WAIT two.bat
but you don't have any control on errors.
Here's some references
http://malektips.com/xp_dos_0002.html
http://ss64.com/nt/sleep.html
http://ss64.com/nt/start.html
Just adding another way, maybe the shortest.
(one.cmd | two.cmd) && (three.cmd | four.cmd)
Concept is really straight forward. Start one and 2 in paralel, once done and errorlevel is 0 run three and four.

Resources