Just lately I've been doing a lot of work in a Lab environment. Some of the work I'm doing is quite important to me so I decided to workout a way I can backup my VM's onto a backup device. To my surprise this was pretty simple to do.
Here is how I decided the script should function:
So that's what I wanted to do, this is what I ended up with.
Backup Script
# Import Backup CSV $backupinfo = Import-Csv C:\scripts\mybackups.csv #Set Date format for clone names $date = Get-Date -Format "yyyyMMdd" #Set Date format for emails $time = (Get-Date -f "HH:MM") #Connect to vCenter Connect-VIServer "<vc server>" foreach ($customer in $backupinfo) { $vm = Get-VM $customer.MasterVM #Send Start Email C:\scripts\backupstartedemail.ps1 # Create new snapshot for clone $cloneSnap = $vm | New-Snapshot -Name "Clone Snapshot" # Get managed object view $vmView = $vm | Get-View # Get folder managed object reference $cloneFolder = $vmView.parent # Build clone specification $cloneSpec = new-object Vmware.Vim.VirtualMachineCloneSpec $cloneSpec.Snapshot = $vmView.Snapshot.CurrentSnapshot # Make linked disk specification $cloneSpec.Location = new-object Vmware.Vim.VirtualMachineRelocateSpec $cloneSpec.Location.Datastore = (Get-Datastore -Name $customer.BackupDS | Get-View).MoRef $cloneSpec.Location.Transform = [Vmware.Vim.VirtualMachineRelocateTransformation]::sparse $cloneName = "$vm-$date" # Create clone $vmView.CloneVM( $cloneFolder, $cloneName, $cloneSpec ) # Write newly created VM to stdout as confirmation Get-VM $cloneName # Remove Snapshot created for clone Get-Snapshot -VM (Get-VM -Name $customer.MasterVM) -Name $cloneSnap | Remove-Snapshot -confirm:$False #Send Complete Email C:\scripts\backupcompletedemail.ps1 } #Disconnect from vCentre Disconnect-VIServer -Confirm:$false
Send Started Email Script
#Set Date format for emails $timestart = (Get-Date -f "HH:MM") $emailFrom = "<senders address>" $emailTo = "<recipients address>" $subject = "[$vm - Backup Started]" $body = "Backup Details ------------- VM Name:",$vm," Clone Name:","$vm-$date"," Target Datastore:", $customer.BackupDS," Time Started:", $timestart $smtpServer = "<smtp server>" $smtp = new-object Net.Mail.SmtpClient($smtpServer) $smtp.Send($emailFrom,$emailTo,$subject,$body)
Send Completed Email Script
#Set Date format for emails $timecomplete = (Get-Date -f "HH:MM") $emailFrom = "<senders address>" $emailTo = "<recipients address>" $subject = "[$vm - Backup Complete]" $body = "Backup Details ------------- VM Name:",$vm," Clone Name:","$vm-$date"," Target Datastore:", $customer.BackupDS," Time Started:", $timestart," Time Completed:", $timecomplete $smtpServer = "<smtp server>" $smtp = new-object Net.Mail.SmtpClient($smtpServer) $smtp.Send($emailFrom,$emailTo,$subject,$body)
Content of CSV
The content of the csv file is very simple. This is what mine looks like:
MasterVM,BackupDS
VM1,BackupDataStore
VM2,BackupDataStore
Summary
So as you can see, it's simple, but very effective. Let me know your thoughts/Idea's on this could be improved.
Sources:
Another VMworld is upon us!!! Sadly, it's only virtual again this year. However, that does…
As part of my recent move to Google, I'm working on quickly getting up to…
I am delighted to announce the next chapter in my career. Today is my first…
In episode thirteen of The VCDX Podcast, I am joined by two special guests who…
In my recent ‘Getting started with Oracle Cloud VMware Solution (OVCS)’ post; Getting Started With…
In my recent ‘Getting started with Oracle Cloud VMware Solution (OVCS)’ post; Getting Started With…
View Comments
As simple as smart !
I am trying this out and get the error below. Any ideas what I may be doing wrong?
Exception calling "CloneVM" with "3" argument(s): "A specified parameter was no
t correct.
host"
At C:scriptsbackup.ps1:41 char:17
+ $vmView.CloneVM <<<< ( $cloneFolder, $cloneName, $cloneSpec )
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Hi Mark, contact me via the contact page and I'll help you through it. It'll save clogging this thread up.
Simon
I am a novice in scripting , Please help me .
1- Could you please what is the csv file format ?
2-How can I execute this script ?
Many thanks
Hi Simon,
first.thanks for the great idea behind your script.
I get the error mentioned by MarkZi in one of the environments I try to use the script.
In this case I want to clone the machine from local datastore to the local datastore on another server. For that I added
"$CloneSpec.Location.Host = ( get-vmhost -Name $Machine.BackupHost | get-view).MoRef" to the script.
The datastore exists and the value of $CloneSpec.Location.Datastore looks fine.
Can I find out where the error is more exactly?
Hello Simon,
Do you have other ideas or a workaround? I even tried setting $cloneSpec.Location.Datastore with MoRef of the datastore I gathered manually and still getting the above error.
Thank you,
Alex
Morning Alex, can you email me via the contact me page. Paste the error you are getting.
Cheers
Did not expect it! (Abercrombie & Fitch) so kind of young, dynamic, innovative, works ahead of its time, much as a hundred years of history, not only that, the past few years, more is high style, high quality and super clean style, all over the United States and Canada, continue to spread open to, create a new index the new global fashion.
Hi Simon,
Thanks a lot for this script, it is working like a charm. However, it seems to clone the backup-vm in thin format, Now I can surely see the value in that, but I would like to make my back-up thick. Can you tell me how I can manage that?
regards,
Ronald
Ronald, my apologies for the delay in getting back to you.
Change the word "sparse" to "flat" on line 36. That should make them Thick format.
Regards
Simon
Very nice script, but how can i make an restore?
PowerOff the original, PowerOn the backed up Virtual Machine?
Yeah, but i think the script makes 2gb spare files on the backup DS?
$cloneSpec.Location.Transform = [Vmware.Vim.VirtualMachineRelocateTransformation]::sparse
Have you tried it? Is that what's happening for you?
If you can help me understand this, I'd be grateful.
1. Why snapshot and then clone? Doesn't cloning involve a snapshot anyways?
2. Why the ".MasterVM" in your statement in line 15? (Get-VM $customer.MasterVM)
I presume that this is related to the format of the input CSV, that the first line of the CSV labels the type in each successive line. It's just not obvious to me what mechanism is that accomodates this.
Thanks,
Marge
Hi Marge, thanks for the questions.
1. Good question. Cloning does indeed take a snapshot. Maybe it's worth trying to see if it works.
2. .MasterVM refers to the column in the CSV. $customer is a line of that CSV
Why this error?
Method invocation failed because [System.Object[]] doesn't contain a method named 'CloneVM'.
At C:Scriptsbackup.ps1:41 char:17
+ $vmView.CloneVM <<<< ( $cloneFolder, $cloneName, $cloneSpec )
+ CategoryInfo : InvalidOperation: (CloneVM:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Using PowerCLI 4.1 build 264274
Host are ESX 4.0.0, 294855
I am trying to test out this script. I have a host that I set up with similar info that you have in your test. I keep getting errors. It does seem to create the snapshot but everything else seems to fail. The mail feature also works. Here are my errors:
Get-VM : Cannot validate argument on parameter 'Name'. The argument is null or empty. Supply an argument that is not nu
ll or empty and then try the command again.
At C:scriptsorig_backupScript.ps1:15 char:17
+ $vm = Get-VM <<<< $customer.MasterVM
+ CategoryInfo : InvalidData: (:) [Get-VM], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM
Get-Datastore : Cannot validate argument on parameter 'Name'. The argument is null or empty. Supply an argument that is
not null or empty and then try the command again.
At C:scriptsorig_backupScript.ps1:35 char:57
+ $cloneSpec.Location.Datastore = (Get-Datastore -Name <<<< $BackupDS | Get-View).MoRef
+ CategoryInfo : InvalidData: (:) [Get-Datastore], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetDatasto
re
Exception calling "CloneVM" with "3" argument(s): "The operation is not supported on the object."
At C:scriptsorig_backupScript.ps1:41 char:20
+ $vmView.CloneVM <<<< ( $cloneFolder, $cloneName, $cloneSpec )
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Get-VM : 4/28/2011 8:09:19 AM Get-VM VM with name 'MasterVM-20110428' was not found, using the specified filt
er(s).
At C:scriptsorig_backupScript.ps1:44 char:11
+ Get-VM <<<< $cloneName
+ CategoryInfo : ObjectNotFound: (:) [Get-VM], VimException
+ FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM
Get-VM : Cannot validate argument on parameter 'Name'. The argument is null or empty. Supply an argument that is not nu
ll or empty and then try the command again.
At C:scriptsorig_backupScript.ps1:47 char:35
+ Get-Snapshot -VM (Get-VM -Name <<<< $customerMasterVM) -Name $cloneSnap | Remove-Snapshot -confirm:$False
+ CategoryInfo : InvalidData: (:) [Get-VM], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM
I have been using a copy of this script for over a year and it has been working great as a poor man's backup solution. I backup over 27TB of data in less than 24 hours!
I was going to write a cleanup script to prune some of my older backups, but I was wondering if I could use something like the -force option when invoking clonevm so that the older files are overwritten in stead of appending with an underscore and a number.
Any ideas on how to overwirte old files using this process?
-Mark
That is excellent, thanks Simon! I can confirm that it works fine leaving the snapshot to be taken by the clone operation itself, as suggested in your earlier reply to Marge.
Thanks for that Nigel, glad to see it still working with v5. :-)