Please advice. I worked about 5 days on it, and it's awesome, IMHO.
Read the leading comment attentively. Save the code as vm-backup.vbs. Enjoy. Share your comments.
' Copyleft saxa aka Alexander Kaufmann, 2006
'
' Written just for fun; total Open Source.
' 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 doesn'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". Or, just download the full install - there is also a 64 bit
' version available.
'
' 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.vbs "Virtual Machine 1"
'
' or
'
' vm-backup.vbs "Virtual Machine 2"
'
' to backup the Virtual Machine 1 or Virtual Machine 2.
'
' If you want to use the script in a sheduled task, you must use the following command line:
'
' wscript.exe vm-backup.vbs "Virtual Machine 1"
'
' to backup the Virtual Machine 1.
'
' The script does the following:
'
' The virtual machine gets the command to shut down it's operating system.
' The script waits 30 seconds and than checks the state of the virtual machine.
' If the vm still runs, the script waits 30 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 it 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 about 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.
' Added on 2006-10-16; now is in Beta-Testing
' It's also possible to run a script as following (quite interesting for "scripting of this script"):
' vm-backup.vbs "X:\Full Path To vmx File\My vmx file.vmx" "Y:\Full Path To Some zip File\bla\Any name.zip"
' The script will backup the directory "X:\Full Path To vmx File\" including all subdirectories.
' Why it's Beta:
' The script will \*not* create the directory ""Y:\Full Path To Some zip File\bla\"
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 = "mail@domain.com" 'Here you'll receive mail messages.
smtp = "smtp.domain.com" 'Your SMTP server must be able to relay the mails for your mail address. IP address is also OK.
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 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 one or two.
' If there are two, it means, user want to define the VM and backup location manually.
' If there are more than two, it's an incorrect call.
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)
' Quit if cancel
if vmfile = "" then
WScript.Quit
end if
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)
' Quit if cancel
if zipfile = "" then
WScript.Quit
end if
tmpfolder = fso.GetParentFolderName(zipfile) & "\" & vm
way = "i"
' New Section: for working with 2 args
ElseIf args.Count=2 Then 'We are in the automatic mode with 2 Arguments: VM and backup location
vmfile = args(0)
vmfolder = fso.GetParentFolderName(vmfile)
vmparent = fso.GetParentFolderName(vmfolder)
vm = Replace(Replace(vmfolder, vmparent, ""),"\","")
' bkfile = bkpath & vm & "-" & iso_date(now) & ".zip"
zipfile = args(1)
tmpfolder = fso.GetParentFolderName(zipfile)
' Here we should check if the tmpfolder exists: dunno if it will be automatically created...
' If not, it should be created on this place programmatically...
way = "a"
' /New Section
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
Message was edited by:
RDPetruska
Updated Script by Saxa