VMware
4 Replies Last post: Nov 15, 2006 9:00 AM by saxa  

The ultimate VBScript for VM backup on Windows hosts (VMWare Server) posted: Oct 11, 2007 11:44 PM

Click to view saxa's profile Master 1,338 posts since
Jun 2, 2006
I made my dream to reality: I written a script which makes backup of virtual machine by shutting down, copying and compressing of .vmx and .vmdk files.

Please read the long comment at the beginning of the code to understand what it does and how it works.

Sorry for bad formatting :)

[code]

' Please save this as vm-backup.vbs
'
' Copyleft saxa, 2006
'
' Written for fun and for functionality; total Open Source.
' Tips and suggestions are welcome.
' Use it at your own risk.
'
' The script uses the VmCOM API for the virtual machine operations.
'
' The virtual machine *must* have the VMware Tools installed, in order to perform the
' shutdown and heartbeat operations correctly.
'
' DON'T APPLY THIS SCRIPT ON RUNNING VIRTUAL MACHINES WHICH DON'T HAVE THE VMWARE TOOLS INSTALLED.
'
' It works on Windows 2000 SP4 and newer; it doens't use the NTBackup utility.
'
' The script runs on the local host only; it cannot be used to connect to a remote VMware Server.
' The script *can* backup to the network share, if you have the appropriate permissions to do it.
'
' For the backup jobs it uses the command line version of 7zip: get it on http://7zip.org/download.html.
' You need the "7-Zip Command Line Version". Unfortunately there is only 32 bit version available now.
'
' We assume that the 7zip executable is included in your %PATH% variable.
' Most probably you already have a folder with your tools, where you will also save this script.
' We have on each of our servers the folder C:\Program files\myTools created and it is added to %PATH%.
'
' Please see Windows Help on how to add a folder to %PATH%.
'
' Here I go again (c) ;))
'
' To use the command line version of this script (non-interactive mode):
' We assuming that all of our .vmx files are named vm.vmx.
' The name itself doesn't matter, but it must be the same for every virtual machine.
' If you don't like vm.vmx, please change the following variable correspondingly.

vmfile = "vm.vmx"

' We also assume that all of your virtual machines are located in the appropriate subdirectories
' of *one* directory; in other words, we need a flat structure.
' See the variable "vmpath" and change it to your needs.
' Here is a sample of correct directory layout:
'
' D:\Virtual Machines\
' Virtual Machine 1\
' vm.vmx
' hdd1.vmdk
' hdd1-flat.vmdk
' hdd2.vmdk
' hdd2-flat.vmdk
' other_file.ext
' Virtual Machine 2\
' vm.vmx
' disks\
' some weird disk 1.vmdk
' some weird diskette.flp
'
' As you can see, subdirectories are also allowed. It's only important that your .vmx file is placed
' on the (in this sample) second level, say, the full path to .vmx must be
' D:\Virtual Machines\Virtual Machine X\vm.vmx for every virtual machine.
'
' The subdirectory where the virtual machine is located is very important for this script:
' it's the virtual machine's identifier.
' In our sample these are "Virtual Machine 1" and "Virtual Machine 2" respectively.
'
' You will start the script as follows:
'
' vm-backup "Virtual Machine 1"
'
' or
'
' vm-backup "Virtual Machine 2"
'
' to backup the Virtual Machine 1 or Virtual Machine 2.
'
' The script does the following:
'
' The virtual machine gets the command to shut down it's operating system.
' The script waits 60 seconds and than checks the state of the virtual machine.
' If the vm still runs, the script waits 60 seconds more and so on.
' As soon as the vm is off, the script copies the vm's folder into the backup location
' (see the "bkpath" variable and change it if you would like to; UNC-Paths are accepted).
'
' If the vm couldn't be shut down, the mail is sent to the admin,
' the error is written in the Windows application log.
'
' After the copying is done, the vm receives the command to start, if if was running before the operation has begun.
' 30 seconds later, and then every 30 seconds, the script checks the heatbeat of the vm.
' As soon as the vm at 300 or more units of heartbeat, the script starts to create
' a compressed archive from a previously copied vm directory.
' At that point of time is the vm already up and running.
' A .zip archive receives the following name: YYYY-MM-DD-HHMMSS-Virtual Machine 1.zip
' The creation of the .zip file takes it's time: on Pentium 4 (with Hyperthreading, single core)
' 2.8 GHz machine with 3 GB RAM is the duration of compress operation on a virtual machine
' having 2 virtual HDDs at 16 and 36 GB was 2 hours. Though it is worth the effort:
' the resulting file has the size of 3.6 GB: compare it to 52 GB uncompressed ;).
' So, after the .zip file is ready, the script checks if there were any errors produced by 7zip.
' If there are some, the Windows Application log is misused for the registration of them.
' If not, then we can safely delete the copy of the vm used as a source for compression and create the record
' of successful backup operation in the Application log.
'
' The interactive mode (if you start the script without any parameters) does the same.
' You can manually name your zip file.

vmpath = "D:\Virtual Machines\"

' Please don't forget the ending backslash!
' vm -> Directory where the VM files are located: the machine name is received from the argument.

' bkpath -> Destination directory; here are temporary backups created,
' and here you will find your .zip files.
' The user who runs the script must have the write permissions on directory / network share.

bkpath = "E:\backups\"

' In the variable seven_zip_switch you can provide the additional switches for the command line of 7zip.
' The most thinkfully switch is " -v4g" (don't forget the leading space!). It causes the splitting of your
' archive into volumes at 4 GB. Please read the 7zip's manual about the -v switch.

seven_zip_switch = ""

adminmail = "admin@domain.tld" 'Here you'll receive mail messages.

smtp = "smtp.domain.tld" 'Your SMTP server must be able to relay the mails for you.


On Error Resume Next

' Common definitions...

Set wshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set cp = CreateObject("VmCOM.VmConnectParams")
Set server = CreateObject("VmCOM.VmServerCtl")
Set thevm = CreateObject("VmCOM.VmCtl")
Set fso = CreateObject("Scripting.FileSystemObject")
Set wshNet = CreateObject("WScript.Network")
Set mailing = CreateObject("CDO.Message")

mailing.From = lcase(wshNet.UserName & "@" & wshNet.ComputerName & "." & wshNet.UserDomain)
mailing.To = adminmail
mailing.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
mailing.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = smtp
mailing.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

header = "Backup Script for VMware Virtual Machines" 'Just the title for message boxes...

Function iso_date(byval dt)

' The function does nothing interesting...

dim y: y=year(dt)
dim m: m=month(dt)
dim d: d=day(dt)
dim h: h=hour(dt)
dim n: n=minute(dt)
dim s: s=second(dt)

if m < 10 then m="0" & m
if d < 10 then d="0" & d
if h < 10 then h="0" & h
if n < 10 then n="0" & m
if s < 10 then s="0" & s

iso_date = y & "-" & m & "-" & d & "-" & h & n & s

end Function

' Here we are getting the name of the VM delivered by the script argument; it must be only one. Or, no one.

Set args = WScript.Arguments

If args.Count=1 Then 'We are in the mode with predefined vm by parameter, way = "a(utomatic)"
vm = args(0)
vmfolder = vmpath & vm
vmfile = vmfolder & "\" & vmfile

zipfile = bkpath & vm & "-" & iso_date(now) & ".zip"

tmpfolder = bkpath & vm

way = "a"

ElseIf args.Count=0 Then 'We are in the interactive mode, way = "i(nteractive)"

vmfile = inputBox("Please enter the full path to the .vmx file of the virtual machine you want to backup:",header,vmpath)

vmfolder = fso.GetParentFolderName(vmfile)

vmparent = fso.GetParentFolderName(vmfolder)

vm = Replace(Replace(vmfolder, vmparent, ""),"\","")

bkfile = bkpath & vm & "-" & iso_date(now) & ".zip"

zipfile = inputBox("Now, please enter the full path to the .zip file the script will create:",header,bkfile)

tmpfolder = fso.GetParentFolderName(zipfile) & "\" & vm

way = "i"

Else

' There is more than one argument provided: write the error message into the application log and bye.
' There is no message box / email here.

errNoVMfile = "Incorrect Input." & VbCrLf & "The directory where the Virtual Machine files" & VbCrLf & "are resided must be provided as argument." & VbCrLf & "If the directory name contains spaces," & VbCrLf & "please add the " & Chr(34) & " sign at the beginning" & VbCrLf & "and at the end of the Virtual Machine's name." & VbCrLf & "The reading of the source code" & VbCrLf & "of the vm-backup.vbs script may help ;)"

wshShell.LogEvent 1, errNoVMfile

WScript.Quit

End If

' Try to connect to server 10 times

connected = False
For tries_srv = 1 To 10
server.Connect cp
If Err.number = 0 Then
connected = True
Exit For
End If
WScript.Sleep 10000
Err.clear
Next

If Not connected Then

'Connection to server couldn't be established; we write something into the application log or/and send a message...

errNoConnectSRV = "The Backup Script for VMware Server couldn't create an appropriate connection." & VbCrLf & "Please check if all of the VMWare Services are up and running." & VbCrLf & "Please keep in mind, you can run this script on the local host only."

wshShell.LogEvent 1, errNoConnectSRV

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errNoConnectSRV
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
crySRV = msgBox(errNoConnectSRV,vbCritical,header)
end if

WScript.Quit

End If


' Connect to the virtual machine. You remember, what the "vmfile" is?

' Try to connect to vm 10 times

connected_m = False
For tries_vm = 1 To 10
thevm.Connect cp, vmfile
If Err.number = 0 Then
connected_m = True
Exit For
End If
WScript.Sleep 1000
Err.clear
Next

If Not connected_m Then

'Connection to vm couldn't be established; we write something into the application log or/and send a message...

errNoConnectVM = "The Backup Script for VMware Server couldn't connect to the virtual machine " & vmfile & "." & VbCrLf & "Please check if the path to .vmx file correct is and if the virtual machine is registered on your server." & VbCrLf & "Please keep in mind, you can run this script on the local host only."

wshShell.LogEvent 1, errNoConnectVM

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errNoConnectVM
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryVM = msgBox(errNoConnectVM,vbCritical,header)
end if

WScript.Quit

End If

' Enough with checking :)
' Get the ExecutionState of the vm to know if it must be started after backup complete

' Const vmExecutionState_Off = 2
' Const vmExecutionState_On = 1
' Const vmExecutionState_Stuck = 4
' Const vmExecutionState_Suspended = 3
' Const vmExecutionState_Unknown = 5

' now we need only 2 states

ps = thevm.ExecutionState

if ps = 1 then

was_on = true ' It must be powered on after backup

elseIf ps = 2 then

was_on = false ' After backup do nothing

else

' If vm stucks, suspended or in unknown state... Who needs such backups? We create some errors.

errState = "The Backup Script for VMware Server couldn't get the correct state of the virtual machine " & vmfile & "." & VbCrLf & "Correct states are on and off only." & VbCrLf & "A vm with pending question, such as new SID after copying or moving, cannot be backed up, too."

wshShell.LogEvent 1, errState

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errState
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryVM = msgBox(errState,vbCritical,header)
end if

WScript.Quit

end If

' Heartbeat. It's the approximate number of seconds from the start of VMWare Tools inside the vm.

hb = thevm.Heartbeat

if was_on = true then

if hb < 1 then ' VMWare Tools not installed or cannnot be contacted...

' VM without VMWare Tools can only be backed up if it was off...

errTools = "The Backup Script for VMware Server couldn't contact the VMWare Tools on the virtual machine " & vmfile & "." & VbCrLf & "Therefore it cannot be shut down correctly." & VbCrLf & "Please shut down the vm manually. Afterwards it can be backed up."

wshShell.LogEvent 1, errTools

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errTools
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryTools = msgBox(errTools,vbCritical,header)
end if

WScript.Quit

end if

end if

' start/stop
' Const vmPowerOpMode_Hard = 1
' Const vmPowerOpMode_Soft = 2
' Const vmPowerOpMode_TrySoft = 3

' Now stopping...

getoff = thevm.stop(2)

isoff = False

For tries_off = 1 To 10
ps = thevm.ExecutionState
If ps = 2 Then
isoff = True
Exit For
End If
WScript.Sleep 60 * 1000
ps = 0

Next

If Not isoff Then

'The vm couldn't be shut down: very critical...

errNoShutDown = "The Backup Script for VMware Server couldn't shut down the virtual machine " & vmfile & "." & VbCrLf & " in a reasonable time." & VbCrLf & "Please check it's state."

wshShell.LogEvent 1, errNoShutDown

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errNoShutDown
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryNoShutDown = msgBox(errNoShutDown,vbCritical,header)
end if

WScript.Quit

end if

' Machine is shut down and can be copied

copyVM = fso.CopyFolder(vmfolder,tmpfolder) 'checked

' Machine copied!

if was_on = true then 'Power on the vm if it was on

geton = thevm.start(2)

' Wait until the heartbeat becomes more than 300

ison = False

For tries_on = 1 To 20
hbs = thevm.Heartbeat
If hbs > 300 Then
ison = True
Exit For
End If
WScript.Sleep 30 * 1000
hbs = 0

Next

If Not ison Then

'The vm couldn't be start up: very critical...

errNoStart = "The Backup Script for VMware Server couldn't power on the virtual machine " & vmfile & "." & VbCrLf & " in a reasonable time. Maybe the machine could not start the VMWare Tools." & VbCrLf & "Please check it's state and / oder configuration."

wshShell.LogEvent 1, errNoStart

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errNoStart
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryNoStart = msgBox(errNoStart,vbCritical,header)
end if

WScript.Quit

end if

end if

' Now the vm is up and running. It is copied and ready to be compressed

backup_string = "7za a -tzip " & chr(34) & zipfile & chr(34) & " " & chr(34) & tmpfolder & "\*" & chr(34) & seven_zip_switch

' Now create the archive...

backup_vm = wshshell.Run(backup_string,0,true)

if backup_vm > 0 then

' The zip file wasn't created

errNozip = "The Backup Script for VMware Server couldn't create a zip file." & VbCrLf & "Please check if you have enough disk space on " & tmpfolder & " and run / shedule the backup script again."

wshShell.LogEvent 1, errNozip

mailing.Subject = header & ": Critical Error"
mailing.TextBody = errNozip
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryNoZip = msgBox(errNozip,vbCritical,header)
end if

WScript.Quit

end if

' Now delete the temporary backup folder...

deltmp = fso.deleteFolder(tmpfolder) 'should be ok

' And send some messages.

success_message = "The Backup Script for VMware Server backed up the virtual machine " & vmfile & " successfully." & VbCrLf & "Backup is saved as " & zipfile & "."

wshShell.LogEvent 0, success_message

mailing.Subject = header & ": Operation Successfully Completed"
mailing.TextBody = success_message
mailing.Configuration.Fields.Update
mailing.Send

if way = "i" Then
cryS = msgBox(success_message,vbExclamation,header)
end if

WScript.Quit
[/code]

Comments are appreciated.

Message was edited by: oreeh

Modified the adminmail and smtp variables by request from saxa

Oliver
VMTN User Moderator

Click to view Heffel's profile Lurker 1 posts since
Nov 1, 2006
This is the greatest thing ever! Thanks SAXA! Are you still updating one of these? Which of the 2 pages will contain the later version? Maybe you need a version number at the top!

You are my hero.....

VMware Developer

SDKs, APIs, Videos, Learn and much more in the Developer community.

Learn More

Developer Sample Code

Increase your developer productivity with VMware API sample code.

Learn More

VMworld Sessions & Labs

Online access to the latest VMworld Sessions & Labs and online services.

Learn more

Purchase PSO Credits Online

Purchase credits to redeem training and consulting services online.

Buy Now

Community Hardware Software

View reported configurations or report your own.

Learn More

VMware vSphere

Come witness the next giant leap in virtualization.

Register Today

Communities