PowerCLI: A Simple VM Backup Script

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:

  1. Send myself an email telling me that the backup process has started
  2. Import the name of the VM to be backed up and the destination datastore from a CSV file
  3. Create a Snapshot of the VM I want to backup
  4. Create a Clone'd VM from the Snapshot
    • Place the backup onto my Backup Datastore
    • Name the backup <master VM name>-<date stamp>
    • Thin provision the backup
  5. Remove the Snapshot from the master VM
  6. Send myself an email telling me that the backup process has completed

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:

Related posts:

  1. Saving Event Logs Using PoSH – My First Ever Script!
  2. PowerCLI: Reconfiguring NTP Servers on ESX Hosts
  3. A Simple VMware ESXi Rapid Deployment System – Part 3 of 3
  4. A Simple VMware ESXi Rapid Deployment System – Part 1 of 3
  5. A Simple VMware ESXi Rapid Deployment System – Part 2 of 3
  • http://twitter.com/hyperviz0r raphael schitz

    As simple as smart !

  • MarkZi

    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

  • http://www.simonlong.co.uk Simon Long

    Hi Mark, contact me via the contact page and I'll help you through it. It'll save clogging this thread up.

    Simon

  • http://profiles.yahoo.com/u/6CHMOSGYTAYOMTJV6GEVVSJECQ Jerry Xie

    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.

  • Ronald

    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

  • http://www.simonlong.co.uk Simon Long

    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

  • diegp

    Very nice script, but how can i make an restore?

  • http://www.simonlong.co.uk Simon Long

    PowerOff the original, PowerOn the backed up Virtual Machine?

  • diegp

    Yeah, but i think the script makes 2gb spare files on the backup DS?

    $cloneSpec.Location.Transform = [Vmware.Vim.VirtualMachineRelocateTransformation]::sparse

  • http://www.simonlong.co.uk Simon Long

    Have you tried it? Is that what's happening for you?

  • Marge

    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

  • http://www.simonlong.co.uk Simon Long

    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

  • WB

    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

  • Sabaghzadeh

    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

  • http://twitter.com/cherzyk Christian Herzyk

    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?

  • Sean Crosby

    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

  • Mzigadlo

    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 

Get Adobe Flash playerPlugin by wpburn.com wordpress themes