GUIDE / WINDOWS SERVER / HYPER-V / BACKUP / POWERSHELL

Automated Hyper-V VM backups: PowerShell export as a free backup solution

Automate Hyper-V VM exports with PowerShell: Export-VM, HyperV-Backup.ps1, ExportPath, Task Scheduler, network paths, retention and restore testing.

HYPER-VEXPORTSTORAGERESTORE
Practical script: HyperV-Backup-Sille-Solutions.ps1 PowerShell · native Hyper-V cmdlets
<#
.SYNOPSIS
    Automatisierter Hyper-V VM-Export mit optionaler Kopie auf ein Remote-Ziel.

.DESCRIPTION
    Moderne, native Variante des klassischen HyperV-Backup-Ansatzes.
    Verwendet ausschließlich das Hyper-V PowerShell-Modul und Export-VM.
    Unterstützt:
      - lokale Exporte
      - optionales Herunterfahren (-TurnOff) oder Speichern (-SaveState)
      - optionalen Neustart / Resume
      - Kopie des fertigen Exports auf eine UNC-Freigabe
      - optionalen StartDelay
      - vorhandenes Ziel wird vor dem Export entfernt
      - Exit-Codes für die Aufgabenplanung

    Nur auf Hyper-V-Systemen verwenden und ausschließlich VMs sichern,
    für deren Betrieb und Sicherung eine Berechtigung besteht.

.EXAMPLE
    powershell.exe -NoProfile -File .\HyperV-Backup-Sille.ps1 `
      -VM "FILESERVER01" `
      -ExportPath "D:\HyperV-Exports"

.EXAMPLE
    powershell.exe -NoProfile -File .\HyperV-Backup-Sille.ps1 `
      -VM "FILESERVER01" `
      -ExportPath "D:\HyperV-Exports" `
      -RemotePath "\\BACKUP01\HyperV$" `
      -TurnOff `
      -StartDelay 60 `
      -Verbose
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]
    [string]$VM,

    [Parameter(Mandatory=$true)]
    [string]$ExportPath,

    [Parameter(Mandatory=$false)]
    [string]$RemotePath,

    [Parameter(Mandatory=$false)]
    [int]$StartDelay = 0,

    [Parameter(Mandatory=$false)]
    [switch]$TurnOff,

    [Parameter(Mandatory=$false)]
    [switch]$SaveState
)

$ErrorActionPreference = 'Stop'

function Write-Step {
    param([string]$Message)
    Write-Host ("[{0}] {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message)
}

$vmObject = $null
$wasRunning = $false
$wasSaved = $false
$localExport = Join-Path -Path $ExportPath -ChildPath $VM
$remoteExport = $null

try {
    if (-not (Get-Command Export-VM -ErrorAction SilentlyContinue)) {
        throw "Das Hyper-V PowerShell-Modul bzw. Export-VM ist nicht verfügbar."
    }

    $vmObject = Get-VM -Name $VM -ErrorAction Stop
    $wasRunning = ($vmObject.State -eq 'Running')
    $wasSaved = ($vmObject.State -eq 'Saved')

    if (-not (Test-Path -LiteralPath $ExportPath)) {
        Write-Step "Erstelle lokales Exportverzeichnis: $ExportPath"
        New-Item -ItemType Directory -Path $ExportPath -Force | Out-Null
    }

    if (Test-Path -LiteralPath $localExport) {
        Write-Step "Entferne vorhandenen lokalen Export: $localExport"
        Remove-Item -LiteralPath $localExport -Recurse -Force
    }

    if ($wasRunning) {
        if ($TurnOff -and $SaveState) {
            throw "-TurnOff und -SaveState dürfen nicht gleichzeitig verwendet werden."
        }

        if ($TurnOff) {
            Write-Step "Fahre VM '$VM' kontrolliert herunter."
            Stop-VM -Name $VM -Force -ErrorAction Stop
        }
        elseif ($SaveState) {
            Write-Step "Speichere Zustand der VM '$VM'."
            Save-VM -Name $VM -ErrorAction Stop
        }
        else {
            Write-Step "VM '$VM' läuft. Export-VM wird mit dem aktuellen Hyper-V-Live-State-Verfahren ausgeführt."
        }
    }

    Write-Step "Starte Export nach: $localExport"
    if ($wasRunning -and -not $TurnOff -and -not $SaveState) {
        Export-VM -Name $VM -Path $ExportPath -CaptureLiveState CaptureDataConsistentState -ErrorAction Stop
    }
    else {
        Export-VM -Name $VM -Path $ExportPath -ErrorAction Stop
    }

    if ($StartDelay -gt 0) {
        Write-Step "Warte $StartDelay Sekunden."
        Start-Sleep -Seconds $StartDelay
    }

    if ($wasRunning -and ($TurnOff -or $SaveState)) {
        if ($SaveState) {
            Write-Step "Setze gespeicherten Zustand der VM fort."
            Start-VM -Name $VM -ErrorAction Stop | Out-Null
        }
        else {
            Write-Step "Starte VM '$VM' wieder."
            Start-VM -Name $VM -ErrorAction Stop | Out-Null
        }
    }

    if ($RemotePath) {
        if (-not (Test-Path -LiteralPath $RemotePath)) {
            throw "Remote-Ziel ist nicht erreichbar: $RemotePath"
        }

        $remoteExport = Join-Path -Path $RemotePath -ChildPath $VM

        if (Test-Path -LiteralPath $remoteExport) {
            Write-Step "Entferne vorhandenen Remote-Export: $remoteExport"
            Remove-Item -LiteralPath $remoteExport -Recurse -Force
        }

        Write-Step "Kopiere Export nach: $remoteExport"
        Copy-Item -LiteralPath $localExport -Destination $remotePath -Recurse -Force -ErrorAction Stop

        Write-Step "Entferne lokalen Zwischenexport."
        Remove-Item -LiteralPath $localExport -Recurse -Force
    }

    Write-Step "Hyper-V-Backup erfolgreich abgeschlossen."
    exit 0
}
catch {
    Write-Error ("Backup fehlgeschlagen: {0}" -f $_.Exception.Message)

    # Falls die VM durch das Script angehalten wurde, versuchen wir sie
    # wieder verfügbar zu machen.
    if ($vmObject -and $wasRunning) {
        try {
            $current = Get-VM -Name $VM -ErrorAction Stop
            if ($current.State -ne 'Running') {
                Write-Step "Versuche, VM '$VM' nach dem Fehler wieder zu starten."
                Start-VM -Name $VM -ErrorAction Stop | Out-Null
            }
        }
        catch {
            Write-Error ("VM konnte nach dem Fehler nicht automatisch gestartet werden: {0}" -f $_.Exception.Message)
        }
    }

    exit 1
}

Version note: This is a modern, native implementation of the Hyper-V backup approach described in this guide. It does not require the historical PSHyperV library. Its parameters intentionally follow the familiar -VM, -ExportPath, -RemotePath, -TurnOff and -StartDelay pattern.

Why Hyper-V exports are interesting as a backup

A Hyper-V export can package a virtual machine into a restorable set of files. Microsoft describes an export as collecting virtual hard disks, VM configuration files and checkpoint files into one unit. The exact consistency behaviour depends on the Hyper-V configuration and capture method.

The idea behind the free backup

A Hyper-V host does not necessarily need a large backup suite to create an additional backup layer. PowerShell, the Hyper-V module, Windows Task Scheduler and enough storage can automate a repeatable export workflow. It is not a replacement for every professional backup platform, but it is very useful as an additional copy or for small environments.

What is actually backed up

A Hyper-V export is more than a copied VHDX. It includes the virtual disks, VM configuration and checkpoint data. That creates a package that can later be imported again and distinguishes an export from simply copying individual virtual disk files.

Export-VM: the core command

The native PowerShell cmdlet is `Export-VM`. The simplest form is `Export-VM -Name TestVM -Path D:\HyperV-Exports`. Microsoft also documents `Get-VM | Export-VM -Path D:\` to export all VMs.

Export-VM -Name "SERVER01" -Path "D:\HyperV-Export\SERVER01"

The classic HyperV-Backup script with -ExportPath

An older PowerShell script called `HyperV-Backup.ps1` can still be found online and was designed for exactly this use case. A typical invocation is `powershell.exe -File C:\Tools\HyperV-Backup.ps1 -VM "W2K8-VM" -ExportPath "D:\Exports"`. Depending on its parameters, the script can shut down a VM, export it, start it again and copy the export to a network location.

powershell.exe -File "C:\Tools\HyperV-Backup.ps1" -VM "SERVER01" -ExportPath "D:\HyperV-Exports"

What -ExportPath means in that script

In the classic script, `-ExportPath` identifies the local working directory where the export is created. It is a parameter of that script, not a parameter of the native `Export-VM` cmdlet. The native cmdlet calls the corresponding parameter `-Path`.

The automated workflow

A useful workflow is: put the VM into the intended state, create a local export, verify the result, make the VM available again and copy the completed export to separate backup storage. The local staging area keeps the actual export operation independent from the network copy.

Why a local staging area helps

Writing an export directly to a network share may look attractive, but a local staging directory reduces dependencies during the Hyper-V export. Once the export succeeds, the completed structure can be copied to a NAS, file server or another backup target.

Example: manual PowerShell export

On a modern Hyper-V host, a native command is enough: `Export-VM -Name "SERVER01" -Path "D:\HyperV-Export\SERVER01"`. Test the manual export first and also test an import.

Example: classic script via powershell.exe

A common Task Scheduler pattern is `powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Tools\HyperV-Backup.ps1" -VM "SERVER01" -ExportPath "D:\HyperV-Exports"`. Check the script's actual supported parameters with `-?` or `-Help` before using it.

Why -File matters

When `powershell.exe` is started by Task Scheduler, explicitly specifying the script with `-File` makes the invocation clear and predictable. Quote paths and parameters containing spaces.

Task Scheduler: the crucial part

In Task Scheduler, use `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` as the program. Put `-NoProfile`, the required execution policy if applicable, `-File` and the complete script invocation in the arguments. The task needs an account with the required Hyper-V and storage permissions.

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile -File "C:\Tools\HyperV-Backup.ps1" -VM "SERVER01" -ExportPath "D:\HyperV-Exports"

Run with highest privileges and without interactive login

For unattended backups, `Run whether user is logged on or not` and `Run with highest privileges` are typically relevant. The account must also have access to the Hyper-V host resources and, for network backups, the SMB share.

Network shares: the classic trap

A backup can work interactively and fail as a scheduled task because of the account or SMB permissions. Mapped drives such as `Z:` are also problematic for unattended jobs. A UNC path such as `\\BackupServer\HyperV$` is much more reliable.

Shut down the VM or export it while running?

The historical script and modern Hyper-V have different approaches. Older scripts commonly use shutdown or saved state. Current `Export-VM` also exposes `-CaptureLiveState`, including `CaptureSavedState`, `CaptureDataConsistentState` and `CaptureCrashConsistentState`. Choose deliberately based on the workload and recovery requirements.

A backup is not just an export

An export is a useful additional copy, but not a complete backup strategy. Without multiple generations, separate storage and ideally an offsite copy, a disk failure, ransomware incident or operator error can destroy both production data and backup data.

Retention and generations

Do not simply overwrite the same export every day and keep one copy. Timestamped export directories or a defined number of generations are better. A cleanup job can remove exports after a retention period.

Do not underestimate storage requirements

A VM export can be large because virtual disks are exported. Calculate storage for several generations, especially when multiple large VHDX files are involved.

Restore testing: the part many people forget

A backup only has value if it can be restored. Regularly import an export on a test host or suitable test environment and start the VM. An export completing successfully does not prove that the application will recover correctly.

Practical restore test

A simple test is: select an export, use `Import-VM`, generate a new VM ID where appropriate, start the VM, check services and test the application. Databases, domain controllers, Exchange and other stateful services need application-level validation.

Logging and failure detection

A scheduled task should not fail silently. PowerShell can write logs and Task Scheduler records task status. Production environments should also consider notifications on failure or monitoring of the backup destination.

My preferred layout for small Hyper-V environments

For a small environment, I would create the export locally on the Hyper-V host, copy it to separate storage, keep several generations and test restores regularly. It is transparent and requires no additional backup licence.

Example: a daily backup

Assume a VM called `FILESERVER01`, local staging at `D:\HyperV-Exports` and a backup server exposing `\\BACKUP01\HyperV$`. A scheduled task runs at night, creates the local export, waits for completion, starts the VM again if required and copies the finished export to the backup server. A cleanup job can then remove old generations.

VM: FILESERVER01
Local staging: D:\HyperV-Exports
Remote backup: \\BACKUP01\HyperV$
Schedule: nightly
Retention: multiple generations

Important note about old scripts

The widely copied `HyperV-Backup.ps1` script comes from a much older Hyper-V/PowerShell generation and was originally documented with an external PSHyperV library. Modern Windows Server versions provide the native Hyper-V PowerShell module. Do not copy an old script to a current server without review. The concept remains useful, but the implementation should match the installed Windows and Hyper-V version.

Why the approach is still interesting

The concept is attractive precisely because it is simple: Hyper-V exports the VM, PowerShell automates the process and Task Scheduler provides the schedule. There is no per-VM agent and no additional backup licence. For many small environments, this is a powerful additional backup layer.

Conclusion

Automated Hyper-V exports are not a universal replacement for professional backup platforms. As a free, transparent and Windows-native additional backup layer, however, they are extremely useful. Automate the export, keep multiple generations on separate storage and test restores regularly.

Important: A VM export is an additional backup layer, not a complete backup strategy. Restore testing and separate backup storage are essential.
Important distinction: The historical HyperV-Backup script from 2010/2011 is not identical to the download above. The original used the PSHyperV library of that era; the download is a modern native implementation using the current Hyper-V PowerShell module.
About Sille-Solutions