Hyper-V backup script

Pick Language to Auto Translate:
AR | BG | CA | CS | DA | DE | EL | ES | FI | FR | HI | HR | ID | IT | IW | JA | KO | LT | LV | NL | NO | PL | PT | RO | RU | SK | SR | SL | SV | TL | UK | VI | ZH | ZH-TW

This script can backup your Hyper-V to a specific folder with an optional list of VM from a file or it can get a list from Hyper-V directly and can rotate backup set based on the optional parameters.

If you are running Windows 2008 R2 then you might want to use ExportVirtualSystemEx function instead ExportVirtualSystem function.

Usage:

cscript program.vbs exportDirectoryName [c:\fileOfVMList.txt] [d3|w1]

Further explain:

[c:\fileOfVMList.txt] (optional)
It is an optional file that contain a list of VM for this script to run backup

[d3|w1] (optional)
d3 is for Daily schedule with 3 rotation
w1 is for Weekly schedule with 1 rotation

Note: the above assume to will have a schedule task created and this script will just parse the text and create the folder for rotation base on the number


' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
' THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
' FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
' DEALINGS IN THE SOFTWARE.
' Hyper-V export all VM
' By: Chanh Ong
' Purpose: Try to create Hyper-V backup solution for Hyper-V server
' Date: 04/2010

option explicit

Const OPEN_FILE_FOR_READING = 1

dim objWMIService
dim managementService
dim fileSystem
dim vmCollection
dim vm
dim backupDir
dim vmList

Dim StdIn, StdOut, gFso, gShell, gNetwork
Set StdIn = WScript.StdIn
Set StdOut = WScript.StdOut
Set gFso = WScript.CreateObject("Scripting.FileSystemObject")
Set gShell = WScript.CreateObject ("WSCript.shell")
Set gNetwork = Wscript.CreateObject("WScript.Network")

const JobStarting = 3
const JobRunning = 4
const JobCompleted = 7
const wmiStarted = 4096
const wmiSuccessful = 0

dim strComputer, objArgs, exportDir, dow, which
dim freq
strComputer = "."
set fileSystem = Wscript.CreateObject("Scripting.FileSystemObject")
set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\virtualization")
set managementService = objWMIService.ExecQuery("select * from Msvm_VirtualSystemManagementService").ItemIndex(0)

set objArgs = WScript.Arguments
if WScript.Arguments.Count > 0 then
exportDir = objArgs.Unnamed.Item(0)
vmList = GetVMList(objArgs)
freq = GetFreq(objArgs)
else
WScript.Echo "usage: cscript program.vbs exportDirectoryName [c:\fileOfVMList.txt] [d3|w1] "
WScript.Quit(1)
end if

if (isArray(vmList) = true) then
backupDir = RotateFolder(exportDir, freq)
WriteLog "Start at " & now & " backup to folder: " & backupDir
call ExportVM(vmList, backupDir)
WriteLog "Stop at " & now
else
WScript.Echo "Nothing to do!"
end if
' end main

Function RotateFolder(exportDir, freq)
dim which, fDate, f, fName, count, nextFolder, nextNumber, thisFolder, prevFolder
dim backupDir, baseDir, rotate
nextNumber = 1

rotate = right(freq,1)
count = rotate
' fName = left(freq,1)
' fName = left(freq,1) & "-" & DatePart("h", now)
fName = left(freq,1) & "-" & DatePart("h", now) & "-" & DatePart("n", now)

backupDir = exportDir & "\" & fName & "."
baseDir = backupDir & "1"
do
thisFolder = backupDir & count
nextFolder = backupDir & count - 1
If (gFso.FolderExists(thisFolder) = true and gFso.FolderExists(nextFolder) = true and count = rotate) Then
call doRun("rmdir /s /q "&thisFolder)
WScript.Sleep 1000
end if
If (count <> rotate) Then
prevFolder = backupDir & count + 1
If (gFso.FolderExists(thisFolder) = true) then
call doRun("move " & thisFolder & " " & prevFolder)
WScript.Sleep 1000
end if
end if
count = count - 1
loop while (count <> 0)
call MakeBackupFolder(baseDir)
RotateFolder = baseDir
end Function

sub MakeBackupFolder(bkupDir)
If (gFso.FolderExists(bkupDir) = true) Then
call doRun("rmdir /s /q "&bkupDir)
WScript.Sleep 1000
end if
call doRun("mkdir "&bkupDir)
WScript.Sleep 1000
end sub

Function GetFreq(objArgs)
if (len(objArgs(2))<>0 and objArgs.Count > 1) then
GetFreq = objArgs(2)
else
GetFreq = "d2"
end if
end Function

Function GetVMList(objArgs)
if (len(objArgs(1))<>0 and objArgs.Count > 0) then
WScript.Echo "Get VM list from file: " & objArgs(1)
GetVMList = getVMFromFile(objArgs(1))
else
WScript.Echo "Get VM list from HyperV"
GetVMList = GetVMListFromHyperV()
end if
end Function

Function GetVMListFromHyperV()
dim oneVM, count
count = 0
Set vmCollection = objWMIService.ExecQuery("SELECT * FROM Msvm_ComputerSystem",,48)
dim vmList(100)
For Each oneVM in vmCollection
vmList(count) = oneVM.ElementName
count = count + 1
next
GetVMListFromHyperV = vmList
end Function

sub ExportAllVM_old(expDirectory)
dim oneVM
call outHeader(" Start export to " & expDirectory)
Set vmCollection = objWMIService.ExecQuery("SELECT * FROM Msvm_ComputerSystem",,48)
For Each oneVM in vmCollection
if oneVM.Caption <> "Hosting Computer System" then
stopOneVM(oneVM)
if ExportVirtualSystemEx(oneVM, expDirectory) then
vmStart(oneVM)
WriteLog " at " & now & " : Finish export"
else
WriteLog "ExportVirtualSystemEx Failed for " & oneVM.ElementName
end if
end if
Next
end sub

sub ExportAllVM(expDirectory)
dim vmList
vmList = GetVMListFromHyperV()
call ExportVM(vmList, expDirectory)
end sub

sub ExportVM(VMList, expDirectory)
dim oneVM, eachVM
' if (isArray(VMList) = true) then
call outHeader(" Start export to " & expDirectory)
For Each eachVM in VMList
' WScript.Echo "VM: " & eachVM
if (eachVM<>"") then
set oneVM = GetComputerSystem(trim(eachVM))
if oneVM.Caption <> "Hosting Computer System" then
stopOneVM(oneVM)
' un-comment this line if you are using Windows 2008 R2
' if ExportVirtualSystemEx(oneVM, expDirectory) then
' This is for Windows 2008 and R2
if ExportVirtualSystem(oneVM, expDirectory) then
vmStart(oneVM)
WriteLog " at " & now & " : Finish export for VM: " & oneVM.ElementName
else
WriteLog "ExportVirtualSystemEx Failed for " & oneVM.ElementName
end if
end if
end if
Next
' end if
end sub

Function ExportVirtualSystem(computerSystem, exportDirectory)
dim objInParam, objOutParams
ExportVirtualSystem = false
if Not fileSystem.FolderExists(exportDirectory) then
fileSystem.CreateFolder(exportDirectory)
end if
set objInParam = managementService.Methods_("ExportVirtualSystem").InParameters.SpawnInstance_()
objInParam.ComputerSystem = computerSystem.Path_.Path
objInParam.CopyVmState = true
objInParam.ExportDirectory = exportDirectory
set objOutParams = managementService.ExecMethod_("ExportVirtualSystem", objInParam)
if objOutParams.ReturnValue = wmiStarted then
if (WMIJobCompleted(objOutParams)) then
ExportVirtualSystem = true
end if
elseif (objOutParams.ReturnValue = wmiSuccessful) then
ExportVirtualSystem = true
else
WriteLog Format1("DefineVirtualSystem failed with ReturnValue {0}", wmiStatus)
end if

End Function

'-----------------------------------------------------------------
' Export a virtual system (R2)
'-----------------------------------------------------------------
Function ExportVirtualSystemEx(oneVM, expDirectory)
dim objInParam, objOutParams
dim query
dim computer
dim exportSettingData
dim computerSystem
ExportVirtualSystemEx = false
if Not fileSystem.FolderExists(expDirectory) then
fileSystem.CreateFolder(expDirectory)
end if
set computerSystem = GetComputerSystem(oneVM.ElementName)
' set managementService = objWMIService.ExecQuery("select * from Msvm_VirtualSystemManagementService").ItemIndex(0)
set objInParam = managementService.Methods_("ExportVirtualSystemEx").InParameters.SpawnInstance_()
objInParam.ComputerSystem = computerSystem.Path_.Path
query = Format1("ASSOCIATORS OF {{0}} WHERE resultClass = Msvm_VirtualSystemExportSettingData", computerSystem.Path_.Path)
set exportSettingData = objWMIService.ExecQuery(query).ItemIndex(0)
exportSettingData.CopyVmStorage = true
exportSettingData.CopyVmRuntimeInformation = true
exportSettingData.CreateVmExportSubdirectory = true
exportSettingData.CopySnapshotConfiguration = 0
objInParam.ExportSettingData = exportSettingData.GetText_(1)
objInParam.ExportDirectory = expDirectory
set objOutParams = managementService.ExecMethod_("ExportVirtualSystemEx", objInParam)
if objOutParams.ReturnValue = wmiStarted then
if (WMIJobCompleted(objOutParams)) then
ExportVirtualSystemEx = true
end if
elseif (objOutParams.ReturnValue = wmiSuccessful) then
ExportVirtualSystemEx = true
else
WriteLog Format1("ExportVirtualSystemEx failed with ReturnValue {0}", objOutParams.ReturnValue)
end if
End Function

'-----------------------------------------------------------------
' Handle wmi Job object
'-----------------------------------------------------------------
Function WMIJobCompleted(outParam)
dim WMIJob, jobState, nextProgress
set WMIJob = objWMIService.Get(outParam.Job)
WMIJobCompleted = true
jobState = WMIJob.JobState
nextProgress = 10
WriteLog " at " & now & " : Start export"
while jobState = JobRunning or jobState = JobStarting
if (nextProgress = WMIJob.PercentComplete) then
nextProgress = WMIJob.PercentComplete + 10
WriteLog Format1(" In progress... {0}% completed.",WMIJob.PercentComplete)
end if
set WMIJob = objWMIService.Get(outParam.Job)
jobState = WMIJob.JobState
wend
if (jobState <> JobCompleted) then
WriteLog Format1("ErrorCode:{0}", WMIJob.ErrorCode)
WriteLog Format1("ErrorDescription:{0}", WMIJob.ErrorDescription)
WMIJobCompleted = false
end if
End Function

Sub WriteLog(line)
dim fileStream, filename
' filename = ".\ExportHyperVLog.log"
filename = backupDir&"\ExportHyperVLog.log"
' WScript.Echo "write log to: "&filename
set fileStream = fileSystem.OpenTextFile(filename, 8, true)
WScript.Echo line
fileStream.WriteLine line
fileStream.Close
End Sub

Function Format2(myString, arg0, arg1)
Format2 = Format1(myString, arg0)
Format2 = Replace(Format2, "{1}", arg1)
End Function

Function Format1(myString, arg0)
Format1 = Replace(myString, "{0}", arg0)
End Function

Function VMCode(VMStateCode)
Select Case VMStateCode
Case 2 VMCode = "Running"
Case 3 VMCode = "PowerOff"
Case 4 VMCode = "ShuttingDown"
Case 10 VMCode = "Reset"
Case 32768 VMCode = "Paused"
Case 32770 VMCode = "Starting"
Case 32771 VMCode = "SnapshotInProgress"
Case 32772 VMCode = "Migrating"
Case 32773 VMCode = "Saving"
Case 32774 VMCode = "Stopping"
Case 32776 VMCode = "Pausing"
Case 32777 VMCode = "Resuming"
Case 32769 VMCode = "Saved"
Case Else VMCode = "Unclassified"
End Select
end Function

Function VMInfo(oneVM)
dim VMStateCode, VMState
VMStateCode = oneVM.EnabledState
VMState = VMCode(VMStateCode)
VMInfo = oneVM.ElementName & Space(20 - Len(oneVM.ElementName)) & oneVM.Description & Space(35 - Len(oneVM.Description)) & VMState & " (" &VMStateCode & ")"
end Function

Function GetComputerSystem(vmElementName)
On Error Resume Next
dim query
query = Format1("select * from Msvm_ComputerSystem where ElementName = '{0}'", vmElementName)
set GetComputerSystem = objWMIService.ExecQuery(query).ItemIndex(0)
if (Err.Number <> 0) then
WriteLog Format1("Err.Number: {0}", Err.Number)
WriteLog Format1("Err.Description:{0}",Err.Description)
WScript.Quit(1)
end if
End Function

Function theVMState(vmName)
dim computerSystem
set computerSystem = GetComputerSystem(VMName)
theVMState = VMCode(computerSystem.EnabledState)
end Function

sub vmChange(oneVM, changeType)
dim VMList, computerSystem, vmName
vmName = oneVM.ElementName
WriteLog VMInfo(oneVM)
set computerSystem = GetComputerSystem(VMName)
' 2 = start, 3 = stop and 32769 = save state
computerSystem.RequestStateChange(changeType)
end sub

Function vmStart(oneVM)
call vmChange(oneVM, 2)
end Function

Function vmStop(oneVM)
call vmChange(oneVM, 3)
end Function

Function vmStartx(oneVM)
dim VMList, computerSystem, vmName
vmName = oneVM.ElementName
WriteLog VMInfo(oneVM)
set computerSystem = GetComputerSystem(VMName)
' 2 = start, 3 = stop and 32769 = save state
computerSystem.RequestStateChange(2)
end Function

Function vmShutdown(oneVM)
dim vmShut, VMGuid, computerSystem, vmName
WriteLog VMInfo(oneVM)
vmName = oneVM.ElementName
set computerSystem = GetComputerSystem(VMName)
VMGuid = computerSystem.Name
Set vmShut = objWMIService.ExecQuery("SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" & VMGuid & "'")
if VMCode(computerSystem.EnabledState) = "Running" then
vmShutdown = vmShut.ItemIndex(0).InitiateShutdown(True,"Scripted Shutdown")
end if
end Function

Function stopOneVM(oneVM)
dim vmReturn, VMState, count, vmName
vmName = oneVM.ElementName
WriteLog " at " & now & " : Stopping..."
count = 0
VMState = theVMState(vmName)
If VMState = "Running" then
vmReturn = vmShutdown(oneVM)
do
if (count = 19) then
vmStop(oneVM)
end if
count = count + 1
VMState = theVMState(vmName)
WriteLog VMInfo(oneVM)
WScript.Sleep 3500

loop while (VMState <> "PowerOff" and count < 20)
End if
end Function

Function stopAllVM(vmList)
dim oneVM, vmName
For Each oneVM In vmList
if oneVM.Caption <> "Hosting Computer System" then
' vmShutdown(oneVM.ElementName)
stopOneVM(oneVM.ElementName)
End if
Next
end Function

Function startAllVM(vmList)
dim oneVM, vmName
For Each oneVM In vmList
if oneVM.Caption <> "Hosting Computer System" then
vmStart(oneVM)
End if
Next
end Function

sub outHeader(outType)
' WriteLog VbCrLF
WriteLog " at " & now & " : " & outType
WriteLog "Name Description State "
WriteLog "------------------- ---------------------------------- -------------"
end sub

sub doRun(cmd)
WScript.Echo cmd
gShell.run "cmd /C " &cmd
end sub

Function getDOW(TheDate)
dim weekday
weekday = DatePart("w", TheDate)
Select Case weekday
Case 1 getDOW = "Sun"
Case 2 getDOW = "Mon"
Case 3 getDOW = "Tue"
Case 4 getDOW = "Wed"
Case 5 getDOW = "Thu"
Case 6 getDOW = "Fri"
Case 7 getDOW = "Sat"
Case 1 getDOW = "Sun"
End Select
End Function

' Read a file eg: larray=rdFile("pc.txt")
Function getVMFromFile(filespec)
Dim oInFile
Dim sData, lArray
dim gdebug
gdebug = false
' WScript.Echo "file:" & filespec
If (gFso.FileExists(filespec)) Then
Set oInFile = gFso.OpenTextFile(filespec, OPEN_FILE_FOR_READING)
lArray = Split(oInFile.ReadAll, vbNewline)
if gdebug = true then
For each sData In lArray
WScript.Echo "line:" & sData
Next
end if
oInFile.Close
getVMFromFile = lArray
end if
end Function