Favorites
Hyper-V Virtual Machine Backup Script using VBS/VBScript

Link to Text File: hypervbackups-shutdown.txt

'================================================================
'Hyper-V Virtual Machine Backup Script using VBS/VBScript
This Script Shuts down the VMs first
'================================================================
'================================================================
'External Requirements:
'
'Windows Server 2008
'HyperV Role
'indicator_square.gif (http://www.czerno.com/html/windows/indicator_square.gif)
'hyperv.htm (http://www.czerno.com/html/windows/hyperv.htm)
'
'All can be found in a zip file here: (http://www.czerno.com/html/windows/hypervbackups-shutdown.zip)
'================================================================

'================================================================
'Instructions:
'
'Save this file as what ever name you want
'
'Place indicator_square.gif and hyperv.htm in the same folder as this script
'
'Do not rename indicator_square.gif or hyperv.htm
'
'Do not run the script in the Root of a drive, subfolder only
'================================================================

'================================================================
'Warnings:
'
'This Script assumes all of your VMs are always set to run. I could not find a way to
'determine if the VM was set to Automatically start with Hyper-V
'
'================================================================

'================================================================
'Note:
'If you want to see the status of the backup, be sure when you schedule
'the task to configure it for Windows Server 2003, Windows XP or Windows 2000
'
'Also, make sure you set the 'Start in folder' when scheduling the task.
'================================================================
On Error Resume Next

'****************************************************************
'Begin User Definable Section
'****************************************************************

'================================================================
' Path to backup VMs to, can be UNC or Local, be careful with spaces
'================================================================
strBackupDir = "\\servername\sharename"
'OR
'strBackupDir = "F:\Foldername"

'================================================================
'Drive Letter, plus colon, where VMs are located
'
'Be sure this drive is limited to only VMs as everything will
'be created in the Shadow Copy.
'It's ok if there is more, but it will take longer and use more
'disk space to create the Shadow Copy.
'There is a chance, if you are linited in space, not all the VMs
'will be in the Shadow Copy.
'================================================================
strVMdrive = "D:"

'================================================================
'Subfolder where VMs are located
'================================================================
strVMfolder = "Virtual Machines"

'================================================================
'Free Drive Letter, plus colon, to mount the Shadow Copy
'================================================================
strTempDrive = "V:"

'================================================================
'Email From address
'================================================================
strEmailFrom = "your@email.com"

'================================================================
'Email to address
'================================================================
strEmailTo = "your@email.com"

'================================================================
'SMTP Server
'================================================================
strSMTP = "mailserver"

'****************************************************************
'End User Defined Section
'****************************************************************

'================================================================
'Load current date (formatted as mm-dd-yyyy)
'into variable strDate
'================================================================
strDate = Month(Now) & "-" & Day(Now) & "-" & Year(Now)

'================================================================
'Determine where the script is being ran from
'================================================================
Set objShell = CreateObject ("WScript.Shell")
set objFSO=CreateObject("Scripting.FileSystemObject")
strPath = Wscript.ScriptFullName
Set objFile = objFSO.GetFile(strPath)
strFolder = objFSO.GetParentFolderName(objFile)


'================================================================
'Setup progress window
'================================================================
Set objExplorer = WScript.CreateObject("InternetExplorer.Application")
objExplorer.Navigate "file:///" & strFolder & "\hyperv.htm"
objExplorer.ToolBar = 0
objExplorer.StatusBar = 0
objExplorer.Width=400
objExplorer.Height = 200
objExplorer.Left = 0
objExplorer.Top = 0

Do While (objExplorer.Busy)
Wscript.Sleep 200
Loop

objExplorer.Visible = 1

'================================================================
'VBScript and Robocopy Log Files
'================================================================
strLogFolder = strFolder & "\vmbackuplogs"

'create Log File folder
Set objFSO = CreateObject("Scripting.FileSystemObject")

If Not objFSO.FolderExists(strLogFolder) Then
Set objFolder = objFSO.CreateFolder(strLogFolder)
End If

'Set objFolder = objFSO.CreateFolder(strLogFolder)
strVBSLog = strLogFolder & "\vmbackup1.log"
strCreateVSSLog = strLogFolder & "\vmbackup3CreateVSS.log"
strDeleteVSSLog = strLogFolder & "\vmbackup4DeleteVSS.log"
strRoboLog = strLogFolder & "\vmbackup2.log"
strLogFile = strFolder & "\" & strDate & "-VMBackupLogFile.txt"

'=============================================================================
'Setup VBS Log File
'=============================================================================

Set objFSO = createobject("scripting.filesystemobject")
Set objStream = objFSO.OpenTextFile(strVBSLog,2,true)
objStream.Writeline((Now) & " --- Hyper-V Virtual Machine Backup Script Starting")
objStream.Writeline((Now) & " --- Script is being ran from: " & strFolder)
objStream.Writeline(" ")
objExplorer.Document.Body.InnerHTML = "Hyper-V Virtual Machine Backup Script Starting<br>" _
& "<img src="".\indicator_square.gif"" />"
wscript.sleep 5000

'=============================================================================
'Shutdown Running VMs
'=============================================================================
objStream.Writeline((Now) & " --- Shutdown Running VMs")
objExplorer.Document.Body.InnerHTML = "Shutdown Running VMs <br>" _
& "<img src="".\indicator_square.gif"" />"
wscript.sleep 5000

Set WMIObject = GetObject("winmgmts:\\.\root\virtualization")
Set VMList = WMIObject.ExecQuery("SELECT * FROM Msvm_ComputerSystem")

For Each VM In VMList
If VM.Caption = "Virtual Machine" then
VMName = VM.ElementName
checkVMState()
If VM.EnabledState = 2 then
wscript.sleep 1000
Set vmshut = WMIObject.ExecQuery("SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" & VM.Name & "'")
vmReturn = vmshut.ItemIndex(0).InitiateShutdown(True,"Scripted Shutdown")
Do While theVM <> 3
checkVMState()
'Wscript.echo theVM
WScript.Sleep 5000
Loop
End if
End if
Next

'=============================================================================
'Create Shadow Copy Commands
'=============================================================================
objStream.Writeline((Now) & " --- " & "Create DiskShadow Commands")
objExplorer.Document.Body.InnerHTML = "Create DiskShadow Commands<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

sVSSCmd = "CreateVSS.dsh"

Set oFileSys = CreateObject("Scripting.FileSystemObject")
if oFileSys.FileExists(sVSSCmd) then oFileSys.DeleteFile(sVSSCmd)
set oVSSCmd = oFileSys.CreateTextFile(sVSSCmd, True)
oVSSCmd.WriteLine "DELETE SHADOWS ALL"
oVSSCmd.WriteLine "SET CONTEXT PERSISTENT"
oVSSCmd.WriteLine "SET METADATA " & strFolder & "\" & "VMBackup.cab"
oVSSCmd.WriteLine "SET VERBOSE OFF"
oVSSCmd.WriteLine "BEGIN BACKUP"
oVSSCmd.WriteLine "ADD VOLUME " & strVMdrive & " ALIAS G1"
oVSSCmd.WriteLine "BEGIN BACKUP"
oVSSCmd.WriteLine "CREATE"
oVSSCmd.WriteLine "EXPOSE %G1% " & strTempDrive
oVSSCmd.Close
objStream.Writeline((Now) & " --- " & "Create DiskShadow Commands Complete")

wscript.sleep 1000

objExplorer.Document.Body.InnerHTML = "Creating DiskShadow Commands Complete<br>" _
& "<img src="".\indicator_square.gif"" />"

'=============================================================================
'Create Shadow Copy Script
'=============================================================================
objStream.Writeline((Now) & " --- " & "Create DiskShadow Scripts")
objExplorer.Document.Body.InnerHTML = "Creating DiskShadow Scripts<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

sVSSScript = "CreateVSS.cmd"

Set oFileSys = CreateObject("Scripting.FileSystemObject")
if oFileSys.FileExists(sVSSScript) then oFileSys.DeleteFile(sVSSScript)
set oVSSScript = oFileSys.CreateTextFile(sVSSScript, CopyOverwrite)
oVSSScript.WriteLine "diskshadow /s " & strFolder & "\" & sVSSCmd & " >" & strCreateVSSLog & ""
oVSSScript.Close
objStream.Writeline((Now) & " --- " & "Create DiskShadow Scripts Complete")

objExplorer.Document.Body.InnerHTML = "Creating DiskShadow Scripts Complete<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Create Shadow Copy
'=============================================================================
objStream.Writeline((Now) & " --- " & "Running DiskShadow Scripts")
objExplorer.Document.Body.InnerHTML = "Running " & sVSSScript & " <br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

Result = objShell.run(sVSSScript,1, TRUE)

objStream.Writeline((Now) & " --- " & "DiskShadow Scripts Completed")
objExplorer.Document.Body.InnerHTML = "DiskShadow Scripts Completed<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Start VMs
'We are assuming all VMs need to be started. I cannot find a way to query
'Hyper-V if the VM is set to Automatically start or not.
'=============================================================================
objStream.Writeline((Now) & " --- Starting VMs")
objExplorer.Document.Body.InnerHTML = "Starting VMs <br>" _
& "<img src="".\indicator_square.gif"" />"
wscript.sleep 5000

Set WMIObject = GetObject("winmgmts:\\.\root\virtualization")
Set VMList = WMIObject.ExecQuery("SELECT * FROM Msvm_ComputerSystem")

For Each VM In VMList
If VM.Caption = "Virtual Machine" then
VMName = VM.ElementName
checkVMState()
'If VM.EnabledState = 32769 then
wscript.sleep 1000
VM.RequestStateChange(2)
Do While theVM <> 2
checkVMState()
'Wscript.echo theVM
WScript.Sleep 60000
Loop
'End if
End if
Next

'=============================================================================
'Robocopy VMs
'=============================================================================
objStream.Writeline((Now) & " --- " & "Running Robocopy Script")
objExplorer.Document.Body.InnerHTML = "Running Robocopy Script<br>" _
& "<img src="".\indicator_square.gif"" />"

sExCmd = "cmd /c robocopy.exe """ & strTempDrive & "\" & strVMfolder & """ """ & strBackupDir & """ /e /r:10 /w:60 /nfl /purge /log:" & strRoboLog & ""
Result = objShell.run(sExCmd,1, TRUE)

objStream.Writeline((Now) & " --- " & "Robocopy Script Completed")
objExplorer.Document.Body.InnerHTML = "Robocopy Script Completed<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Create Delete Shadow Copy Commands
'=============================================================================
objStream.Writeline((Now) & " --- " & "Create Delete Shadow Copy Commands")
objExplorer.Document.Body.InnerHTML = "Creating Delete Shadow Copy Commands<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 5000

sDVSSCmd = "DeleteVSS.dsh"

Set oFileSys = CreateObject("Scripting.FileSystemObject")
if oFileSys.FileExists(sDVSSCmd) then oFileSys.DeleteFile(sDVSSCmd)
set oDeleteVSSCmd = oFileSys.CreateTextFile(sDVSSCmd, CopyOverwrite)

oDeleteVSSCmd.WriteLine "DELETE SHADOWS ALL"
oDeleteVSSCmd.WriteLine "END BACKUP"
oDeleteVSSCmd.Close

objStream.Writeline((Now) & " --- " & "Create Delete Shadow Copy Commands Complete")
objExplorer.Document.Body.InnerHTML = "Creating Delete Shadow Copy Commands Complete<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Create Shadow Copy Delete Script
'=============================================================================
objStream.Writeline((Now) & " --- " & "Create Shadow Copy Delete Script")
objExplorer.Document.Body.InnerHTML = "Creating Shadow Copy Delete Script<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 5000

sVSSDelScript = "DeleteVSS.cmd"

Set oFileSys = CreateObject("Scripting.FileSystemObject")
if oFileSys.FileExists(sVSSDelScript) then oFileSys.DeleteFile(sVSSDelScript)
set oVSSScript = oFileSys.CreateTextFile(sVSSDelScript, CopyOverwrite)

oVSSScript.WriteLine "diskshadow /s " & strFolder & "\" & sDVSSCmd & " >" & strDeleteVSSLog & ""
oVSSScript.Close

objStream.Writeline((Now) & " --- " & "Create Shadow Delete Script Complete")
objExplorer.Document.Body.InnerHTML = "Creating Shadow Delete Script Complete<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Delete Shadow Copy
'=============================================================================
objStream.Writeline((Now) & " --- " & "Delete Shadow Copy ")
objExplorer.Document.Body.InnerHTML = "Deleting Shadow Copy<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 5000

Result = objShell.run(sVSSDelScript,1, TRUE)

objStream.Writeline((Now) & " --- " & "Delete Shadow Copy Script Completed")
objExplorer.Document.Body.InnerHTML = "Deleting Shadow Copy Completed<br>" _
& "<img src="".\indicator_square.gif"" />"

wscript.sleep 1000

'=============================================================================
'Backup should now be finished,
'=============================================================================
objStream.Writeline((Now) & " --- " & "Backup should now be finished, Emailing this Log File")
objExplorer.Document.Body.InnerHTML = "Backup should now be finished, Emailing the Log File<br>" _
& "<img src="".\indicator_square.gif"" />"
objStream.Writeline((Now) & " --- " & "Robocopy Log is below.")
wscript.sleep 5000
objStream.close

'=============================================================================
'Combine Log Files
'=============================================================================
Const ForReading = 1

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objOutputFile = objFSO.CreateTextFile(strLogFile)

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set FileList = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_Directory.Name='" & strLogFolder & "'} Where " _
& "ResultClass = CIM_DataFile")

For Each objFile In FileList
Set objTextFile = objFSO.OpenTextFile(objFile.Name, ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
objOutputFile.WriteLine strText
Next
objOutputFile.Close

'=============================================================================
'Email Log File
'=============================================================================
Set objEmail = CreateObject("CDO.Message")
objEmail.From = strEmailFrom
objEmail.To = strEmailTo
objEmail.Subject = strDate & " VM Backups"
objEmail.AddAttachment strLogFile
objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = _
StrSMTP
objEmail.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objEmail.Configuration.Fields.Update
objEmail.Send

wscript.sleep 1000
objExplorer.Quit

oFileSys.DeleteFile(sVSSCmd)
oFileSys.DeleteFile(sVSSDelScript)
oFileSys.DeleteFile(sVSSScript)
oFileSys.DeleteFile(sDVSSCmd)

wscript.quit

'=============================================================================
'Subs and what not
'=============================================================================

sub checkVMState()
Set WMIObject = GetObject("winmgmts:\\.\root\virtualization")
Set VMCurrent = WMIObject.ExecQuery("SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" & VMName & "'")

For Each currentVM In VMCurrent

theVM = VMCurrent.ItemIndex(0).EnabledState
'wscript.echo theVM

Next

Select Case theVM

Case 0
objStream.Writeline((Now) & " --- " & VMName & "'s State is unknown")
objExplorer.Document.Body.InnerHTML = VMName & "'s State is unknown<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 2
objStream.Writeline((Now) & " --- " & VMName & " is Started")
objExplorer.Document.Body.InnerHTML = VMName & " is Started<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 3
objStream.Writeline((Now) & " --- " & VMName & " is Stopped")
objExplorer.Document.Body.InnerHTML = VMName & " is Stopped<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32768
objStream.Writeline((Now) & " --- " & VMName & " is Paused")
objExplorer.Document.Body.InnerHTML = VMName & " is Paused<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32769
objStream.Writeline((Now) & " --- " & VMName & " is Suspended")
objExplorer.Document.Body.InnerHTML = VMName & " is Suspended<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32770
objStream.Writeline((Now) & " --- " & VMName & " is Starting")
objExplorer.Document.Body.InnerHTML = VMName & " is Starting<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32771
objStream.Writeline((Now) & " --- " & VMName & " is Snapshotting")
objExplorer.Document.Body.InnerHTML = VMName & " is Snapshotting<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32772
objStream.Writeline((Now) & " --- " & VMName & " is Migrating")
objExplorer.Document.Body.InnerHTML = VMName & " is Migrating<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32773
objStream.Writeline((Now) & " --- " & VMName & " is Saving")
objExplorer.Document.Body.InnerHTML = VMName & " is Saving<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32774
objStream.Writeline((Now) & " --- " & VMName & " is Stopping")
objExplorer.Document.Body.InnerHTML = VMName & " is Stopping<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32775
objStream.Writeline((Now) & " --- " & VMName & " is Deleted")
objExplorer.Document.Body.InnerHTML = VMName & " is Deleted<br>" _
& "<img src="".\indicator_square.gif"" />"
Case 32776
objStream.Writeline((Now) & " --- " & VMName & " is Pausing")
objExplorer.Document.Body.InnerHTML = VMName & " is Started and is now Saving<br>" _
& "<img src="".\indicator_square.gif"" />"
Case Else
objStream.Writeline((Now) & " --- " & VMName & " is unknown")
objExplorer.Document.Body.InnerHTML = VMName & " is unknown<br>" _
& "<img src="".\indicator_square.gif"" />"
End Select

End sub