Let us assume the current directory on starting the main batch file is C:\Temp\Test containing following folders and files:
- Development & Test
- Hello World!
- VersionInfo
- Main.bat
Batch file Development & Test.bat contains just the line:
@dir ..\Development & Test
Batch file Hello World!.bat contains just the line:
@echo Hello World!
Batch file VersionInfo.bat contains just the line:
@ver
Batch file main.bat contains following lines:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
set "exit_code=0"
for /D %%I in ("%~dp0*") do (
    echo ********************  %%~nxI  ********************
    echo(
    for %%J in ("%%I\*.bat") do (
        echo Calling %%J
        echo(
        pushd "%%I"
        call "%%J"
        if errorlevel 1 set "exit_code=1"
        popd
    )
    echo(
    echo(
)
echo Exit code is: %exit_code%
endlocal & exit /B %exit_code%
A command prompt is opened in which next the following command lines are executed manually one after the other:
C:\Temp\Test\Main.bat
echo Errorlevel is: %errorlevel%
ren "C:\Temp\Test\Development & Test\Development & Test.bat" "Development & Test.cmd"
C:\Temp\Test\Main.bat
echo Errorlevel is: %errorlevel%
The first execution of Main.bat results in exit with value 1 as it can be seen in command prompt window on the line:
Errorlevel is: 1
The reason is the wrong coded dir command with the directory name not enclosed in double quotes resulting in interpreting Test as command to execute. For that reason the dir command line results in following error output:
 Volume in drive C is TEMP
 Volume Serial Number is 14F0-265D
 Directory of C:\Temp\Test
File Not Found
'Test' is not recognized as an internal or external command,
operable program or batch file.
The exit code of this batch file is not 0 due to the error and for that reason the condition if errorlevel 1 is true and set "exit_code=1" is executed already on first executed batch file.
The processing of the other two batch files always end with 0 as exit code.
The command ren is used to change the file extension of Development & Test.bat to have the batch file next with name Development & Test.cmd resulting in ignoring it by main.bat. The second execution of Main.bat results in exit with 0 as it can be seen on the line:
Errorlevel is: 0
Please read the following pages for the reasons on all the code changes:
Summary of the changes:
- Delayed expansion is not enabled in Main.batas not required here to process also correct directory and file names containing an exclamation mark likeC:\Temp\Test\Hello World!\Hello World!.bat.
- Iand- Jare used as loop variables instead of- sand- fbecause of the latter two letters could be misinterpreted as loop variable modifiers in some cases. Therefore it is better to avoid the letters which have a special meaning for command- foron referencing the loop variables.
- %~dp0is used instead of- .\to make sure that the batch file searches for non-hidden subdirectories in the directory of the batch file independent on what is the current directory on starting the batch file. This expression references drive and path of argument 0 which is the full path of currently executed batch file- Main.bat. The referenced path of the batch file always ends with a backslash and for that reason- %~dp0is concatenated with- *without an additional backslash.
- Directory and file name arguments are enclosed in double quotes to work also for names containing a space or one of these characters &()[]{}^=;!'+,`~.%%~nxIand%%Jin the twoechocommand lines are not enclosed in double quotes as not necessary as long as delayed expansion is not enabled. The batch file makes sure that this is not the case forMain.bat.
- The usage of "%~dp0*"instead of just.\*in first FOR loop results in getting assigned to loop variableIthe directory names with full path never ending with a backslash. The usage of"%%I\*.bat"makes sure to get assigned to loop variableJthe full qualified file name of a non-hidden batch file. It is in general better to use full qualified directory/file names wherever possible. This helps also quite often on errors.
- The two cdcommands are replaced bypushdandpopdand moved inside the inner FOR loop. Then it does not matter if a called batch file works only with current directory being the directory of the called batch file or works independent on current directory likeMain.bat. Further it does not longer matter if a called batch file changes the current directory as withpopdthe initial current directory on startingMain.batis restored as current directory which could be the directory in which files are stored to be processed by the called batch files. The usage ofpushdandpopdmakes this batch file also working on being stored on a network resource andMain.batis started with its UNC path.
The most important modification is on last command line:
endlocal & exit /B %exit_code%
This command line is first parsed by Windows command processor cmd.exe with replacing %exit_code% by current value of environment variable exit_code defined inside the local environment setup with setlocal EnableExtensions DisableDelayedExpansion. So the command line becomes either
endlocal & exit /B 0
or
endlocal & exit /B 1
Then Windows command processor executes command endlocal to restore the previous environment defined outside Main.bat which results in exit_code no longer defined if not defined in initial execution environment. Then the command exit with option /B to exit just processing of batch file Main.bat is executed with returning 0 or 1 to the parent process which is cmd.exe which assigns the exit code to variable errorlevel.
Well, there is one issue left with the batch file code of Main.bat. A called batch file could modify the value of environment variable exit_code of Main.bat on using the same environment variable without definition of a local environment by using command setlocal. The solution would be to use additionally the commands setlocal before and endlocal after calling a batch file.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
set "exit_code=0"
for /D %%I in ("%~dp0*") do (
    echo ********************  %%~nxI  ********************
    echo(
    for %%J in ("%%I\*.bat") do (
        echo Calling %%J
        echo(
        pushd "%%I"
        setlocal
        call "%%J"
        endlocal
        if errorlevel 1 set "exit_code=1"
        popd
    )
    echo(
    echo(
)
echo Exit code is: %exit_code%
endlocal & exit /B %exit_code%
The command endlocal does not modify errorlevel.
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.
- call /?
- cls /?
- echo /?
- endlocal /?
- for /?
- if /?
- popd /?
- pushd /?
- set /?
- setlocal /?