How to Store and Retrieve Script State Across Reboots in Batch Script
Many automation tasks like system updates, driver installations, or complex software deployments require the computer to restart halfway through the process. By default, a Batch script "forgets" everything as soon as it is closed or the machine reboots. To handle multi-stage operations, you must implement a "Persistence Layer" that allows the script to remember which stage it was on before the power was cycled.
This guide will explain how to use state files and registry keys to maintain script continuity across reboots.
Method 1: The "State File" Method (Easiest)
This method involves writing a simple stage number to a permanent file on the disk. When the script starts, it reads this file and jumps to the correct section.
The Persistent Installer Template
@echo off
setlocal
set "StateFile=%localappdata%\MyInstaller\install_stage.txt"
set "StateDir=%localappdata%\MyInstaller"
:: Ensure the state directory exists
if not exist "%StateDir%" mkdir "%StateDir%"
:: 1. Read the current state (default to Stage 1 if file missing)
set "stage=1"
if exist "%StateFile%" (
set /p "stage=" < "%StateFile%"
)
:: Validate the stage value
if "%stage%"=="" set "stage=1"
echo [RESUME] Starting from Stage %stage%...
echo.
:: 2. Route the script based on state
if "%stage%"=="1" goto :STAGE_1
if "%stage%"=="2" goto :STAGE_2
if "%stage%"=="3" goto :STAGE_3
:: Unknown stage - reset
echo [ERROR] Unknown stage: %stage%. Resetting to Stage 1.
echo 1 > "%StateFile%"
goto :STAGE_1
:STAGE_1
echo [STAGE 1/3] Installing Core Components...
:: === Stage 1 tasks here ===
echo Simulating installation...
timeout /t 3 /nobreak >nul
:: === End of Stage 1 tasks ===
:: Verify Stage 1 completed successfully
:: (Add your own verification logic here)
:: Save state for next stage
echo 2 > "%StateFile%"
echo.
echo [INFO] Stage 1 complete. A reboot is required to continue.
echo The script will need to be run again after reboot.
pause
exit /b 0
:STAGE_2
echo [STAGE 2/3] Resuming after reboot. Applying settings...
:: === Stage 2 tasks here ===
echo Simulating configuration...
timeout /t 3 /nobreak >nul
:: === End of Stage 2 tasks ===
:: Save state for next stage (no reboot needed this time)
echo 3 > "%StateFile%"
goto :STAGE_3
:STAGE_3
echo [STAGE 3/3] Final cleanup...
:: === Stage 3 tasks here ===
echo Finalizing...
timeout /t 2 /nobreak >nul
:: === End of Stage 3 tasks ===
:: All stages complete - clean up the state file
del "%StateFile%" >nul 2>&1
echo.
echo [SUCCESS] All stages complete. Installation finished.
pause
endlocal
Method 2: Auto-Resuming after Reboot (RunOnce)
Storing the state is only half the battle; you also need the script to launch itself automatically when the user logs back in. We use the Windows RunOnce registry key for this.
@echo off
setlocal
set "StateFile=%localappdata%\MyUpdater\update_stage.txt"
set "StateDir=%localappdata%\MyUpdater"
set "RegPath=HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce"
if not exist "%StateDir%" mkdir "%StateDir%"
:: Check if we are resuming from a reboot
if "%~1"=="--resume" (
echo [RESUME] Resuming after reboot...
goto :Phase2
)
:: --- PHASE 1 ---
echo [PHASE 1] Performing pre-reboot tasks...
:: === Phase 1 tasks here ===
echo Installing components...
timeout /t 3 /nobreak >nul
:: === End of Phase 1 ===
:: Save state indicating Phase 1 is complete
echo phase2 > "%StateFile%"
:: Register the script to auto-run on next login with the --resume flag
reg add "%RegPath%" /v "MyUpdater" /t REG_SZ /d "\"%~f0\" --resume" /f >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Could not register for auto-resume.
echo Please run this script with --resume after rebooting.
pause
exit /b 1
)
echo [INFO] Phase 1 complete.
echo The system will reboot in 30 seconds.
echo The script will resume automatically on next login.
shutdown /r /t 30 /c "Rebooting to continue installation. Save your work."
exit /b 0
:: --- PHASE 2 ---
:Phase2
echo [PHASE 2] Completing post-reboot tasks...
:: Verify Phase 1 actually completed
if not exist "%StateFile%" (
echo [ERROR] State file missing. Phase 1 may not have completed.
echo Please run the script without --resume to start over.
pause
exit /b 1
)
:: === Phase 2 tasks here ===
echo Finalizing configuration...
timeout /t 3 /nobreak >nul
:: === End of Phase 2 ===
:: Clean up state file and any remaining registry entries
del "%StateFile%" >nul 2>&1
rmdir "%StateDir%" >nul 2>&1
reg delete "%RegPath%" /v "MyUpdater" /f >nul 2>&1
echo.
echo [SUCCESS] All phases complete. System is fully configured.
pause
endlocal
By passing --resume as an argument when registering with RunOnce, the script can detect on startup whether it is running fresh or continuing from a reboot. This is cleaner than reading a state file for the initial routing decision.
Method 3: Using the Registry for Complex State Data
If you need to store more than just a stage number (like a backup path, a username, or a timestamp), the Registry provides structured key-value storage.
@echo off
setlocal
set "MyKey=HKCU\Software\MyAutomation"
:: Save multiple values
reg add "%MyKey%" /v "LastBackupDate" /t REG_SZ /d "%date%" /f >nul 2>&1
reg add "%MyKey%" /v "BackupPath" /t REG_SZ /d "D:\Backups" /f >nul 2>&1
reg add "%MyKey%" /v "StageComplete" /t REG_DWORD /d 1 /f >nul 2>&1
echo [SAVED] State written to registry.
echo.
:: Retrieve values
set "LastRun="
for /f "tokens=2*" %%a in ('reg query "%MyKey%" /v "LastBackupDate" 2^>nul ^| findstr /c:"LastBackupDate"') do (
set "LastRun=%%b"
)
set "BackupPath="
for /f "tokens=2*" %%a in ('reg query "%MyKey%" /v "BackupPath" 2^>nul ^| findstr /c:"BackupPath"') do (
set "BackupPath=%%b"
)
if defined LastRun (
echo [INFO] Last backup: %LastRun%
echo [INFO] Backup path: %BackupPath%
) else (
echo [INFO] No previous state found.
)
:: Cleanup when done (uncomment when the process is complete)
:: reg delete "%MyKey%" /f >nul 2>&1
pause
endlocal
How to Avoid Common Errors
Wrong Way: Storing the state in the %TEMP% folder
The %temp% folder is often cleared by Windows or IT maintenance scripts during or shortly after a reboot.
Correct Way: Use %localappdata%, %programdata%, or the Windows Registry to ensure the data survives maintenance cycles.
Problem: Infinite Reboot Loops
If you add your script to RunOnce but the script crashes before it finishes its work, RunOnce entries are automatically removed after execution (regardless of success or failure). However, if your script re-registers itself in RunOnce as part of its logic and crashes before completing, it could create a loop.
Best Practice: Never re-register in RunOnce during the resume phase. The entry should only be created once, during the initial phase before the reboot.
Problem: State file corruption
If the system crashes during the write to the state file, the file might be empty or contain partial data.
Best Practice: Always validate the state value after reading it and fall back to a known-good state (like Stage 1) if the value is unrecognized.
Best Practices and Rules
1. User Context
Remember that HKCU is specific to the user. If you use RunOnce in HKCU, it will only resume when that exact same user logs back in. If the machine reboots and a different admin logs in, the script won't start. For machine-level operations, use HKLM and run as Administrator.
2. Cleanup
Always delete your state files and registry entries once the entire multi-stage process is finished (as shown in all three methods). Leaving artifacts behind can confuse future audits or lead to unexpected behavior.
3. Verification
Before jumping to Stage 2, always verify that Stage 1's work was actually successful (e.g., check if a file was created or a service was installed). Don't just trust the state number.
Conclusions
Implementing state persistence in a Batch script is what turns a simple sequence of commands into a robust, semi-intelligent workflow. By using the combination of state files for data and the RunOnce registry key for execution, you can build automation that flawlessly navigates system restarts. This persistence is a key requirement for professional-grade deployments and maintenance tools.