How to Get the Exit Code of a Background Process in a Batch Script
A common requirement in advanced scripting is to launch a time-consuming task in the background, allow the main script to continue with other work, and then, later, retrieve the result (the exit code) of that background process. The standard START command is perfect for launching background processes, but it introduces a major challenge: it detaches the new process, so the main script cannot simply check %ERRORLEVEL% to get its result.
This guide will teach you the standard and most robust asynchronous pattern for solving this problem: using a "wrapper" batch script and a temporary result file. You will learn how the main script can launch a task, proceed with its work, and then reliably retrieve the final exit code once the background task is complete.
The Core Challenge: START and Asynchronous Execution
When you use the START command, it launches a new program and your main script immediately continues to the next line without waiting. This is called asynchronous execution.
Example of the problem:
@ECHO OFF
ECHO Starting a background task that will take 5 seconds...
REM PING with a bad address will take time and return an ERRORLEVEL of 1
START "My Task" PING -n 1 non-existent-host.com
ECHO The START command has finished.
ECHO The ERRORLEVEL in the main script is: %ERRORLEVEL%
Output:
Starting a background task that will take 5 seconds...
The START command has finished.
The ERRORLEVEL in the main script is: 0
The %ERRORLEVEL% is 0 because the START command itself completed successfully. It says nothing about the PING command, which is still running (and will eventually fail) in its own separate process.
The Solution: A Wrapper Script with a Result File
The most reliable way to solve this is with a two-script system that communicates using a temporary file.
Main.bat(The Controller): This is your primary script. Its job is to launch the background task and then, later, check for the result. Instead of launching the task directly, it launches a small "wrapper" script.Wrapper.bat(The Worker): This script's only purpose is to run the actual long-running task synchronously (withoutSTART). When the task finishes, the wrapper script immediately captures the%ERRORLEVEL%.- The Result File (
.tmp): The wrapper script's final action is toECHOthe captured exit code into a temporary file with a unique name. The existence of this file signals that the task is complete, and its content is the result.
The Scripts: Main.bat and Wrapper.bat
This is the main script:
@ECHO OFF
SETLOCAL
SET "TaskID=%RANDOM%"
SET "ResultFile=%TEMP%\result_%TaskID%.tmp"
ECHO --- Main Script ---
ECHO Launching background task with ID %TaskID%...
START "My Background Task" Wrapper.bat %TaskID%
ECHO Main script is now continuing with other work...
REM (Simulate other tasks)
TIMEOUT /T 5 > NUL
ECHO Now, waiting for the background task to complete...
:WaitForFile
IF EXIST "%ResultFile%" GOTO :FileFound
TIMEOUT /T 2 /NOBREAK > NUL
GOTO :WaitForFile
:FileFound
SET /P "ExitCode=" < "%ResultFile%"
DEL "%ResultFile%"
ECHO The background task finished with exit code: %ExitCode%
ENDLOCAL
and this is the wrapper script:
@ECHO OFF
SET "TaskID=%1"
SET "ResultFile=%TEMP%\result_%TaskID%.tmp"
REM --- Run the actual long-running command here ---
REM This PING command will fail and set ERRORLEVEL to 1.
PING -n 1 non-existent-host.com > NUL 2> NUL
REM --- Immediately capture the exit code and write it to the result file ---
ECHO %ERRORLEVEL% > "%ResultFile%"
EXIT /B
How the Asynchronous Pattern Works
Main.batgenerates a unique ID and launchesWrapper.batwith that ID usingSTART.Main.batis now free to do other things.Wrapper.batstarts and executes the long-runningPINGcommand. It waits for thePINGcommand to finish.- When
PINGfinishes, it sets the%ERRORLEVEL%for theWrapper.batscript's environment. Wrapper.batimmediately runsECHO %ERRORLEVEL% > result_12345.tmp, saving the result. It then exits.- Meanwhile,
Main.bathas finished its other work and is now in a loop, polling to see ifresult_12345.tmpexists. - Once the file appears,
Main.batbreaks the loop, reads the content of the file (1) into itsExitCodevariable, deletes the temporary file, and reports the result.
A Simpler (but Flawed) Alternative: Waiting with TASKLIST
You can use a TASKLIST loop to wait for a process to disappear.
START "My App" my_app.exe
:WaitLoop
TASKLIST | FIND /I "my_app.exe" > NUL
IF %ERRORLEVEL% EQU 0 (
ECHO Process is still running. Waiting...
TIMEOUT /T 5 > NUL
GOTO :WaitLoop
)
ECHO Process has finished.
The Critical Flaw: This method can only tell you when the process has finished. It cannot tell you how it finished (i.e., you cannot get its exit code). For that, the wrapper script method is the only reliable solution.
Common Pitfalls and How to Solve Them
- Race Conditions: If you run
Main.batmultiple times in quick succession, they might generate the same%RANDOM%ID. Solution: For critical applications, use a more unique identifier like a GUID. - Cleanup: The main script is responsible for deleting the temporary result file. If the main script is terminated before the background task finishes, the temp file might be left behind. Solution: A cleanup script that periodically deletes old
result_*.tmpfiles from the%TEMP%directory is a good practice.
Practical Example: Launching and Collecting Multiple Background Jobs
This script launches three "jobs" at once, each with its own wrapper and result file. It then waits for all three to complete before showing a final report.
This is the main script:
@ECHO OFF
SETLOCAL
ECHO --- Launching 3 background jobs ---
START "Job 1" Wrapper.bat 1 "8.8.8.8"
START "Job 2" Wrapper.bat 2 "non-existent-host"
START "Job 3" Wrapper.bat 3 "1.1.1.1"
ECHO All jobs launched. Now waiting for completion...
FOR %%i IN (1 2 3) DO (
:Wait_%%i
IF EXIST "%TEMP%\result_%%i.tmp" (
SET /P "ExitCode_%%i=" < "%TEMP%\result_%%i.tmp"
DEL "%TEMP%\result_%%i.tmp"
) ELSE (
TIMEOUT /T 1 /NOBREAK > NUL
GOTO :Wait_%%i
)
)
ECHO.
ECHO --- All Jobs Complete. Results: ---
ECHO Job 1 Exit Code: %ExitCode_1%
ECHO Job 2 Exit Code: %ExitCode_2%
ECHO Job 3 Exit Code: %ExitCode_3%
ENDLOCAL
This requires a Wrapper.bat that accepts a second argument, like PING %2.
Conclusion
Getting the exit code from a background process is an advanced but powerful technique for creating parallel and asynchronous batch scripts.
- The "Wrapper Script" and "Result File" pattern is the standard and most reliable method.
- The main script uses
STARTto launch a wrapper, which runs the task synchronously. - The wrapper captures
%ERRORLEVEL%and writes it to a uniquely named file. - The main script polls for the existence of the result file to know when the task is complete and then reads its content to get the exit code.