Batch Installer Template

Overview

The Batch Installer Template provides a lightweight, compatible foundation for creating installation scripts for Windows systems that need to support older Windows versions or environments where PowerShell may not be available.

Complete Batch Installer Template

@echo off
setlocal enabledelayedexpansion

REM {{app_name}} Installer Script
REM Version: {{app_version}}
REM Generated by I.S.A.A.C. v{{isaac_version}}
REM Platform: Windows (Batch)
REM Generated: {{generation_timestamp}}

REM =============================================================================
REM CONFIGURATION VARIABLES
REM =============================================================================

set "SCRIPT_NAME=%~nx0"
set "SCRIPT_DIR=%~dp0"
set "LOG_FILE=%TEMP%\{{app_name}}_install_%DATE:~-4,4%%DATE:~-10,2%%DATE:~-7,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%.log"
set "TEMP_DIR=%TEMP%\{{app_name}}_install_%RANDOM%"
set "BACKUP_DIR=%TEMP%\{{app_name}}_backup_%DATE:~-4,4%%DATE:~-10,2%%DATE:~-7,2%"

REM Application configuration
set "APP_NAME={{app_name}}"
set "APP_VERSION={{app_version}}"
set "APP_DESCRIPTION={{app_description}}"
set "INSTALL_PATH={{install_path}}"
set "SERVICE_NAME={{service_name}}"

REM Default configuration values
{{#each default_config}}
set "{{name}}={{value}}"
{{/each}}

REM Installation flags
set "INTERACTIVE_MODE=1"
set "SKIP_DEPENDENCIES=0"
set "DRY_RUN=0"
set "VERBOSE=0"
set "FORCE_INSTALL=0"

REM =============================================================================
REM UTILITY FUNCTIONS
REM =============================================================================

:log_info
echo [INFO] %DATE% %TIME% - %~1
echo [INFO] %DATE% %TIME% - %~1 >> "%LOG_FILE%"
goto :eof

:log_warn
echo [WARN] %DATE% %TIME% - %~1
echo [WARN] %DATE% %TIME% - %~1 >> "%LOG_FILE%"
goto :eof

:log_error
echo [ERROR] %DATE% %TIME% - %~1
echo [ERROR] %DATE% %TIME% - %~1 >> "%LOG_FILE%"
goto :eof

:log_debug
if "%VERBOSE%"=="1" (
    echo [DEBUG] %DATE% %TIME% - %~1
    echo [DEBUG] %DATE% %TIME% - %~1 >> "%LOG_FILE%"
)
goto :eof

:show_progress
set /a "percentage=(%~1*100)/%~2"
echo Progress: [%percentage%%%] %~3
goto :eof

:check_admin
net session >nul 2>&1
if %errorlevel% neq 0 (
    call :log_error "Administrator privileges required"
    echo This installer must be run as Administrator.
    echo Right-click on the installer and select "Run as administrator"
    pause
    exit /b 1
)
goto :eof

:check_windows_version
for /f "tokens=4-5 delims=. " %%i in ('ver') do set VERSION=%%i.%%j
call :log_info "Windows version: %VERSION%"

REM Check minimum Windows version (Windows 7 = 6.1)
if "%VERSION%" lss "{{min_windows_version}}" (
    call :log_error "Windows {{min_windows_version}} or later is required"
    exit /b 1
)
goto :eof

:detect_architecture
if "%PROCESSOR_ARCHITECTURE%"=="AMD64" (
    set "ARCH=x64"
) else if "%PROCESSOR_ARCHITECTURE%"=="x86" (
    set "ARCH=x86"
) else (
    set "ARCH=%PROCESSOR_ARCHITECTURE%"
)
call :log_info "Architecture: %ARCH%"
goto :eof

:check_disk_space
for /f "tokens=3" %%a in ('dir /-c "%INSTALL_PATH%\.." 2^>nul ^| find "bytes free"') do set "FREE_SPACE=%%a"
set "FREE_SPACE=%FREE_SPACE:,=%"
set /a "FREE_SPACE_MB=%FREE_SPACE%/1048576"
set "REQUIRED_SPACE_MB={{required_disk_space_mb}}"

if %FREE_SPACE_MB% lss %REQUIRED_SPACE_MB% (
    call :log_error "Insufficient disk space. Required: %REQUIRED_SPACE_MB%MB, Available: %FREE_SPACE_MB%MB"
    exit /b 1
)
call :log_info "Disk space check passed: %FREE_SPACE_MB%MB available"
goto :eof

:check_required_tools
{{#each required_tools}}
where "{{this}}" >nul 2>&1
if %errorlevel% neq 0 (
    call :log_error "Required tool not found: {{this}}"
    exit /b 1
)
{{/each}}
call :log_info "Required tools check passed"
goto :eof

REM =============================================================================
REM USER INTERFACE FUNCTIONS
REM =============================================================================

:show_welcome
cls
echo.
echo ╔══════════════════════════════════════════════════════════════╗
echo β•‘                    {{app_name}} Installer                    β•‘
echo β•‘                        Version {{app_version}}                        β•‘
echo ╠══════════════════════════════════════════════════════════════╣
echo β•‘                                                              β•‘
echo β•‘  {{app_description}}  β•‘
echo β•‘                                                              β•‘
echo β•‘  This installer will guide you through the setup process.   β•‘
echo β•‘  You can exit at any time with Ctrl+C.                     β•‘
echo β•‘                                                              β•‘
echo β•‘  Estimated installation time: {{estimated_time}}                  β•‘
echo β•‘  Required disk space: {{required_space}}                         β•‘
echo β•‘                                                              β•‘
echo β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
echo.

if "%INTERACTIVE_MODE%"=="1" (
    pause
)
goto :eof

:show_menu
echo.
echo β”Œβ”€ %~1 ─────────────────────────────────────────────────────┐
echo β”‚                                                              β”‚
set "menu_counter=1"
shift
:menu_loop
if "%~1"=="" goto :menu_end
echo β”‚  !menu_counter!^) %~1
set /a "menu_counter+=1"
shift
goto :menu_loop
:menu_end
echo β”‚                                                              β”‚
echo β”‚  Q^) Quit installer                                          β”‚
echo β”‚  H^) Help                                                    β”‚
echo β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
echo.
goto :eof

:get_menu_choice
set "max_choice=%~1"
:choice_loop
set /p "choice=Enter your choice [1-%max_choice%, Q, H]: "

if /i "%choice%"=="Q" (
    echo Installation cancelled by user.
    call :cleanup_and_exit 0
)

if /i "%choice%"=="H" (
    call :show_help
    goto :choice_loop
)

REM Validate numeric choice
echo %choice%| findstr /r "^[1-9][0-9]*$" >nul
if %errorlevel% neq 0 (
    echo Invalid input. Please enter a number, Q to quit, or H for help.
    goto :choice_loop
)

if %choice% geq 1 if %choice% leq %max_choice% (
    exit /b %choice%
) else (
    echo Invalid choice. Please enter a number between 1 and %max_choice%.
    goto :choice_loop
)

:validate_port
set "port=%~1"
echo %port%| findstr /r "^[0-9][0-9]*$" >nul
if %errorlevel% neq 0 (
    echo Error: Port must be a number
    exit /b 1
)

if %port% lss 1024 (
    echo Error: Port must be 1024 or higher
    exit /b 1
)

if %port% gtr 65535 (
    echo Error: Port must be 65535 or lower
    exit /b 1
)

REM Check if port is in use
netstat -an | find ":%port% " >nul
if %errorlevel% equ 0 (
    echo Warning: Port %port% appears to be in use
    if "%INTERACTIVE_MODE%"=="1" (
        set /p "confirm=Continue anyway? [y/N]: "
        if /i not "!confirm!"=="y" exit /b 1
    ) else (
        exit /b 1
    )
)
exit /b 0

:get_validated_input
set "prompt=%~1"
set "validator=%~2"
set "default=%~3"

:input_loop
if not "%default%"=="" (
    set /p "input=%prompt% [%default%]: "
    if "!input!"=="" set "input=%default%"
) else (
    set /p "input=%prompt%: "
)

if "%input%"=="" if "%default%"=="" (
    echo This field is required. Please enter a value.
    goto :input_loop
)

call :%validator% "!input!"
if %errorlevel% neq 0 goto :input_loop

echo !input!
goto :eof

REM =============================================================================
REM SYSTEM CHECKS
REM =============================================================================

:check_system_requirements
call :log_info "Checking system requirements..."

call :check_admin
if %errorlevel% neq 0 exit /b 1

call :check_windows_version
if %errorlevel% neq 0 exit /b 1

call :detect_architecture

call :check_disk_space
if %errorlevel% neq 0 exit /b 1

call :check_required_tools
if %errorlevel% neq 0 exit /b 1

call :log_info "System requirements check passed"
goto :eof

REM =============================================================================
REM CONFIGURATION COLLECTION
REM =============================================================================

:collect_configuration
if "%INTERACTIVE_MODE%"=="0" (
    call :log_info "Using default configuration (non-interactive mode)"
    goto :eof
)

call :log_info "Collecting configuration parameters..."

echo.
echo ╔══════════════════════════════════════════════════════════════╗
echo β•‘                    Configuration Setup                      β•‘
echo β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
echo.

{{#each configurable_parameters}}
{{#if (eq type "choice")}}
REM {{description}}
echo {{prompt}}:
{{#each choices}}
echo   {{@index}}) {{label}} - {{description}}
{{/each}}

:choice_{{name}}_loop
set /p "choice=Choice [{{default_index}}]: "
if "!choice!"=="" set "choice={{default_index}}"

{{#each choices}}
if "!choice!"=="{{@index}}" (
    set "{{../name}}={{value}}"
    goto :choice_{{../name}}_end
)
{{/each}}

echo Invalid choice. Please try again.
goto :choice_{{name}}_loop
:choice_{{name}}_end

{{else}}
REM {{description}}
for /f %%i in ('call :get_validated_input "{{prompt}}" "{{#if validation.pattern}}validate_pattern_{{@index}}{{else}}validate_{{type}}{{/if}}" "{{default}}"') do set "{{name}}=%%i"
{{/if}}

{{/each}}

call :log_info "Configuration collection completed"
goto :eof

:show_configuration_summary
echo.
echo ╔══════════════════════════════════════════════════════════════╗
echo β•‘                   Configuration Summary                      β•‘
echo ╠══════════════════════════════════════════════════════════════╣
echo β•‘                                                              β•‘
echo β•‘  Application: %APP_NAME% v%APP_VERSION%
echo β•‘  Installation Path: %INSTALL_PATH%
{{#each configurable_parameters}}
echo β•‘  {{display_name}}: !{{name}}!
{{/each}}
echo β•‘                                                              β•‘
echo ╠══════════════════════════════════════════════════════════════╣
echo β•‘                                                              β•‘
echo β•‘  The installer will now proceed with these settings.        β•‘
echo β•‘  This process may take several minutes to complete.         β•‘
echo β•‘                                                              β•‘
echo β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
echo.

if "%INTERACTIVE_MODE%"=="1" (
    set /p "confirm=Proceed with installation? [Y/n]: "
    if /i "!confirm!"=="n" (
        echo Installation cancelled by user.
        call :cleanup_and_exit 0
    )
)
goto :eof

REM =============================================================================
REM INSTALLATION FUNCTIONS
REM =============================================================================

:install_dependencies
if "%SKIP_DEPENDENCIES%"=="1" (
    call :log_info "Skipping dependency installation"
    goto :eof
)

call :log_info "Installing dependencies..."

REM Check for Chocolatey
where choco >nul 2>&1
if %errorlevel% neq 0 (
    call :log_info "Installing Chocolatey package manager..."
    if "%DRY_RUN%"=="0" (
        powershell -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"
        if !errorlevel! neq 0 (
            call :log_error "Failed to install Chocolatey"
            exit /b 1
        )
    )
)

REM Install dependencies
{{#each windows_dependencies}}
call :log_info "Installing {{name}}..."
if "%DRY_RUN%"=="0" (
    choco install {{chocolatey_name}} -y
    if !errorlevel! neq 0 (
        call :log_error "Failed to install {{name}}"
        exit /b 1
    )
    
    REM Verify installation
    {{verify_command}} >nul 2>&1
    if !errorlevel! neq 0 (
        call :log_error "Installation verification failed for {{name}}"
        exit /b 1
    )
)
{{/each}}

call :log_info "Dependencies installed successfully"
goto :eof

:create_directories
call :log_info "Creating directories..."

if not exist "%INSTALL_PATH%" (
    if "%DRY_RUN%"=="0" (
        mkdir "%INSTALL_PATH%"
        if !errorlevel! neq 0 (
            call :log_error "Failed to create installation directory: %INSTALL_PATH%"
            exit /b 1
        )
    )
    call :log_info "Created directory: %INSTALL_PATH%"
)

REM Create additional directories
{{#each required_directories}}
if not exist "{{path}}" (
    if "%DRY_RUN%"=="0" (
        mkdir "{{path}}"
        if !errorlevel! neq 0 (
            call :log_error "Failed to create directory: {{path}}"
            exit /b 1
        )
    )
    call :log_info "Created directory: {{path}}"
)
{{/each}}

goto :eof

:install_application
call :log_info "Installing application files..."

if "%DRY_RUN%"=="0" (
    REM Copy application files
    xcopy "%SCRIPT_DIR%\files\*" "%INSTALL_PATH%\" /E /I /Y
    if !errorlevel! neq 0 (
        call :log_error "Failed to copy application files"
        exit /b 1
    )
)

call :log_info "Application files installed successfully"
goto :eof

:configure_service
call :log_info "Configuring Windows service..."

if "%DRY_RUN%"=="0" (
    REM Create service
    sc create "%SERVICE_NAME%" binPath= "%INSTALL_PATH%\bin\%APP_NAME%.exe" start= auto
    if !errorlevel! neq 0 (
        call :log_error "Failed to create service: %SERVICE_NAME%"
        exit /b 1
    )
    
    REM Start service
    sc start "%SERVICE_NAME%"
    if !errorlevel! neq 0 (
        call :log_warn "Service created but failed to start: %SERVICE_NAME%"
    ) else (
        call :log_info "Service started successfully: %SERVICE_NAME%"
    )
)

goto :eof

:validate_installation
call :log_info "Validating installation..."

REM Check if service is running
sc query "%SERVICE_NAME%" | find "RUNNING" >nul
if %errorlevel% equ 0 (
    call :log_info "βœ“ Service is running: %SERVICE_NAME%"
) else (
    call :log_error "βœ— Service is not running: %SERVICE_NAME%"
    exit /b 1
)

REM Check if application responds
{{#if health_check_url}}
curl -f "{{health_check_url}}" >nul 2>&1
if %errorlevel% equ 0 (
    call :log_info "βœ“ Application is responding"
) else (
    call :log_error "βœ— Application is not responding"
    exit /b 1
)
{{/if}}

call :log_info "Installation validation completed successfully"
goto :eof

REM =============================================================================
REM CLEANUP AND ERROR HANDLING
REM =============================================================================

:cleanup_temp_files
if exist "%TEMP_DIR%" (
    call :log_debug "Cleaning up temporary directory: %TEMP_DIR%"
    rmdir /s /q "%TEMP_DIR%" 2>nul
)
goto :eof

:cleanup_and_exit
set "exit_code=%~1"
if "%exit_code%"=="" set "exit_code=0"

call :log_info "Cleaning up and exiting..."
call :cleanup_temp_files

if "%exit_code%"=="0" (
    call :log_info "Installation completed successfully!"
    echo.
    echo ╔══════════════════════════════════════════════════════════════╗
    echo β•‘                 Installation Complete!                      β•‘
    echo ╠══════════════════════════════════════════════════════════════╣
    echo β•‘                                                              β•‘
    echo β•‘  %APP_NAME% has been successfully installed.                 β•‘
    echo β•‘                                                              β•‘
    echo β•‘  Service status: sc query %SERVICE_NAME%                     β•‘
    echo β•‘  Logs location: {{log_path}}                                 β•‘
    echo β•‘  Configuration: {{config_path}}                              β•‘
    echo β•‘                                                              β•‘
    echo β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
) else (
    call :log_error "Installation failed with exit code: %exit_code%"
    echo Check the log file for details: %LOG_FILE%
)

exit /b %exit_code%

:show_help
echo.
echo %APP_NAME% Installer Help
echo.
echo Usage: %SCRIPT_NAME% [options]
echo.
echo Options:
echo   --non-interactive    Run in non-interactive mode
echo   --skip-deps         Skip dependency installation
echo   --dry-run           Show what would be installed
echo   --verbose           Enable verbose logging
echo   --force             Force installation over existing
echo   --help              Show this help message
echo.
goto :eof

REM =============================================================================
REM MAIN INSTALLATION WORKFLOW
REM =============================================================================

:main
REM Parse command line arguments
:parse_args
if "%~1"=="" goto :args_done
if /i "%~1"=="--non-interactive" (
    set "INTERACTIVE_MODE=0"
    shift
    goto :parse_args
)
if /i "%~1"=="--skip-deps" (
    set "SKIP_DEPENDENCIES=1"
    shift
    goto :parse_args
)
if /i "%~1"=="--dry-run" (
    set "DRY_RUN=1"
    shift
    goto :parse_args
)
if /i "%~1"=="--verbose" (
    set "VERBOSE=1"
    shift
    goto :parse_args
)
if /i "%~1"=="--force" (
    set "FORCE_INSTALL=1"
    shift
    goto :parse_args
)
if /i "%~1"=="--help" (
    call :show_help
    exit /b 0
)
echo Unknown option: %~1
call :show_help
exit /b 1

:args_done

REM Create temporary directory
if "%DRY_RUN%"=="0" mkdir "%TEMP_DIR%" 2>nul

REM Start installation
call :log_info "Starting %APP_NAME% installation..."
call :log_info "Log file: %LOG_FILE%"

REM Installation steps
call :show_welcome
call :check_system_requirements
if %errorlevel% neq 0 call :cleanup_and_exit 1

call :collect_configuration
call :show_configuration_summary

REM Main installation phases
set "total_steps={{total_installation_steps}}"
set "current_step=0"

{{#each installation_steps}}
set /a "current_step+=1"
call :show_progress !current_step! %total_steps% "{{description}}"
call :{{function_name}}
if !errorlevel! neq 0 call :cleanup_and_exit 1
{{/each}}

REM Final validation
set /a "current_step+=1"
call :show_progress !current_step! %total_steps% "Validating installation"
call :validate_installation
if %errorlevel% neq 0 call :cleanup_and_exit 1

REM Success
call :cleanup_and_exit 0

REM Execute main function
call :main %*

Template Features

Batch Script Capabilities

  • Wide Compatibility: Works on Windows XP through Windows 11

  • No Dependencies: Runs without PowerShell or .NET Framework

  • Lightweight: Minimal resource usage and fast execution

  • Native Windows: Uses built-in Windows commands and utilities

Core Functionality

  • Interactive Configuration: Menu-driven parameter collection

  • System Validation: Comprehensive system requirement checking

  • Progress Tracking: Visual progress indicators for long operations

  • Error Handling: Robust error detection and recovery

  • Logging: Detailed installation logging for troubleshooting

Windows Integration

  • Service Management: Windows service creation and management

  • Registry Operations: Windows registry configuration (if needed)

  • File Association: File type association setup

  • Chocolatey Integration: Package manager integration for dependencies

User Experience

  • Professional Interface: Clean, formatted console output

  • Input Validation: Robust parameter validation and error messages

  • Help System: Built-in help and usage information

  • Non-Interactive Mode: Support for automated installations

This Batch template provides reliable installation capabilities for Windows environments where maximum compatibility is required, while still maintaining professional user experience and comprehensive functionality.

Last updated