Backing up Workstation VMs with PowerShell
It’s pretty common for me to backup my Workstation VMs and I’m always looking for quick way to accomplish this. I’ve been using SyncBack Free for many years but most recently I’ve out grown. In this blog I’ll show you the script I wrote to backup my VM’s to a target location.
My Workstation server has many data disks with many folders for my VM’s. I backup my VM’s to a large hard disk and then regularly I’ll off load these backups to a NAS for archive purposes. This keeps the VM’s local for quick restores and the NAS provides some further protection.

My PowerShell 7 script is rather simple.
- Define my sources
- Choose a target folder
- Asks if you want to simulate a backup
- Robocopy copies or simulates a copy of the files while appending to a logfile
- Appends the folders and log file with a date stamp
It’s a pretty simple process but it works quite well.
Write-Output "`n**** Workstation VM Backups for VCF 9 vSAN ESA 3 Node *****`n"
# Define Sources
$source1 = "d:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source2 = "f:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source3 = "g:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source4 = "h:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source5 = "i:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source6 = "j:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source7 = "k:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source8 = "l:\Virtual Machines\VCF 9 vSAN ESA 3 Node"
$source8 = "D:\Virtual Machines\Domain Services\DomainToolsVM - 12 05 2025"
# Function user selected destination folder
function Select-FolderDialog {
param([string]$Description="Select a EMPTY folder",
[string]$RootFolder="MyComputer")
# Load the necessary assembly
Add-Type -AssemblyName System.Windows.Forms
# Create an instance of the FolderBrowserDialog object
$objForm = New-Object System.Windows.Forms.FolderBrowserDialog
$objForm.RootFolder = $RootFolder
$objForm.Description = $Description
# Show the dialog box
$Show = $objForm.ShowDialog()
# Check if the user clicked 'OK' and return the selected path
if ($Show -eq "OK") {
return $objForm.SelectedPath
} else {
Write-Error "****Operation cancelled by user****"
pause
exit 1
}
# Clean up the object
$objForm.Dispose()
}
Write-Output "`n***** Choose Destination Folder *****"
# Prompt User for desintation folder
$selectedFolderPath = Select-FolderDialog -Description "Please choose the destination folder"
if ($selectedFolderPath) {
Write-Host "You selected: $selectedFolderPath"
# You can now use $selectedFolderPath in the rest of your script
}
Write-output "`n****Choose Robo options****"
# Robocopy options
# /log+ createa a log file
# /tee Writes the status output to the console window, and to the log file.
# /L Simulate backup
# /ZB Restart Mode, if denied back to backup mode
# /R:# Retires
# /W:# Wait time between retires
# /J Unbuffered IO for faster large file backups
# https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy
#To simulate backup or not
$question = "Do you want run a simulated backup? (Y/N)"
do {
$response = Read-Host -Prompt $question
# Use ToLower() for case-insensitive comparison
$response = $response.ToLower()
} until ($response -eq 'y' -or $response -eq 'n')
if ($response -eq 'y') {
Write-Host "Continuing... with Simulated Robocopy backup`n"
$robocopyoptions = "/E /TEE /ZB /R:2 /W:10 /J /L"
} else {
Write-Host "Continuing.... with Robocopy backup`n"
$robocopyoptions = "/E /TEE /ZB /R:2 /W:10 /J"
}
Write-Output "`n****Robocopy START****"
#Define Log loction
$logfile = $selectedFolderPath + "\WorkstationBackupLog.txt"
# Start Robocopy and append to log file
robocopy $source1 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source2 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source3 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source4 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source5 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source6 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source7 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source8 $selectedFolderPath $robocopyoptions /LOG+:$logfile
robocopy $source9 $selectedFolderPath $robocopyoptions /LOG+:$logfile
Write-Output "****Robocopy FINISH****"
Write-Output "`n****Rename Files START****"
#Rename Folders/file with date stamp
$DateStamp = Get-Date -Format "_yyyy-MM-dd"
Get-ChildItem -Path $selectedFolderPath -Directory | ForEach-Object {
# Construct the new name: original name + date stamp
$NewName = $_.Name + $DateStamp
# Rename the item (folder)
Rename-Item -Path $_.FullName -NewName $NewName
}
Get-ChildItem -Path $selectedFolderPath -File | Rename-Item -NewName {
$_.BaseName + $DateStamp + $_.Extension
}
Write-Output "****Rename Files FINISH****"
# Exit
Write-Output "`n`n****Script finished. Press Enter to exit.****"
pause
January 15, 2026 at 12:13 pm
[…] One of the more important steps is making sure I backup my environment and delete any VM snapshots. This way my environment is ready for […]
LikeLike
January 15, 2026 at 12:17 pm
[…] rarely run it 24/7. After its initial deployment, my first task is shutting down the environment, backing it up, and then starting it up. In this blog post I’ll document how I accomplish […]
LikeLike