Script to perform a warm backup of a virtual machine
Here's an example of a script written in VBScript that you can write to perform a warm backup of a virtual machine. It was written by John Kelbley, who's a technology specialist for Microsoft. Please pay attention to the warnings and caveats given in the script.
Thanks John!
' READ THIS LINE!!! The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
'
'
' MoveWarm.VBS written by John Kelbley
'
'
' This the mother of all Demo Virtual Server Availability scripts!
'
' When the script is executed properly from a running Virtual Server system with active Guest images,
' it hibernates, copies, installs, and starts all active Guest images on another Virtual Server!
'
' This could be used in a production environment to allow for hardware maintenance while minimizing down time of Guest images, if all assumptions are met, including:
' Identical Virtual Server hardware configuration - enough RAM, disk space with same drive letters, etc. on target to accommodate migrated guest images
' Identical Virtual Network configuration (it's just easier, otherwise, they may not start automatically, and you'll have to adjust the config)
' Other things I haven't run into in my testing (I only have a couple of Evo's to test on!)
' XP SP2 (connection firewall) can keep this from running, depending on the hosts you are using (rumor that some DCOM security thing might mess things up, too)
' I sometimes have been know to setup a local account on both hosts with the same name and password as my domain credential, and map drives back and forth to
' make sure everything will run right before kicking off the script for a demo!
'
' NAME RESOLUTION IS A BIG DEAL HERE TOO!!!
'
' How does the Script do it? It does a few key things:
' 1) "saves state" on running VPC images
' 2) Creates a .BAT and .VBS on original host for each of the hibernated images in current directory
' 3) Starts .BAT for each hibernated image on local host (this kind of multi-threads the copy)
' a) copies files related to image to new host (.VHD config, save state)
' b) runs .VBS to register config file on new host, and re-start from Saved State
'
' The script does not clean up after itself, as it is a sample meant for training purposes!
'
' The .BAT and .VBS files generated may be of interest to someone, so at this time, I did not want to delete them
'
'
' When I run the demos, I usually use smaller VMs - some from the VMSTORE areas - like Windows 3.0 or BOB on Windows 95
'
'
' Thanks to the Tech Net Script Center folks for all their guidance (great examples on the web, as well as usable reference books on VBS!)
'
'
Option Explicit
'On Error Resume Next
Const ForWriting = 2 ' constant used for openning text files
Dim ToSystem ' Computer Name of Target host system
Dim FromSystem ' Computer Name of source host system
Dim VMStateCodes ' Array of VM State Codes - to display kinder status that integers
Dim VMStuff ' Virtual Server Info instance
Dim SourcevmCollection ' Collection of VMs from Source Server
Dim vm ' instance of a VM from collection loop
Dim objVM ' instance of a VM
Dim MoveVM ' instance of a VM
Dim colHardDisks ' Collection of VHDs in a VM
Dim objDrive ' instance of a VHD from collection loop
Dim objHardDisk ' instance of a VHD
Dim NameLength ' for tidy display of VM names
Dim MaxNameLength ' for tidy display of VM names
Dim VMCount ' counter for all VMs
Dim MoveCount ' counter for VMs to move - VMs that are currently running (nicer demo!)
Dim MoveName ' local var with VM name
Dim VMInfo(100) ' array of VM names to be moved
Dim TargetHost ' The server where all the runnning VM's will be moved
Dim TargetHostServer ' The server where all the runnning VM's will be moved
Dim TargetHostAvailable ' Boolean to track if the target host is pingable
Dim MyShell ' Used to find local host name, if required
Dim MyEnvironment ' Used to find local host name, if required
' Set Target host variables
'TargetHost = "192.168.0.3" ' put name or IP Address of target server here, NOT preceeded by two slashes
'TargetHost = "WS03VS01" ' put name or IP Address of target server here, NOT preceeded by two slashes
TargetHost = "CHANGEME" ' put name or IP Address of target server here, NOT preceeded by two slashes
'
' Should not need to change anything after here to get script to run!
'
TargetHostServer = "\\" & TargetHost
TargetHostAvailable = TRUE ' setting default before ping test
Call Housekeeping()
VMCount = 0
Set SourcevmCollection = VMStuff.VirtualMachines
'
' Get maximum Name Length for Formatting - just makes some things look nice
'
For each vm in SourcevmCollection
NameLength = Len(vm.Name)
If MaxNameLength < NameLength Then
MaxNameLength = NameLength
End If
'
' If VM is "Running" them target for WARM migration to other host system
' Here is where the systems are identifed at migration targets
'
if VMStateCodes(vm.State) = "Running" Then
VMInfo(VMCount) = vm.Name
VMCount = VMCount + 1
End If
Next
For each vm in SourcevmCollection
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Wscript.Echo " " & vm.Name & Space(MaxNameLength - Len(vm.Name)) & " - State is: " & VMStateCodes(vm.State)
Next
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Wscript.Echo "--------------------------------------------------------------------"
if VMCount = 0 then
Wscript.Echo VbCrLf & "No VMs are runnning, nothing to warm move"
End If
'****************************************************
' Engine is here!!!!!
'****************************************************
if TargetHostAvailable = TRUE Then
For MoveCount = 1 to VMCount
MoveName = VMInfo(MoveCount-1)
Wscript.Echo "Processing " & MoveName & Space(MaxNameLength - Len(MoveName)) & " VM " & MoveCount & " of " & VMCount & "..."
Set objVM = VMStuff.FindVirtualMachine(MoveName)
' Save State of all running VMs
Call SaveVMState(MoveName)
' Generage .BAT and .VBS for each of the running VMs
Call MakeScriptFiles(MoveName)
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Next
End If
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Wscript.Echo "--------------------------------------------------------------------"
'End Script
'******************************************************************************
'******************************************************************************
'******************************************************************************
'******************************************************************************
'* *
'* *
'* Subroutines to make the stuff up top look nicer! *
'* *
'* *
'* *
'******************************************************************************
'******************************************************************************
'******************************************************************************
'******************************************************************************
'******************************************************************************
'* *
'* Do some if the ugly stuff that I didn't want to put at the front *
'* of the script *
'* *
'******************************************************************************
Sub Housekeeping()
Dim objPing ' use for ping test - poached from TechNet examples
Dim objStatus ' use for ping test - poached from TechNet examples
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- WarmMove.VBS -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- by -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- John Kelbley -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- Finds running VM's running under Virtual Server 2005 -"
Wscript.Echo VbCrLf & "- on local system, pauses them, moves them to specified target -"
Wscript.Echo VbCrLf & "- and unpauses them! -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- Please read comments in script carefully before running! -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- This is a sample, and is not meant for use in production. -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- Script expects NO paramameter - the name of the target -"
Wscript.Echo VbCrLf & "- Virtual Server host is specified internally -"
Wscript.Echo VbCrLf & "- (I WANT YOU TO LOOK AT THE SCRIPT!!!!) -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- Example: cscript MoveWarm.VBS -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "- -"
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
' Populate VM State Array
VMStateCodes = Array("Invalid", "Turned Off","Saved","Turning On", "Restoring", "Running", "Paused", "Saving",_
"Turning Off", "Merging Drives", "Deleting Machine")
' Create VS application instance
Set VMStuff = WScript.CreateObject("VirtualServer.Application")
Wscript.Echo VbCrLf & "Source Host System (this box!): " & FromSystem
Wscript.Echo VbCrLf & "--------------------------------------------------------------------"
Wscript.Echo "Default VM configuration path: " & VMStuff.DefaultVMConfigurationPath
Wscript.Echo "Default VN configuration path: " & VMStuff.DefaultVNConfigurationPath
' Check to see if remote target system is accessible...
'
Wscript.Echo VbCrLf & "Pinging " & TargetHost & " to see if warm migration can occour..."
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery("select * from Win32_PingStatus where address = '" & TargetHost & "'")
For Each objStatus in objPing
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
TargetHostAvailable = FALSE
WScript.Echo VbCrLf & "machine " & TargetHost & " is not reachable"
WScript.Echo "CANNOT EXECUTE Warm migration" & VbCrLf
End If
Next
'***********************************************************************************
' should add a check to see if remote system has Virual Server installed, too!!!!!
'***********************************************************************************
End Sub
'******************************************************************************
'* *
'* Saves the State of Running VMs - creating a "hibernated" VM *
'* *
'******************************************************************************
Sub SaveVMState(subVMName)
Wscript.Echo Space(MaxNameLength + 12) & "Saving State"
While objVM.State > 2 ' if the VM is not turned off of saved...
if VMStateCodes(objVM.State) = "Running" Then
objVM.Save()
End If
wscript.sleep(1000)
Wscript.Echo Space(MaxNameLength + 12) & VMStateCodes(objVM.State)
Wend
End Sub
'******************************************************************************
'* *
'* Generate .BAT and .VBS files to handle the migration of VM files *
'* *
'******************************************************************************
Sub MakeScriptFiles(subVMName)
Dim LocalBatchFile
Dim LocalVBSFile
Dim LocalFSO
Dim LocalFile
Dim FileFSO
Dim FileToCheck
Dim FoundFolder
Dim FromFileConfig
Dim ToFileConfig
Dim ConfigFolder
Dim FromFileState
Dim ToFileState
Dim FromFileVHD
Dim ToFileVHD
Dim FromFileVUD
Dim ToFileVUD
Dim CommandString
Dim objShell
Set MoveVM = VMStuff.FindVirtualMachine(subVMName)
Wscript.Echo VbCrLf & "Beginning Move Processing..."
' ***********************************************************************************************************************
' ***********************************************************************************************************************
' code to create .BAT to copy files and call .VBS to register config file and start image
' ***********************************************************************************************************************
' ***********************************************************************************************************************
LocalVBSFile = subVMName & "_" & "local.vbs"
LocalBatchFile = subVMName & "_" & "local.bat"
Set LocalFSO = CreateObject ("scripting.FileSystemObject")
Set LocalFile = LocalFSO.CreateTextFile(LocalBatchFile)
' start writing batch file
LocalFile.WriteLine "@Echo off"
LocalFile.WriteLine "Echo ---------------------------------------------------------"
' Construct destination UNC for Config File to copy
' Need the path for the parent directory of the file to copy to make Xcopy work right...this seemed easier than parsing the string!
FromFileConfig = MoveVM.File
Set FileFSO = CreateObject("Scripting.FileSystemObject")
Set FileToCheck = FileFSO.GetFile(FromFileConfig)
FoundFolder = FileFSO.GetParentFolderName(FileToCheck)
ConfigFolder = FoundFolder ' Saving this for the VBS later...
ToFileConfig = TargetHostServer & "\" & Left(FoundFolder, 1) & "$" & Mid(FoundFolder, 3, 1024)
CommandString = "xcopy " & CHR(34) & FromFileConfig & CHR(34) & " " & CHR(34) & ToFileConfig & "\" & CHR(34) & " /Y"
LocalFile.WriteLine "echo Copying " & FromFileConfig & " to remote, please wait..."
LocalFile.WriteLine CommandString
LocalFile.WriteLine "Echo ---------------------------------------------------------"
' Construct destination UNC for Save State File n
FromFileState = MoveVM.SavedStateFilePath
Set FileFSO = CreateObject("Scripting.FileSystemObject")
Set FileToCheck = FileFSO.GetFile(FromFileState)
FoundFolder = FileFSO.GetParentFolderName(FileToCheck)
ToFileState = TargetHostServer & "\" & Left(FoundFolder , 1) & "$" & Mid(FoundFolder, 3, 1024)
CommandString = "xcopy " & CHR(34) & FromFileState & CHR(34) & " " & CHR(34) & ToFileState & "\" & CHR(34) & " /Y"
LocalFile.WriteLine "echo Copying " & FromFileState & " to remote, please wait..."
LocalFile.WriteLine CommandString
LocalFile.WriteLine "Echo ---------------------------------------------------------"
' Take Care of VHD (drive image) and VUD files (undo files) - can be more than one for a Guest...
Set colHardDisks = MoveVM.HardDiskConnections
For Each objDrive in colHardDisks
FromFileVHD = objDrive.HardDisk.File
Set FileFSO = CreateObject("Scripting.FileSystemObject")
Set FileToCheck = FileFSO.GetFile(FromFileVHD)
FoundFolder = FileFSO.GetParentFolderName(FileToCheck)
ToFileVHD = TargetHostServer & "\" & Left(FoundFolder, 1) & "$" & Mid(FoundFolder, 3, 1024)
CommandString = "xcopy " & CHR(34) & FromFileVHD & CHR(34) & " " & CHR(34) & ToFileVHD & "\" & CHR(34) & " /Y"
LocalFile.WriteLine "echo Copying " & FromFileVHD & " to remote, please wait...(big file!)"
LocalFile.WriteLine CommandString
LocalFile.WriteLine "Echo ---------------------------------------------------------"
If MoveVM.Undoable Then
FromFileVUD = objDrive.UndoHardDisk.File
Set FileFSO = CreateObject("Scripting.FileSystemObject")
Set FileToCheck = FileFSO.GetFile(FromFileVUD)
FoundFolder = FileFSO.GetParentFolderName(FileToCheck)
ToFileVUD = TargetHostServer & "\" & Left(FoundFolder, 1) & "$" & Mid(FoundFolder, 3, 1024)
CommandString = "xcopy " & CHR(34) & FromFileVUD & CHR(34) & " " & CHR(34) & ToFileVUD & "\" & CHR(34) & " /Y"
LocalFile.WriteLine "echo Copying " & FromFileVUD & " to remote, please wait..."
LocalFile.WriteLine CommandString
LocalFile.WriteLine "Echo ---------------------------------------------------------"
End If
Next
' Call .VBS to register configuration file and start the VPC image
LocalFile.WriteLine "Echo Calling script to register config file on remote and start VM..."
LocalFile.WriteLine "CScript " & CHR(34) & LocalVBSFile & CHR(34) & " //NoLogo"
LocalFile.WriteLine "Echo End of Batch file"
LocalFile.WriteLine "Echo ---------------------------------------------------------"
LocalFile.Close 'close batch file
' ***********************************************************************************************************************
' ***********************************************************************************************************************
' code to create .VBS to register config file with Target Virtual Server
' ***********************************************************************************************************************
' ***********************************************************************************************************************
Set LocalFSO = CreateObject ("scripting.FileSystemObject")
Set LocalFile = LocalFSO.CreateTextFile(LocalVBSFile)
' start writing .VBS file
' LocalFile.WriteLine "On Error Resume Next"
LocalFile.WriteLine "Set objVS = CreateObject(" & CHR(34) & "VirtualServer.Application" & CHR(34) & ", " & CHR(34) & TargetHostServer & CHR(34) & ")"
LocalFile.WriteLine "errReturn = objVS.RegisterVirtualMachine(" & CHR(34) & subVMName & CHR(34) & "," & CHR(34) & ConfigFolder & CHR(34) & ")"
LocalFile.WriteLine "Set objVM = objVS.FindVirtualMachine(" & CHR(34) & subVMName & CHR(34) & ")"
LocalFile.WriteLine "objVM.Startup()"
LocalFile.Close 'close .VBS file
Set objShell = Wscript.CreateObject("Wscript.Shell")
CommandString = "%comspec% /c " & CHR(34) & LocalBatchFile & CHR(34)
Wscript.Echo VbCrLf & "Command string: " & CommandString
objShell.Run(CommandString)
Wscript.Echo VbCrLf & "End Move Processing"
End Sub