Public/Backup-VM.ps1

function Backup-VM {
    <#
    .SYNOPSIS
    Perform a backup of Hyper-V Virtual Machines.

    .DESCRIPTION
    Perform a backup of Hyper-V Virtual Machines. This module exports Virtual Machines and compress them using 7zip.

    .PARAMETER Name
    Name of the Virtual Machine. You can get a list of your Hyper-V machines using Get-VM.

    .PARAMETER BackupDestination
    Specify the location of the backup.

    .PARAMETER Compress
    Specify if you want to compress the backup into a .7z file.

    .PARAMETER Retention
    Configure how long you want to keep the backups.

    .PARAMETER Force
    The Force parameter allows the user to skip the "Should Continue" box.

    .EXAMPLE
    Backup-VM -Name "GAME-01", "VPN-01" -BackupDestination 'D:\Backup\Hyper-V' -Retention 30

    .EXAMPLE
    Get-VM | Backup-VM

    Backups all VMs on the Hyper-V host.

    .NOTES
    Cmdlet must be executed from an elevated prompt.

    #>


    [CmdletBinding(SupportsShouldProcess = $true,
        ConfirmImpact = 'Medium')]
    param
    (
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = 'Enter one or more Hyper-V virtual machine names seperated by commas.'
        )]
        [string[]]$Name,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Enter the backup destination.'
        )]
        [string]$BackupDestination,

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

        [Parameter(Mandatory = $false)]
        [int]$Retention = 30,

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

    process {
        $BackupSCMessage = @"
Do you want to backup the following Hyper-V machine:
    $($Name)
"@

        if ($Force -or $PSCmdlet.ShouldContinue($BackupSCMessage, 'Backup Virtual Machine?')) {
            Write-Verbose -Message "Virtual machine to backup: $($Name)."
            Write-Verbose -Message "Backup destination: $($BackupDestination)."
            Write-Verbose -Message "Days to keep backup: $($Retention)."
            $TimeStamp = Get-Date -Format "yyyy-MM-dd-HHmm"

            # Exporting the VM.
            Export-VM -Name $Name -Path "$($BackupDestination)\$($Name)-$($TimeStamp)"

            if ($Compress) {
                # Compress the exported VM using 7Zip4PowerShell if the parameter is set.
                Compress-7Zip -Path "$($BackupDestination)\$($Name)-$($TimeStamp)" -ArchiveFileName "$($BackupDestination)\$($Name)-$($TimeStamp).7z"

                # Remove the exported folder as it's now compressed.
                Remove-Item -Path "$($BackupDestination)\$($Name)-$($TimeStamp)" -Force -Recurse
            }
        } # ShouldContinue
    } # Process

    end {
        $OldBackups = Get-ChildItem -Path $BackupDestination -Recurse -Force | Where-Object -FilterScript { -not $_.PSIsContainer -and (((Get-Date)-$_.LastWriteTime) -gt (New-TimeSpan -Day $Retention)) }
        $RemoveOldSCMessage = @"
Do you want to remove any backups older than $($Retention) days?
"@

        if ($null -ne $OldBackups) {
            if ($Force -or $PSCmdlet.ShouldContinue($RemoveOldSCMessage, 'Remove old backups?')) {
                $OldBackups | Remove-Item -Force
            }
        }
    } # End
} # Cmdlet