How to Create a Script Bootstrapper to Download Dependencies in Batch Script
A "Bootstrapper" is a lightweight script whose only job is to prepare the environment for a much larger application. If your main automation requires a specialized tool like 7zip, curl, or a custom .exe that isn't included with Windows, forcing users to manually download and install it increases the risk of setup errors. A smart Bootstrapper automatically detects if a dependency is missing, downloads it from a secure URL, and then launches the main process.
This guide will explain how to use curl (built into modern Windows) to create a self-healing dependency bootstrapper.
Method 1: The Automated Download Pattern
This pattern checks for a local file and downloads it from a repository if it's missing.
@echo off
setlocal
set "ToolName=wget.exe"
set "ToolURL=https://example.com/downloads/wget.exe"
set "BinFolder=%~dp0bin"
:: 1. Verify that curl is available
where curl >nul 2>&1
if errorlevel 1 (
echo [ERROR] curl is not available on this system. >&2
echo This bootstrapper requires Windows 10 1803 or later. >&2
endlocal
exit /b 1
)
:: 2. Ensure the bin folder exists
if not exist "%BinFolder%\" mkdir "%BinFolder%"
if not exist "%BinFolder%\" (
echo [ERROR] Could not create folder: %BinFolder% >&2
endlocal
exit /b 1
)
:: 3. Check if the tool is already there
if exist "%BinFolder%\%ToolName%" goto :LaunchApp
echo [INFO] %ToolName% is missing. Downloading now...
:: 4. Download using curl
:: -f = Fail on HTTP errors (404, 500) instead of saving error pages
:: -L = Follow redirects
:: -o = Output file
curl -f -L -o "%BinFolder%\%ToolName%" "%ToolURL%"
if errorlevel 1 (
echo [ERROR] Failed to download %ToolName%. >&2
echo Please check your internet connection and the URL. >&2
del "%BinFolder%\%ToolName%" 2>nul
endlocal
exit /b 1
)
:: 5. Verify the file was actually written
if not exist "%BinFolder%\%ToolName%" (
echo [ERROR] Download reported success but file not found. >&2
endlocal
exit /b 1
)
:LaunchApp
echo [OK] Dependencies verified.
"%BinFolder%\%ToolName%" --version
endlocal
exit /b 0
Why curl -f is critical:
Without the -f (--fail) flag, curl treats any completed HTTP response as a success, even a 404 Not Found or 500 Internal Server Error. It will save the server's HTML error page as your output file (e.g., saving a "Page Not Found" HTML document as wget.exe). With -f, curl returns a non-zero exit code on HTTP errors, allowing the if errorlevel 1 check to catch the failure.
Method 2: Bootstrapping a PowerShell Module
Sometimes your dependency isn't an .exe but a PowerShell module from the PowerShell Gallery. You can bootstrap the module installation from Batch.
@echo off
setlocal
set "Module=PSWindowsUpdate"
set "MainScript=%~dp0myscript.ps1"
echo [INFO] Checking for required PowerShell module: %Module%...
powershell -NoProfile -Command ^
"if (-not (Get-Module -ListAvailable -Name '%Module%')) {" ^
" Write-Host '[INFO] Installing %Module%...';" ^
" Install-Module -Name '%Module%' -Force -Scope CurrentUser -Confirm:$false" ^
"}"
if errorlevel 1 (
echo [ERROR] Could not install module: %Module%. >&2
endlocal
exit /b 1
)
:: Run the actual task
if not exist "%MainScript%" (
echo [ERROR] Main script not found: %MainScript% >&2
endlocal
exit /b 1
)
powershell -NoProfile -ExecutionPolicy Bypass -File "%MainScript%"
if errorlevel 1 (
echo [ERROR] Main script exited with an error. >&2
endlocal
exit /b 1
)
endlocal
exit /b 0
Design notes:
-NoProfileprevents user profile scripts from interfering with the bootstrapper's predictable behavior.-Scope CurrentUseravoids requiring administrator privileges for module installation.-ExecutionPolicy Bypassensures the.ps1file can run regardless of the machine's execution policy setting.%~dp0on the script path ensures the.ps1file is found relative to the bootstrapper, not the current working directory.
Method 3: Downloading and Extracting an Archive
If your toolset consists of multiple files, it is better to download a single .zip archive and extract it.
@echo off
setlocal
set "ZipURL=https://example.com/tools.zip"
set "ZipPath=%temp%\tools_%RANDOM%.zip"
set "ExtractTo=%~dp0tools"
echo [1/3] Downloading toolset...
curl -f -L -o "%ZipPath%" "%ZipURL%"
if errorlevel 1 (
echo [ERROR] Download failed. >&2
del "%ZipPath%" 2>nul
endlocal
exit /b 1
)
if not exist "%ZipPath%" (
echo [ERROR] Download reported success but file not found. >&2
endlocal
exit /b 1
)
echo [2/3] Extracting files...
tar -xf "%ZipPath%" -C "%ExtractTo%"
if errorlevel 1 (
echo [ERROR] Extraction failed. >&2
del "%ZipPath%" 2>nul
endlocal
exit /b 1
)
echo [3/3] Cleaning up temporary files...
del "%ZipPath%" 2>nul
echo [OK] Toolset ready in: %ExtractTo%
endlocal
exit /b 0
Why tar for zip files?
Modern Windows 10 (1803+) and Windows 11 include the tar command, which can natively extract .zip, .tar.gz, and other archive formats without needing third-party tools like 7-Zip. This makes it ideal for bootstrappers, since the goal is to avoid requiring external dependencies to install external dependencies.
How to Avoid Common Errors
Wrong Way: Hardcoding C:\Downloads
Every user has a different folder structure. If you download files to a folder the user doesn't have write access to, the script will fail.
Correct Way: Use %temp% for temporary downloads and %~dp0bin (local to the script) for permanent dependencies.
Wrong Way: Using curl Without --fail
Without -f, a 404 Not Found response saves the HTML error page as your dependency file. The script then reports success and later tries to execute a corrupted binary.
Correct Way: Always use curl -f -L -o ... and verify the file exists after download.
Problem: TLS/SSL Errors
Older versions of Windows might not support the modern TLS certificates of your download server.
Solution: Ensure the machine has the latest Windows Updates to support modern HTTPS. Avoid curl -k (--insecure) as it disables all certificate validation, making the download vulnerable to man-in-the-middle attacks, where a malicious executable could be substituted for your tool. If you must use -k on an isolated internal network, add a checksum verification step immediately after the download (see Best Practices below).
Best Practices and Rules
1. Integrity Checking
Do not just check if the file exists. Verify its checksum after downloading to confirm the file is authentic and uncorrupted. This is especially important when the downloaded file is an executable.
:: Verify SHA256 checksum after download
set "ExpectedHash=3E23E8160039594A33894F6564E1B1348BBD7A0088D42C4ACB73EEAED59C009D"
set "ActualHash="
for /f "skip=1 delims=" %%h in (
'certutil -hashfile "%BinFolder%\%ToolName%" SHA256 2^>nul'
) do if not defined ActualHash set "ActualHash=%%h"
if /i not "%ActualHash%"=="%ExpectedHash%" (
echo [ERROR] Checksum mismatch! The downloaded file may be corrupt or tampered with. >&2
del "%BinFolder%\%ToolName%" 2>nul
endlocal
exit /b 1
)
echo [OK] Checksum verified.
2. User Permission
Inform the user before starting a large download, especially in interactive contexts.
choice /m "A 100MB download is required. Proceed?"
if errorlevel 2 (
echo Download cancelled by user.
endlocal
exit /b 0
)
3. Always Use HTTPS
Always use https:// URLs for your dependencies. Using http:// leaves your users vulnerable to man-in-the-middle attacks where a malicious file could be substituted during transit.
Conclusions
Building a bootstrapper turns your standalone Batch script into a sophisticated, self-contained deployment tool. By automating the detection and acquisition of dependencies, you provide a "One-Click" experience for your users while ensuring that your automation always has the exact environment it needs to succeed. This professional approach drastically reduces setup-related support tickets and increases the reliability of your cross-machine deployments.