Option Explicit On Error Resume Next ' ' Author: Jamie Morrison http://theether.net/contact ' ' Purpose: Mount virtual machines in a combination of file and fullvm backups per disk ' ' Revision: 05/05/2009 Initial release ' 28/07/2009 Updated to allow uncompressed VMDK with compressVMDK property ' ' Known Issues: ' VMware Consolidated Backup must be installed. Tested with V1.5. ' Compressed VMDK files must be imported into ESX with vmkfstools -i option Dim vmMounter Set vmMounter = New vmdkMounter 'vmMounter.verbose = True 'vmMounter.compressVMDK = True If vmMounter.isValidCommandLine Then If vmMounter.binariesExist Then If vmMounter.isIpaddr Then vmMounter.enumerateNames End If If vmMounter.isVmRefSet Then If vmMounter.isUnmount Then vmMounter.unmountDrives Else vmMounter.createSnapshot vmMounter.enumerateDiskPaths vmMounter.mountDrives End If End If End If Else vmMounter.displayUseage End If Set vmMounter = Nothing Class vmdkMounter ' ' Purpose: ' ' Public Functions ' ' Private Variables ' ----------------- Private vmwareVcbPath Private vmwareCompressVMDK Private snapshotID Private vmRef Private logVerbose Private wshShell Private fso Private vmName, vmDisk, vmDiskPath, commandLine ' Private Functions ' ----------------- Sub Class_Initialize ' ' SYNTAX: Constructor called on object creation ' ' Parameters: None ' ' Returns: N/A ' ' Example: Set object = New vmdkMounter ' ' Remarks: Requires VMware consolidated backup ' ' Create Objects Set wshShell = Wscript.CreateObject("Wscript.Shell") Set fso = CreateObject("Scripting.FileSystemObject") Set vmName = CreateObject("Scripting.Dictionary") Set vmDisk = CreateObject("Scripting.Dictionary") Set vmDiskPath = CreateObject("Scripting.Dictionary") Set commandLine = CreateObject("Scripting.Dictionary") wshShell.LogEvent 4, "vmdkMounter: [Info]" & vbCrLf & "Starting backup using " & WScript.ScriptFullName ' Initial Values logVerbose = vbFalse snapshotID ="" vmRef = "" vmwareCompressVMDK = vbFalse parseCommandLine() getVcbPath End Sub Private Sub Class_Terminate ' ' SYNTAX: Destructor called on object deletion ' ' Parameters: None ' ' Returns: N/A ' ' Example: Set object = Nothing ' ' Remarks: ' ' Destroy objects Set fso = Nothing Set vmName = Nothing Set vmDisk = Nothing Set vmDiskPath = Nothing Set commandLine = Nothing wshShell.LogEvent 4, "vmdkMounter: [Info]" & vbCrLf & "Completing backup using " & WScript.ScriptFullName Set wshShell = Nothing End Sub Private Function parseCommandLine ' ' SYNTAX: parseCommandLine ' ' Parameters: None ' ' Returns: True if parameters passed, otherwise false ' ' Example: ' ' Remarks: ' Dim commandLineArguments, loopCount, diskCommandLine, diskCount, scsiDisk, mountPath parseCommandLine = vbFalse Set commandLineArguments = WScript.Arguments For loopCount = 0 to commandLineArguments.Count - 1 If (Left(TRIM(commandLineArguments(loopCount)), 1) = "-" ) Then ' Process command line switches parseCommandLine = vbTrue If (commandLineArguments(loopCount) = "-r") OR (commandLineArguments(loopCount) = "-U") Then mountPath = commandLineArguments(loopCount + 1) If (Right(mountPath, 1) <> "\") Then mountPath = mountPath & "\" End If commandLine.Add Trim(commandLineArguments(loopCount)), Trim(mountPath) Else commandLine.Add Trim(commandLineArguments(loopCount)), Trim(commandLineArguments(loopCount + 1)) End If loopCount = loopCount + 1 Else ' Process VMDK diskCommandLine = Split(commandLineArguments(loopCount), ",") For diskCount = 0 to UBound(diskCommandLine) scsiDisk = Split(diskCommandLine(diskCount), ":") If (Len(Trim(scsiDisk(0))) > 0) AND (Len(Trim(scsiDisk(1))) > 0) Then vmDisk.Add Trim(scsiDisk(0)), Trim(scsiDisk(1)) End If Next End If Next If (commandLine.Exists("-s") AND (Len(commandLine.Item("-s")) > 0)) Then vmRef = commandLine.Item("-s") End If End function Private Function getVcbPath ' ' SYNTAX: getVcbPath ' ' Parameters: None ' ' Returns: True if path is set, otherwise false ' ' Example: ' ' Remarks: ' Const VCB_PATH = "HKLM\SOFTWARE\VMware, Inc.\VMware Consolidated Backup\InstallPath" Dim stringValue stringValue = WshShell.RegRead(VCB_PATH) If Err.Number <> 0 Then vmwareVcbPath ="" wshShell.LogEvent 1, "vmdkMounter: [Info]" & vbCrLf & "VCB path not found at " & VCB_PATH getVcbPath = vbFalse Else If (Right(stringValue, 1) <> "\") Then stringValue = stringValue & "\" End If vmwareVcbPath = stringValue If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Info]" & vbCrLf & "VCB installed at " & stringValue getVcbPath = vbTrue End If End function ' Public Variables ' ---------------- Public Property Get verbose verbose = logVerbose End Property Public Property Let verbose(logState) logVerbose = logState End Property Public Property Get compressVMDK compressVMDK = vmwareCompressVMDK End Property Public Property Let compressVMDK(flag) vmwareCompressVMDK = flag End Property Public Property Get vcbPath vcbPath = vmwareVcbPath End Property Public Property Let vcbPath(path) vmwareVcbPath = path End Property ' Public Functions ' ----------------- Public Function isIpaddr ' ' SYNTAX: isIpaddr ' ' Parameters: None ' ' Returns: True if -s ipaddr:server is set, otherwise false ' ' Example: object.isUnmount ' ' Remarks: ' isIpaddr = vbFalse If (commandLine.Exists("-s")) Then If InStr(LCase(commandLine.Item("-s")), "ipaddr") Then If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Info] " & vbCrLf & "Using " & commandLine.Item("-s") isIpaddr = vbTrue End If End If End function Public Function isUnmount ' ' SYNTAX: isUnmount ' ' Parameters: None ' ' Returns: True if -U is specified in the command line, otherwise false ' ' Example: object.isUnmount ' ' Remarks: ' isUnmount = vbFalse If (commandLine.Exists("-U")) Then isUnmount=vbTrue End If End function Public Function isType(backupType) ' ' SYNTAX: isType(backupType) ' ' Parameters: backupType Type of backup to check for (file or fullvm) ' ' Returns: True if type of backup as specified by backupType, otherwise false ' ' Example: object.isType("file") ' ' Remarks: ' Dim backupItem, loopCount isType = vbFalse backupItem = vmDisk.Items For loopCount = 0 to vmDisk.Count - 1 If (InStr(LCase(backupItem(loopCount)), LCase(backupType))) Then If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Info] " & vbCrLf & "Found backup type " & backupItem(loopCount) isType = vbTrue End If Next End function Public Function isValidCommandLine ' ' SYNTAX: isValidCommandLine ' ' Parameters: None ' ' Returns: True if parameters set, otherwise false ' ' Example: object.isValidCommandLine ' ' Remarks: ' isValidCommandLine = vbFalse If ((commandLine.Exists("-h")) AND (commandLine.Exists("-u")) AND (commandLine.Exists("-p")) AND (commandLine.Exists("-s")) AND _ ((commandLine.Exists("-r")) OR (commandLine.Exists("-U")))) Then isValidCommandLine = vbTrue End If End function Public Function isVmRefSet ' ' SYNTAX: isVmRefSet ' ' Parameters: None ' ' Returns: True if vmRef set, otherwise false ' ' Example: object.isVmRefSet ' ' Remarks: ' If (Len(vmRef) > 0) Then isVmRefSet = vbTrue Else isVmRefSet = vbFalse wshShell.LogEvent 1, "vmdkMounter: [Info] " & vbCrLf & "The VM Reference is not set (vmRef)" End If End function Public Function binariesExist ' ' SYNTAX: binariesExist ' ' Parameters: None ' ' Returns: True if vcb binaries exist, otherwise false ' ' Example: object.isVmRefSet ' ' Remarks: ' Dim binary, binaries binariesExist = vbTrue binaries = Array("vcbSnapshot.exe", "mountVM.exe", "vcbVmName.exe") For each binary in binaries If Not (fso.FileExists(vmwareVcbPath & binary)) Then binariesExist = vbFalse wshShell.LogEvent 1, "vmdkMounter: [Info] " & vbCrLf & "Could not find: " & vbCrLf & vmwareVcbPath & binary End If Next End function Public Function enumerateNames ' ' SYNTAX: enumerateNames ' ' Parameters: None ' ' Returns: True if vcbVMName returns values, otherwise false ' ' Example: ' ' Remarks: ' Dim cmdExec, wshExec, wshExecOut, wshExecLine, wshExecName If (commandLine.Exists("-s")) Then cmdExec = vmwareVcbPath & "vcbVmName -L 0 -h " & commandLine.Item("-h") & " -u " & commandLine.Item("-u") & " -p " & _ commandLine.Item("-p") & " -s " & commandLine.Item("-s") If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll Else Do While Not wshExec.StdOut.AtEndOfStream wshExecLine = wshExec.StdOut.ReadLine() If (Left(wshExecLine, 5) = "moref") OR (Left(wshExecLine, 4) = "name") OR (Left(wshExecLine, 4) = "uuid") OR _ (Left(wshExecLine, 6) = "ipaddr") Then wshExecName = Split(wshExecLine, ":") If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExecName(0) & "=" & wshExecName(1) vmName.Add wshExecName(0), wshExecName(1) End If Loop End If End If If ((isIpaddr) AND Len(vmName.Item("moref")) > 0) Then vmRef = "moref:" & vmName.Item("moref") Else vmRef = "" End If End function Public Function createSnapshot ' ' SYNTAX: createSnapshot ' ' Parameters: None ' ' Returns: True if vcbSnapshot successful, otherwise false ' ' Example: objetc.createSnapshot ' ' Remarks: ' Dim cmdExec, wshExec, wshExecOut, wshExecLine, wshStdOut createSnapshot = vbFalse cmdExec = vmwareVcbPath & "vcbSnapshot -L 0 -h " & commandLine.Item("-h") & " -u " & commandLine.Item("-u") & " -p " & _ commandLine.Item("-p") & " -c " & vmRef & " _VCB-BACKUP_ " & CHR(34) & now() & CHR(34) If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll Else Do While Not wshExec.StdOut.AtEndOfStream wshExecLine = wshExec.StdOut.ReadLine() wshStdOut = wshStdOut & wshExecLine & vbCrLf If (InStr(wshExecLine, "SsId:")) Then snapshotID = mid(wshExecLine, InStr(wshExecLine, "SsId:") + 5) If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Info] " & vbCrLf & "Snapshot ID = " & snapshotID createSnapshot = vbTrue End If Loop If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshStdOut End If End function Public Function enumerateDiskPaths ' ' SYNTAX: enumerateDiskPaths ' ' Parameters: None ' ' Returns: True if vcbSnapshot returns paths, otherwise false ' ' Example: object.enumerateDiskPaths ' ' Remarks: ' Dim cmdExec, wshExec, wshExecOut, wshExecLine, wshExecPath, wshStdOut enumerateDiskPaths = vbFalse cmdExec = vmwareVcbPath & "vcbSnapshot -L 0 -h " & commandLine.Item("-h") & " -u " & commandLine.Item("-u") & " -p " & _ commandLine.Item("-p") & " -l " & vmRef & " SsId:" & snapshotID If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll Else Do While Not wshExec.StdOut.AtEndOfStream wshExecLine = wshExec.StdOut.ReadLine() wshStdOut = wshStdOut & wshExecLine & vbCrLf If (LCase(Left(wshExecLine, 4)) = "scsi") Then wshExecPath = split(wshExecLine, ":") vmDiskPath.Add wshExecPath(0), wshExecPath(1) If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExecPath(0) &" = " & wshExecPath(1) enumerateDiskPaths = vbTrue End If Loop If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshStdOut End If End function Public Function mountDrives ' ' SYNTAX: mountDrives ' ' Parameters: None ' ' Returns: True if vcbSnapshot returns paths, otherwise false ' ' Example: object.mountDrives ' ' Remarks: ' Dim diskKey, diskPath, unmountFile, vmdkCompress, vmdkFlatFile, loopCount, cmdExec, wshExec, wshExecOut, wshExecLine, wshStdOut mountDrives = vbTrue If Not (fso.FolderExists(commandLine.Item("-r"))) Then fso.CreateFolder(commandLine.Item("-r")) End If If (vmwareCompressVMDK) Then vmdkCompress = "-F 0" Else vmdkCompress = "-F 1" End If ' Mount VMDK's for fullVM backup diskKey = vmDisk.Keys For loopCount = 0 to vmDisk.Count - 1 If (vmDisk.Item(diskKey(loopCount)) = "fullvm") Then diskPath = split(vmDiskPath.Item(diskKey(loopCount)), "/") If (fso.FileExists(commandLine.Item("-r") & "vmdk\" & diskPath(1))) Then wshShell.LogEvent 4, "vmdkMounter: [Info] Deleting " & commandLine.Item("-r") & "vmdk\" & diskPath(1) fso.DeleteFile commandLine.Item("-r") & "vmdk\" & diskPath(1), vbTrue End If vmdkFlatFile = Replace(commandLine.Item("-r") & "vmdk\" & diskPath(1), ".vmdk", "-flat.vmdk") If (fso.FileExists(vmdkFlatFile)) Then wshShell.LogEvent 4, "vmdkMounter: [Info] Deleting " & vmdkFlatFile fso.DeleteFile vmdkFlatFile, vbTrue End If cmdExec = vmwareVcbPath & "vcbExport -M 1 " & vmdkCompress & " -d " & commandLine.Item("-r") & "vmdk\" & diskPath(1) & _ " -s " & CHR(34) & "blklst://" & snapshotID & vmDiskPath.Item(diskKey(loopCount)) & "@" & _ commandLine.Item("-h") & "?" & commandLine.Item("-u") & "/" & commandLine.Item("-p") & CHR(34) If Not (fso.FolderExists(commandLine.Item("-r") & "vmdk")) Then fso.CreateFolder(commandLine.Item("-r") & "vmdk") End If If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll mountDrives = vbFalse Else If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExec.StdOut.ReadAll End If End If Next If (isType("file")) Then ' Write unmount info Set unmountFile = fso.OpenTextFile(commandLine.Item("-r") & "unmount.dat", 8, vbTrue) unmountFile.WriteLine(snapshotID) unmountFile.Close ' Mount VMDK's for file backup diskKey = vmDisk.Keys cmdExec = vmwareVcbPath & "mountVM -cycleId " If (vmDisk.Item("scsi0.0") <> "file") Then ' Always add system drive for determining drive letters diskPath = split(vmDiskPath.Item("scsi0.0"), "/") cmdExec = cmdExec & " -d " & CHR(34) & "blklst://" & snapshotID & vmDiskPath.Item("scsi0.0") & "@" & _ commandLine.Item("-h") & "?" & commandLine.Item("-u") & "/" & commandLine.Item("-p") & CHR(34) End If For loopCount = 0 to vmDisk.Count - 1 If (vmDisk.Item(diskKey(loopCount)) = "file") Then diskPath = split(vmDiskPath.Item(diskKey(loopCount)), "/") cmdExec = cmdExec & " -d " & CHR(34) & "blklst://" & snapshotID & vmDiskPath.Item(diskKey(loopCount)) & _ "@" & commandLine.Item("-h") & "?" & commandLine.Item("-u") & "/" & commandLine.Item("-p") & CHR(34) End If Next cmdExec = cmdExec & " " & commandLine.Item("-r") & "file" If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll mountDrives = vbFalse Else If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExec.StdOut.ReadAll End If Else cmdExec = vmwareVcbPath & "vcbSnapshot -L 0 -h " & commandLine.Item("-h") & " -u " & commandLine.Item("-u") & _ " -p " & commandLine.Item("-p") & " -d " & vmRef & " SsId:" & snapshotID If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll mountDrives = vbFalse Else If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExec.StdOut.ReadAll End If End If End function Public Function unmountDrives ' ' SYNTAX: unmountDrives ' ' Parameters: None ' ' Returns: True if unmount successful, otherwise false ' ' Example: ' ' Remarks: ' Dim cmdExec, wshExec, unmountFile, unmountLine unmountDrives = vbTrue cmdExec = vmwareVcbPath & "mountVM -f -u " & commandLine.Item("-U") & "file" If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll unmountDrives = vbFalse Else wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExec.StdOut.ReadAll End If Set unmountFile = fso.OpenTextFile(commandLine.Item("-U") & "unmount.dat", 1, vbTrue) Do While unmountFile.AtEndOfStream <> True unmountLine = Trim(unmountFile.ReadLine) cmdExec = vmwareVcbPath & "vcbSnapshot -L 0 -h " & commandLine.Item("-h") & " -u " & commandLine.Item("-u") & _ " -p " & commandLine.Item("-p") & " -d " & vmRef & " SsId:" & unmountLine If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Command] " & vbCrLf & cmdExec Set wshExec = wshShell.Exec(cmdExec) If (Len(Trim(wshExec.StdErr.ReadAll)) > 0) Then wshShell.LogEvent 1, "vmdkMounter: [Result] " & vbCrLf & "Exit Code: " & wshExec.ExitCode & vbCrLf & _ wshExec.StdOut.ReadAll & vbCrLf & wshExec.StdErr.ReadAll unmountDrives = vbFalse Else If logVerbose Then wshShell.LogEvent 4, "vmdkMounter: [Result] " & vbCrLf & wshExec.StdOut.ReadAll End If Loop unmountFile.Close fso.DeleteFile commandLine.Item("-U") & "unmount.dat", vbTrue End function Public Function displayUseage ' ' SYNTAX: displayUseage ' ' Parameters: None ' ' Returns: None ' ' Example: ' ' Remarks: ' wscript.echo "Useage: cscript //nologo vmdkMounter.vbs -h -u -p -s -r -U " wscript.echo "" wscript.echo "Note:" wscript.echo " -s valid naming conventions:" wscript.echo " ipaddr:vm.domain.com" wscript.echo " moref:vm-99" wscript.echo "" wscript.echo " If moref is used virtual machine does not require" wscript.echo " registration/VMware Tools" wscript.echo "" wscript.echo " comma seperated list of diskes and backup types" wscript.echo " " wscript.echo " type is fullvm or file" wscript.echo " disk is virtual device node" wscript.echo " e.g. scsi0.0:fullvm,scsi0.1:file" wscript.echo "" wscript.echo " Requires VCB installed and configured" wscript.echo "" wscript.echo " Unmount (-U) only required if file type backup is done on any disk" wscript.echo "" wscript.echo " C: will always be mounted if file type backup is done on any disk," wscript.echo " to determine drive letters" wscript.echo "" wscript.echo " Events written to the application event log" wscript.echo "" wscript.echo "e.g. Mount C: as fullVM, mount D: as file" wscript.echo " cscript //nologo vmdkMounter.vbs -h virtualcenter -u username -p password -r D:\mnt\server -s ipaddr:server.domain.com scsi0.0:fullvm,scsi0.1:file" wscript.echo "" wscript.echo "e.g. Unmount above backup" wscript.echo " cscript //nologo vmdkMounter.vbs -h virtualcenter -u username -p password -U D:\mnt\server -s ipaddr:server.domain.com" wscript.echo "" End function End Class