HOWTO · Batch
How to Create a Function in Batch Script
This article explains how to define and call label-based subroutines in Windows Batch, pass positional arguments, return results through environment variables, and use exit codes to handle missing input.
On this page
Batch files do not define functions with a separate declaration keyword. A reusable subroutine is a label, invoked with CALL; CALL runs the commands after that label and returns to the next command after the call. These examples use Windows CMD syntax and should be run in a .bat or .cmd file on Windows.
How Batch Functions Work
A Batch “function” is commonly called a subroutine. Its label names the entry point, while CALL :label transfers control to it and preserves a return point. A label by itself does not create a separate scope or automatically return. Use EXIT /B inside the subroutine to return to its caller; without an explicit return, execution can continue into later labels and commands. EXIT /B exits the current batch script when it is not being called as a subroutine.
Define and Call a Batch Function
Put the call site before the label, then finish the main body with GOTO :EOF so it cannot fall through into the subroutine. In the generated script, the subroutine prints a greeting and returns to the caller.
To view a small Windows CMD script without implying that CMD ran here, run this Python script. It prints the Batch source; save that output as a .bat or .cmd file and run it in Windows CMD.
print('''@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0''')
@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0
The generated script is for Windows CMD; Python prints the source but does not execute it. GOTO :EOF ends the main flow, and EXIT /B 0 returns a success status from the called label. The 0 is the conventional success code; a nonzero code can report failure to the caller.
Pass Arguments to a Batch Function
Arguments follow the label in the CALL command, separated by spaces. Inside the subroutine, %1 is the first argument, %2 the second, and so on. Prefer %~1 when you want the first argument with any surrounding quotes removed; the tilde does not make the value safe to insert into every command, so quote values when using them as paths or text.
This Python example prints a complete Batch script that passes one argument containing a space; save the printed source as a .bat or .cmd file to run it in Windows CMD. The :show subroutine reads the value as %~1.
print("""@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0""")
@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0
Keep argument expansion inside quoted comparisons or quoted SET assignments when the value may contain spaces or command metacharacters. Batch parsing has multiple expansion phases, so complex values such as %, &, and | need extra care.
Return Values and Exit Codes
Batch has no built-in function return-value slot. A common pattern is to place a result in an environment variable, while using the subroutine’s exit code separately for success or failure. This Python example prints a complete Batch script that calls a two-argument subroutine, checks its status immediately after CALL, and reads the result variable on success. Save the printed source as a .bat or .cmd file to run it in Windows CMD.
print("""@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0""")
@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0
The label reads the positional values as %~1 and %~2. SETLOCAL keeps the temporary _sum local; on the same command line, CMD expands %_sum% before ENDLOCAL runs, then assigns that value to the caller’s sum variable. Keep ENDLOCAL & SET together. This example expects integer arguments; missing arguments return status 1, while a completed addition returns status 0.
Handle Errors in a Batch Function
Validate required inputs near the start of the subroutine and return a nonzero status when they are missing. This Python example prints a complete Batch script that calls the same validation label with missing and present input; each if errorlevel 1 check follows its CALL immediately. Save the printed source as a .bat or .cmd file to run it in Windows CMD.
print("""@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0""")
@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0
The first call reaches the failure branch because the required value is absent; the second reaches the success branch. if errorlevel 1 means the current error level is at least 1; test higher codes in descending order if the exact code matters. A valid argument can proceed with the subroutine’s work and finish with EXIT /B 0.
Use EXIT /B rather than EXIT for a subroutine return: EXIT closes the CMD session, while EXIT /B returns from the current batch context. When a CALL targets a label that does not exist, CMD reports an error; spelling labels consistently and keeping subroutine calls visibly paired with their labels makes this easier to diagnose. The Python examples print Batch source; they do not execute it, so run the saved scripts in Windows CMD to observe their Batch behavior.