Skip to main content

How to Restore a Hyper-V VM Snapshot in Batch Script

When a software update fails, a configuration change breaks an application, or a test environment needs to be reset to a known state, restoring a Hyper-V checkpoint allows you to revert the virtual machine to exactly how it was when the checkpoint was created. This operation takes seconds regardless of the VM's disk size, making it dramatically faster than reinstalling or manually undoing changes.

In this guide, we will explore how to restore Hyper-V VM checkpoints from a Batch Script using PowerShell, including selecting specific checkpoints, handling running VMs, and implementing safe rollback workflows.

Understanding What Happens During a Restore

When you restore a checkpoint:

  1. The VM is stopped (if running).
  2. The current disk state is discarded and replaced with the checkpoint's disk state.
  3. For standard checkpoints, the memory and device state are also restored, and the VM resumes where it was.
  4. For production checkpoints, only the disk is restored, and the VM boots fresh.
  5. All changes made after the checkpoint was created are permanently lost unless you created another checkpoint before restoring.
warning

Restoring a checkpoint permanently discards all changes made after that checkpoint. This includes files created, data written, and configurations applied. Always create a new checkpoint before restoring if you need to preserve the current state.

Method 1: Restoring the Most Recent Checkpoint

@echo off
setlocal

set "vm_name=WebServer-01"

:: Verify Admin
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges required.
pause
exit /b 1
)

echo Restoring most recent checkpoint for "%vm_name%"...

powershell -NoProfile -Command ^
"$cp = Get-VMCheckpoint -VMName '%vm_name%' | Sort-Object CreationTime -Descending | Select-Object -First 1;" ^
"if ($cp) {" ^
" Write-Host ('Restoring: ' + $cp.Name + ' (Created: ' + $cp.CreationTime + ')');" ^
" Restore-VMCheckpoint -VMCheckpoint $cp -Confirm:$false;" ^
" Write-Host '[SUCCESS] Checkpoint restored.'" ^
"} else {" ^
" Write-Host '[ERROR] No checkpoints found for this VM.'; exit 1" ^
"}"

pause

Method 2: Restoring a Specific Named Checkpoint

When multiple checkpoints exist, restore a specific one by name.

@echo off
setlocal

set "vm_name=DatabaseVM"
set "cp_name=Pre-Update 2024-01-15"

net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

echo Restoring checkpoint "%cp_name%" for "%vm_name%"...

powershell -NoProfile -Command ^
"Restore-VMCheckpoint -VMName '%vm_name%' -Name '%cp_name%' -Confirm:$false"

if %errorlevel%==0 (
echo [SUCCESS] Checkpoint restored.
) else (
echo [ERROR] Checkpoint not found or restore failed.
)

pause

Method 3: Interactive Checkpoint Selector

For administrators who need to browse available checkpoints and choose one:

@echo off
title Checkpoint Restore Tool
setlocal enabledelayedexpansion

net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Run as Administrator.
pause
exit /b 1
)

set /p "vm_name=Enter VM name: "

echo.
echo Available checkpoints for "%vm_name%":
echo =======================================
echo.

set "count=0"
for /f "usebackq delims=" %%L in (`powershell -NoProfile -Command ^
"Get-VMCheckpoint -VMName '%vm_name%' -ErrorAction SilentlyContinue | Sort-Object CreationTime | ForEach-Object { $_.Name + ' ^| ' + $_.CreationTime }"`) do (
set /a count+=1
set "cp_name[!count!]=%%L"
echo !count!. %%L
)

if !count!==0 (
echo No checkpoints found.
pause
exit /b 1
)

echo.
echo 0. Cancel
echo.
set /p "choice=Select checkpoint to restore: "

if "!choice!"=="0" exit /b 0

if !choice! lss 1 (
echo [ERROR] Invalid selection.
pause
exit /b 1
)
if !choice! gtr !count! (
echo [ERROR] Invalid selection.
pause
exit /b 1
)

:: Extract the checkpoint name (before the pipe delimiter)
set "selected=!cp_name[%choice%]!"
for /f "tokens=1 delims=|" %%N in ("!selected!") do set "restore_name=%%N"

:: Trim trailing spaces
call :TrimRight restore_name

echo.
echo Selected: !restore_name!
echo.
echo WARNING: All changes made after this checkpoint will be LOST.
set /p "confirm=Type RESTORE to proceed: "

if /i not "!confirm!"=="RESTORE" (
echo [CANCELLED]
pause
exit /b 0
)

echo.
echo Restoring...
powershell -NoProfile -Command ^
"$cp = Get-VMCheckpoint -VMName '%vm_name%' | Where-Object { $_.Name -eq '!restore_name!' } | Select-Object -First 1;" ^
"if ($cp) { Restore-VMCheckpoint -VMCheckpoint $cp -Confirm:$false; Write-Host '[OK] Restored.' }" ^
"else { Write-Host '[ERROR] Checkpoint not found.'; exit 1 }"

pause
exit /b 0

:TrimRight
:: Remove trailing spaces from the variable named in %1
set "val=!%1!"
:TrimLoop
if "!val:~-1!"==" " (
set "val=!val:~0,-1!"
goto TrimLoop
)
set "%1=!val!"
exit /b 0

Method 4: Safe Restore with Pre-Restore Checkpoint

Before restoring, create a checkpoint of the current state so you can undo the restore if needed.

@echo off
setlocal

set "vm_name=AppServer-01"
set "restore_to=Pre-Deployment 2024-01-15"

net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

echo =============================================
echo SAFE CHECKPOINT RESTORE
echo =============================================
echo.
echo VM: %vm_name%
echo Restore to: %restore_to%
echo.

:: Build a timestamp for the safety checkpoint name
for /f "tokens=2 delims==" %%T in ('wmic os get LocalDateTime /value') do set "dt=%%T"
set "safety_name=Pre-Restore Safety %dt:~0,4%-%dt:~4,2%-%dt:~6,2% %dt:~8,2%-%dt:~10,2%"

:: Step 1: Create a safety checkpoint of current state
echo [1/2] Creating safety checkpoint: %safety_name%
powershell -NoProfile -Command ^
"Checkpoint-VM -Name '%vm_name%' -SnapshotName '%safety_name%'"

if %errorlevel% neq 0 (
echo [ABORT] Could not create safety checkpoint.
pause
exit /b 1
)
echo Safety checkpoint saved.

:: Step 2: Restore the target checkpoint
echo.
echo [2/2] Restoring to: %restore_to%
powershell -NoProfile -Command ^
"Restore-VMCheckpoint -VMName '%vm_name%' -Name '%restore_to%' -Confirm:$false"

if %errorlevel%==0 (
echo.
echo [SUCCESS] VM restored to "%restore_to%".
echo.
echo If you need to undo this restore, run:
echo Restore-VMCheckpoint -VMName "%vm_name%" -Name "%safety_name%" -Confirm:$false
) else (
echo [ERROR] Restore failed. Current state preserved in safety checkpoint.
)

pause

Method 5: Restoring and Immediately Starting the VM

After restoring a production checkpoint (disk-only), the VM is left in the Off state and needs to be started manually.

@echo off
setlocal

set "vm_name=WebServer-01"
set "cp_name=Known Good State"
set "boot_timeout=60"

net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Admin required.
pause
exit /b 1
)

echo Restoring and starting "%vm_name%"...

:: Restore
powershell -NoProfile -Command ^
"Restore-VMCheckpoint -VMName '%vm_name%' -Name '%cp_name%' -Confirm:$false"

if %errorlevel% neq 0 (
echo [ERROR] Restore failed.
pause
exit /b 1
)

echo [OK] Checkpoint restored.

:: Start the VM
echo Starting VM...
powershell -NoProfile -Command "Start-VM -Name '%vm_name%'"

if %errorlevel% neq 0 (
echo [ERROR] Failed to start VM.
pause
exit /b 1
)

:: Wait for Running state
echo Waiting for VM to reach Running state (timeout: %boot_timeout%s^)...
powershell -NoProfile -Command ^
"$timeout = %boot_timeout%;" ^
"$elapsed = 0;" ^
"while ((Get-VM -Name '%vm_name%').State -ne 'Running' -and $elapsed -lt $timeout) {" ^
" Start-Sleep -Seconds 2; $elapsed += 2" ^
"};" ^
"$state = (Get-VM -Name '%vm_name%').State;" ^
"if ($state -eq 'Running') { Write-Host \"[OK] VM is running. Boot time: ${elapsed}s\" }" ^
"else { Write-Host \"[WARNING] VM state: $state after ${timeout}s timeout\"; exit 1 }"

pause

Common Mistakes

The Wrong Way: Restoring Without a Safety Net

:: WRONG - No way to undo the restore
powershell -Command "Restore-VMCheckpoint -VMName 'ProdServer' -Name 'OldCheckpoint' -Confirm:$false"
:: All recent changes are permanently lost

Output Concern: If the restored checkpoint is older than expected or the wrong one, all work since that checkpoint is irreversibly lost. Always create a new checkpoint before restoring to preserve the current state as a fallback.

The Wrong Way: Restoring While the VM Is Running (Without Planning)

:: RISKY - VM will be forcefully stopped
powershell -Command "Restore-VMCheckpoint -VMName 'ActiveServer' -Name 'Backup' -Confirm:$false"

While Hyper-V will stop the VM before restoring, active users will experience an immediate disconnection without warning. For production VMs, gracefully shut down or notify users before restoring.

Best Practices

  1. Create a pre-restore checkpoint: Always snapshot the current state before restoring, so you can undo the restore if needed.
  2. Verify the checkpoint name: Use Get-VMCheckpoint to list available checkpoints and confirm you are restoring the correct one.
  3. Notify users before restoring production VMs: Active sessions will be terminated without warning.
  4. Start the VM after restoring production checkpoints: Production checkpoints leave the VM in the Off state.
  5. Delete the safety checkpoint after verification: Once you confirm the restore is correct, remove the pre-restore safety checkpoint to reclaim disk space.

Conclusion

Restoring Hyper-V VM checkpoints from a Batch Script is handled by PowerShell's Restore-VMCheckpoint cmdlet. The key to safe restoration is always creating a pre-restore safety checkpoint, selecting the correct checkpoint by name, and verifying the VM's state after the operation. Whether performing emergency rollbacks in production or resetting lab environments between tests, checkpoint restoration provides instant, reliable recovery measured in seconds rather than hours.