-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathBackup-VirtualBox.ps1
234 lines (196 loc) · 8.87 KB
/
Backup-VirtualBox.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<#
.SYNOPSIS
This is a simple Powershell script to allow you to create backups of VirtualBox VM's using the 'Export to Appliance' command. It uses the VM name as displayed in VirtualBox Manager as the input
.DESCRIPTION
The script is using the command line interface of VirtualBox named VBoxManage to do the starting and stopping of the VM's and the creation of the exported OVA files.
It is as well required to have 7-Zip installed on the computer.
It uses 7-Zip to compress the backupped directory. The command line argument Compress-Archive is not
supported as the output files are most likely larger than 2GB. Because of a .NET limitation zip archives larger then 2GB are not supported yet because of Zip64 not being
implemented in .NET yet.
Make sure to use StartAfterBackup if you plan to stop the VM, make a backup and start the VM. This is so that you are able to make backups of machines that are offline
and should stay offline.
.EXAMPLE
Basic example to backup the VM to a folder
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Destination D:\Test\TESTVM -Verbose
.EXAMPLE
Basic example to backup the VM to a folder and use zip archiving with 7zip
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Destination D:\Test\TESTVM -Compress -Verbose
.EXAMPLE
Basic example to backup the VM to a folder and use 7z archiving with 7zip
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Destination D:\Test\TESTVM -Compress -CompressExtention "7z" -Verbose
.EXAMPLE
Basic example to backup the VM to a folder and use 7z archiving with 7zip with maximum compression 9 (this can also be 1, 3, 5 (default) or 7)
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Destination D:\Test\TESTVM -Compress -CompressExtention "7z" -CompressLevel 9 -Verbose
.EXAMPLE
Basic example to backup the VM to a folder and start the VM back up after exporting
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Destination D:\Test\TESTVM -Compress -StartAfterBackup -Verbose
.EXAMPLE
Basic example to only create a snapshot of the VM, this does not delete snapshots
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Snapshot -Verbose
.EXAMPLE
Basic example to only create a snapshot of the VM and delete snapshots that are older then 30 days
.\Backup-VirtualBox.ps1 -VM 'TESTVM' -Snapshot -Keep 30 -Verbose
.LINK
https://www.techrepublic.com/article/how-to-import-and-export-virtualbox-appliances-from-the-command-line/
https://www.virtualbox.org/manual/ch08.html
https://www.virtualbox.org/manual/ch08.html#vboxmanage-export
https://stackoverflow.com/questions/49807310/in-powershell-with-a-large-number-of-files-can-you-send-2gb-at-a-time-to-zip-fil
https://blogs.msdn.microsoft.com/oldnewthing/20180515-00/?p=98755
https://stackoverflow.com/questions/17461237/how-do-i-get-the-directory-of-the-powershell-script-i-execute
https://askubuntu.com/questions/42482/how-to-safely-shutdown-guest-os-in-virtualbox-using-command-line
https://www.dotnetperls.com/7-zip-examples
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][String]$VM,
[Parameter(ParameterSetName="FullBackup", Mandatory=$true)][String]$Destination = "C:\Users\" + $env:UserName + "\Documents\",
[Parameter(ParameterSetName="FullBackup")][String]$Suffix,
[Parameter(ParameterSetName="FullBackup")][Switch]$Compress,
[Parameter(ParameterSetName="FullBackup")][String]$CompressExtension = "zip",
[Parameter(ParameterSetName="FullBackup")][String]$CompressLevel = "5",
[Parameter(ParameterSetName="FullBackup")][Switch]$StartAfterBackup,
[Parameter(ParameterSetName="FullBackup")][switch]$Force = $False,
[Parameter(ParameterSetName="Snapshot", Mandatory=$true)][switch]$Snapshot,
[Parameter(ParameterSetName="Snapshot")][string]$Keep
)
$VBoxManage = "$($Env:ProgramFiles)\Oracle\VirtualBox\VBoxManage.exe"
$Date = Get-Date -format "yyyyMMdd-HHmmss"
$OVA = "$VM-$Date"
if ($Suffix)
{
$OVA = "$VM-$Date-$Suffix"
}
$OVAPath = Join-Path -Path $Destination -ChildPath ($OVA + $OVAExtension)
$OVAExtension = ".ova"
function New-7ZipArchive()
{
Param
(
[Parameter(Mandatory=$true)][String]$DestinationFile,
[Parameter(Mandatory=$true)][String]$SourceFile,
[Parameter(Mandatory=$true)][String]$Extention,
[Parameter(Mandatory=$true)][String]$Level
)
$7ZipLocation = "$($Env:ProgramFiles)\7-Zip\7z.exe"
$7ZipArguments = "a -t" + $Extention + ' "' + $DestinationFile + '" "' + $SourceFile + '" -mx' + $Level
Start-Process $7ZipLocation -ArgumentList $7ZipArguments -Wait -WindowStyle Hidden
}
function Get-RunningVM($VM)
{
$VBoxManage = "$($Env:ProgramFiles)\Oracle\VirtualBox\VBoxManage.exe"
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $VBoxManage
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "list runningvms"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
if ($stdout.Contains($VM))
{
return $stdout
}
}
function Get-Snapshots($VM)
{
$VBoxManage = "$($Env:ProgramFiles)\Oracle\VirtualBox\VBoxManage.exe"
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $VBoxManage
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "snapshot ""$VM"" list"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
$snapshots = $stdout | Select-String -Pattern "Name:(.*?)\(UUID" -AllMatches | Foreach-Object { $_.Matches} | ForEach-Object { $_.Groups[1].Value.Trim() }
return $snapshots
}
if ($Snapshot)
{
if (Get-RunningVM($VM))
{
Write-Verbose "Taking new snapshot of $VM, be patient can take a while"
Start-Process $VBoxManage -ArgumentList "snapshot ""$VM"" take ""$OVA"" --live" -Wait -WindowStyle Hidden
if ($Keep)
{
Write-Verbose "Checking for snapshots olders then $Keep day(s) that can be removed for $VM"
$SnapshotStorage = Get-Snapshots($VM)
if ($SnapshotStorage)
{
Foreach($Snap in $SnapshotStorage)
{
$SnapDate = [datetime]::parseexact($Snap.Split("$VM-")[1], "yyyyMMdd-HHmmss", $null)
if ((New-TimeSpan -Start $SnapDate -End (Get-Date)).Days -gt $Keep)
{
Write-Verbose "Removing old $VM snapshot $Snap"
Start-Process $VBoxManage -ArgumentList "snapshot ""$VM"" delete ""$Snap""" -Wait -WindowStyle Hidden
}
}
}
}
}
else
{
Write-Error "$VM was not running, snapshot command could not be performed"
}
Write-Verbose "Completed the snapshot"
Exit
}
if (Get-RunningVM($VM))
{
if ($Force)
{
Write-Verbose "Stopping $VM, using PowerOff method (Force)"
Start-Process $VBoxManage -ArgumentList "controlvm ""$VM"" poweroff" -Wait -WindowStyle Hidden
}
else
{
Write-Verbose "Stopping $VM, using ACPI Power Button method"
Start-Process $VBoxManage -ArgumentList "controlvm ""$VM"" acpipowerbutton" -Wait -WindowStyle Hidden
}
While(Get-RunningVM($VM))
{
Write-Verbose "Waiting for $VM to have stopped"
Start-Sleep -Seconds 1
}
}
Write-Verbose "Testing if $Destination exists, if not then create it"
if (-Not(Test-Path $Destination))
{
New-Item -Path $Destination -ItemType Directory | Out-Null
}
Write-Verbose "Checking if $OVAPath already exists and removing it before beginning"
if (Test-Path $OVAPath)
{
Remove-Item $OVAPath -Force
}
Write-Verbose "Exporting the VM appliance of $VM to $OVAPath, be patient can take a while"
Start-Process $VBoxManage -ArgumentList "export ""$VM"" -o ""$OVAPath""" -Wait -WindowStyle Hidden -RedirectStandardOutput True
if ($StartAfterBackup)
{
Write-Verbose "Starting $VM"
Start-Process $VBoxManage -ArgumentList "startvm ""$VM"" -type headless" -Wait -WindowStyle Hidden
}
if ($Compress)
{
$DestinationCompress = Join-Path $Destination -ChildPath ((Get-Item $OVAPath).BaseName + "." + $CompressExtension)
Write-Verbose "Checking if $DestinationCompress already exists and removing it before beginning"
if (Test-Path $DestinationCompress)
{
Remove-Item $DestinationCompress -Force
}
Write-Verbose "Starting the compression of $OVAPath to $DestinationCompress, be patient can take a while"
New-7ZipArchive -SourceFile $OVAPath -DestinationFile $DestinationCompress -Extention $CompressExtension -Level $CompressLevel
Write-Verbose "Removing uncompressed $OVAPath because of completed compression"
Remove-Item $OVAPath -Force
}
Write-Verbose "Completed the backup"