' VMware support script, VBscript version
' Copyright (c) 1998-2021 VMware, Inc.
'  Collects various configuration and log files, the information that this
'  collects is zipped and transferred to the VM's log file using xferlogs

Option Explicit
' On Error Resume Next

Const HKLM = &H80000002
Const COMMON_APPDATA = &H23&
Const USER_APPDATA = &H1A&
Const WINDOWS_DIR = &H24&

' The status constants are important and have to be kept
' in sync with VMware Workstation implementation

' vm-support script is not running
Const VMSUPPORT_NOT_RUNNING = 0
' vm-support script is beginning
Const VMSUPPORT_BEGINNING = 1
' vm-support script running in progress
Const VMSUPPORT_RUNNING = 2
' vm-support script is ending
Const VMSUPPORT_ENDING = 3
' vm-support script failed
Const VMSUPPORT_ERROR = 10
' vm-support collection not supported
Const VMSUPPORT_UNKNOWN = 100

Dim updateMode

Dim transfer

Function ParseArgs
    Dim args, i
    Set args = WScript.Arguments
    If args.Count >= 1 Then
        For i = 0 to (args.Count - 1)
            select case args(i)
                case "-u"
                    updateMode = True
                case "-x"
                    transfer = True
            end select
        Next
    End If
End Function

' Convert and quote a string
Function Quote(strin)
    Dim siz, i, s
    siz = Len(strin)
    For i=1 to siz
        s = s & Chr(Asc(Mid(strin, i, 1)))
    Next
    Quote = Chr(34) & s & Chr(34)
End Function

Class VMsupport

    Private tmpdir, workdir, AppData, UserData, SysTemp, Username, VMTools
    Private WindowsDir
    Private Fso, Wsh, RegObj
    Private szaExe, xferlogs

    Private Sub Class_Initialize()
        Dim sh, desktop, objShell, wshNetwork
        ' Run as administrator to get rid off permission denied issue when copying files
        If WScript.Arguments.Length = 0 Then
            CreateObject("Shell.Application").ShellExecute "wscript.exe",_
                """" & WScript.ScriptFullName & """ RunAsAdministrator", "", "runas", 1
            WScript.Quit
        End If
        Set RegObj=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
                     & ".\root\default:StdRegProv")
        Set Fso = CreateObject("Scripting.FileSystemObject")

        set Wsh = WScript.CreateObject("WScript.Shell")
        set wshNetwork = CreateObject("WScript.Network")
        Username = wshNetwork.Username
        desktop = Wsh.SpecialFolders("Desktop")
        tmpdir = Wsh.Environment("Process").Item("Temp")
        SysTemp = Wsh.Environment("Process").Item("WINDIR") & "\Temp"
        workdir = tmpdir & "\vmsupport-" & Month(Date) _
                         & "-" & Day(Date) & "-" & Year(Date) & "-" _
                         & Hour(Now) & "-" & Minute(Now)
        If Fso.FolderExists(workdir) Then
            Fso.DeleteFolder(workdir)
        End If
        Fso.CreateFolder(workdir)
        Fso.CreateFolder(workdir & "\Misc")
        Fso.CreateFolder(workdir & "\TEMP")
        Fso.CreateFolder(workdir & "\SYSTEMP")
        Fso.CreateFolder(workdir & "\Global_Config")
        Fso.CreateFolder(workdir & "\Current_User")
        Fso.CreateFolder(workdir & "\Customization")
        Fso.CreateFolder(workdir & "\Customization\Panther")
        Fso.CreateFolder(workdir & "\Customization\Panther\UnattendGC")
        Fso.CreateFolder(workdir & "\Customization\Sysprep")
        Set objShell = CreateObject("Shell.Application")
        AppData = objShell.Namespace(COMMON_APPDATA).Self.Path
        UserData = objShell.Namespace(USER_APPDATA).Self.Path
        WindowsDir = objShell.Namespace(WINDOWS_DIR).Self.Path
        szaExe = Left(WScript.ScriptFullName, Len(WScript.ScriptFullName) - _
        Len(WScript.ScriptName)) & "7za.exe"
        xferlogs = Left(WScript.ScriptFullName, Len(WScript.ScriptFullName) - _
        Len(WScript.ScriptName)) & "VMwareXferlogs.exe"
        RegObj.GetStringValue HKLM, "Software\VMware, Inc.\VMware Tools",_
                              "InstallPath", VMTools
    End Sub

    'Updates the VM with the current state
    Sub Update(state)
        If updateMode = True Then
            Wsh.exec(Quote(xferlogs) & " upd " & state)
        End If
    End Sub

    Sub DumpKey(DefKey, Path, filename)
        Dim f1
        Set f1 = fso.CreateTextFile(filename, True, True)
        EnumerateKey DefKey, Path, f1
        f1.Close
    End Sub

    ' Recursively enumerate registry and write it to a file.
    Sub EnumerateKey(DefKey, Path, OutFile)
        dim Keys, Names, types, i, j, value
        OutFile.WriteLine("[" & Path & "]")
        RegObj.EnumValues DefKey, Path, Names, Types
        if not IsNull(Names) and not IsNull(Types) Then
            for i = lbound(types) to ubound(types)
                select case types(i)
                    case 1
                        RegObj.GetStringValue defkey, path, names(i), value
                        If not isnull(names(i)) or not isnull(value) then
                            OutFile.WriteLine  names(i) & "=" & Quote(value)
                        end if
                    case 2
                        RegObj.GetExpandedStringValue defkey, path, names(i), value
                        if not isnull(names(i)) or not isnull(value) then
                            OutFile.WriteLine Quote(names(i)) & "=expand:" & Quote(value)
                        end if
                    case 3
                        RegObj.GetBinaryValue defkey, path, names(i), value
                        for j = lbound(value) to ubound(value)
                            value(j) = hex(cint(value(j)))
                        next
                        if not isnull(names(i)) or not isnull(value) then
                            OutFile.WriteLine Quote(names(i)) &"=hex:"& _
                                              join(value, ",")
                        end if
                    case 4
                        RegObj.GetDWordValue defkey, path, names(i), value
                        if not isnull(names(i)) or value then
                            OutFile.WriteLine Quote(names(i)) & "=dword:" & _
                                              hex(value)
                        end if
                end select
            next
        end if

        OutFile.WriteLine
        RegObj.EnumKey HKLM, Path, Keys
        Dim SubKey, NewPath
        If not IsNull(Keys) Then
            For Each SubKey In Keys
                NewPath = Path & "\" & SubKey
                EnumerateKey DefKey, NewPath,OutFile
            Next
        End if
    End Sub

    ' Run a command and save the output to a file
    Sub RunCmd(cmd, outfile)
        Dim f1, run, output
        Set f1 = fso.CreateTextFile(outfile, True, True)
        set run = Wsh.exec(cmd)
        output = run.stdout.readall
        f1.Write output
        f1.Close
    End Sub

    Sub CopyConfig()
        On Error Resume Next
        Fso.CopyFolder AppData & "\VMware", workdir & "\Global_Config"
        Fso.CopyFolder UserData & "\VMware", workdir & "\Current_User"
        Fso.CopyFile  SysTemp & "\vmware*.log", workdir & "\SYSTEMP\"
        Fso.CopyFile  SysTemp & "\vminst*.log", workdir & "\SYSTEMP\"
        Fso.CopyFile  tmpdir & "\vminst*.log", workdir & "\Temp\"
        Fso.CopyFile  SysTemp & "\vmmsi*.log", workdir & "\SYSTEMP\"
        Fso.CopyFile  tmpdir & "\vmmsi*.log", workdir & "\Temp\"
        Fso.CopyFile  SysTemp & "\*_vcredist_*.log", workdir & "\SYSTEMP\"
        Fso.CopyFile  tmpdir & "\*_vcredist_*.log", workdir & "\Temp\"
        Fso.CopyFile  WindowsDir & "\WindowsUpdate.log", workdir & "\SYSTEMP\"
        ' Contains verbose output of CbSensor MSI installer triggered by cblauncher.exe
        Fso.CopyFile  SysTemp & "\Cbinstall*.log", workdir & "\SYSTEMP\"
        ' Contains CbSensor installation activity logs
        Fso.CopyFile  SysTemp & "\cb-install*.log", workdir & "\SYSTEMP\"
        If (Fso.FileExists(WindowsDir & "\setupapi.log")) Then
           Fso.CopyFile WindowsDir & "\setupapi.log" , workdir & "\SYSTEMP\"
        End If
        If (Fso.FileExists(WindowsDir & "\inf\setupapi.dev.log")) Then
           Fso.CopyFile WindowsDir & "\inf\setupapi.dev.log" , workdir & "\SYSTEMP\"
        End If
        If (Fso.FileExists(WindowsDir & "\inf\setupapi.offline.log")) Then
           Fso.CopyFile WindowsDir & "\inf\setupapi.offline.log" , workdir & "\SYSTEMP\"
        End If
        If (Fso.FileExists(WindowsDir & "\inf\setupapi.app.log")) Then
           Fso.CopyFile WindowsDir & "\inf\setupapi.app.log" , workdir & "\SYSTEMP\"
        End If
        If (Fso.FolderExists(WindowsDir & "\System32\Sysprep\Panther")) Then
           Fso.CopyFolder WindowsDir & "\System32\Sysprep\Panther" , workdir & "\Customization\Sysprep\"
        End If
        If (Fso.FileExists(WindowsDir & "\Panther\unattend.xml")) Then
           Fso.CopyFile  WindowsDir & "\Panther\unattend.xml" , workdir & "\Customization\Panther\"
        End If
        If (Fso.FolderExists(WindowsDir & "\Panther")) Then
           Fso.CopyFile WindowsDir & "\Panther\setup*.log" , workdir & "\Customization\Panther\"
        End If
        If (Fso.FolderExists(WindowsDir & "\Panther\UnattendGC")) Then
           Fso.CopyFile WindowsDir & "\Panther\UnattendGC\setup*.log" , workdir & "\Customization\Panther\UnattendGC\"
        End If
        If (Fso.FolderExists(WindowsDir & "\Debug")) Then
           Fso.CopyFolder WindowsDir & "\Debug" , workdir & "\Customization\"
        End If
        If (Fso.FolderExists(SysTemp & "\vmware-imc")) Then
           Fso.CopyFolder SysTemp & "\vmware-imc" , workdir & "\Customization\"
        End If
        On Error Goto 0
    End Sub

    Sub CopyEventLogs()
        CopyLog "Application", workdir & "\Misc\"
        CopyLog "System", workdir & "\Misc\"
        CopyLog "Security", workdir & "\Misc\"
    End Sub

    ' Copy the specified system event log to the specified directory
    Sub CopyLog(logname, directory)
        ' non-admin users would lack permissions
        On Error Resume Next
        Dim wmiobj, record, txtlog, msg, query

        Set wmiobj = GetObject("winmgmts:{impersonationLevel=impersonate," &_
                               "(Backup,Security)}!\\.\root\cimv2")

        query = "select * from Win32_NTEventLogFile where " &_
                "LogfileName='" & logname & "'"
        For Each record in wmiobj.ExecQuery(query)
            record.BackupEventLog(directory & logname & "-log.evt")
        Next

        '
        ' Query the entries in the log and write a simple text file that
        ' is more easily parseable by scripts, since the evt / evtx format
        ' is completely undocumented. Line format:
        '
        ' [timestamp]:[user]:[source]:[level]:[message]
        '
        ' Any new lines embedded in the messages are replaced by a space.
        ' Carriage returns are removed.
        '
        Set txtlog = Fso.CreateTextFile(directory & logname & "-log.txt", True, True)

        query = "SELECT * FROM Win32_NTLogEvent WHERE Logfile = '" & logname & "'"
        For Each record in wmiobj.ExecQuery(query)
            msg = Replace(record.Message, Chr(10), " ")
            msg = Replace(msg, Chr(13), "")
            txtlog.WriteLine("" &_
               record.TimeGenerated & ":" &_
               record.User & ":" &_
               record.SourceName & ":" &_
               record.EventType & ":" &_
               msg)
        Next
        txtlog.Close

        On Error Goto 0
    End Sub

    Sub CopyPowerManagementScripts
        Fso.CopyFile  VMTools & "\*.bat", workdir & "\Misc\"
    End Sub

    ' Save the MSinfo report, this takes a while and hence not saving text.
    Sub MSInfo
        Dim msinfo
        msinfo = Wsh.RegRead("HKLM\SOFTWARE\Microsoft\Shared Tools\MSInfo\Path")
        Wsh.Run Quote(msinfo) & " /nfo " & workdir & "\Misc\MSinfo.nfo", 0, True
    End Sub

    Sub Service
        Dim fp, wmi, s, Services
        Set fp = Fso.CreateTextFile(workdir & "\Misc\Service.txt", _
                                    True, True)
        Set wmi = GetObject("winmgmts:" _
            & "{impersonationLevel=impersonate}!\\.\root\cimv2")
        Set Services = wmi.ExecQuery _
                ("SELECT * FROM Win32_Service")
        For Each s in Services
            fp.WriteLine "System Name: " & s.SystemName
            fp.WriteLine "Service Name: " & s.Name
            fp.WriteLine "Service Type: " & s.ServiceType
            fp.WriteLine "Service State: " & s.State
            fp.WriteLine "ExitCode: " & s.ExitCode
            fp.WriteLine "Process ID: " & s.ProcessID
            fp.WriteLine "Accept Pause: " & s.AcceptPause
            fp.WriteLine "Accept Stop: " & s.AcceptStop
            fp.WriteLine "Caption: " & s.Caption
            fp.WriteLine "Description: " & s.Description
            fp.WriteLine "Desktop Interact: " & s.DesktopInteract
            fp.WriteLine "Display Name: " & s.DisplayName
            fp.WriteLine "Error Control: " & s.ErrorControl
            fp.WriteLine "Path Name: " & s.PathName
            fp.WriteLine "Started: " & s.Started
            fp.WriteLine "StartMode: " & s.StartMode
            fp.WriteLine "StartName: " & s.StartName
            fp.Writeline
        Next
        fp.Close
    End Sub

    Sub BootIni
        Dim i, bootdrive, bootini
        For i=0 to 23
            bootdrive = Chr(Asc("C")+i)
            bootini = bootdrive & ":\boot.ini"
            If Fso.FileExists(bootini) Then
                On Error Resume Next
		Dim bootinidest, f
		bootinidest = workdir & "\Misc\" & bootdrive & "_boot.ini"
                Fso.CopyFile  bootini, bootinidest

		' Unset the hidden and system bits if set.
		Set f = Fso.GetFile(bootinidest)
		If f.attributes and 4 Then
			f.attributes = f.attributes - 4
		End If
		If f.attributes and 2 Then
			f.attributes = f.attributes - 2
		End If
                ' GetFile would fail if the boot.ini was not copied
                On Error Goto 0
                If bootdrive = "C" Then
                    Exit For
                End If
            End If
        Next
    End Sub

    Sub TimeInfo()
        DumpKey HKLM, "SYSTEM\CurrentControlSet\Services\W32Time", workdir & "\Misc\w32time_reg.txt"
        RunCmd "w32tm /tz", workdir & "\Misc\w32tm_tz.txt"
        RunCmd "w32tm /query /status /verbose", workdir & "\Misc\w32tm_status.txt"
        RunCmd "w32tm /query /configuration /verbose", workdir & "\Misc\w32tm_config.txt"
    End Sub

    Sub Generate()
        Dim currDir
        Update VMSUPPORT_BEGINNING

        Set Fso = CreateObject("Scripting.FileSystemObject")

        DumpKey HKLM, "SOFTWARE\VMware, Inc.", workdir & "\Misc\vmware_reg.txt"
        DumpKey HKLM, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards", workdir & "\Misc\networkcards_reg.txt"
        RunCmd "ipconfig /all", workdir & "\Misc\ipconfig.txt"
        RunCmd "netstat -aens", workdir & "\Misc\netstat.txt"
        RunCmd "route print", workdir & "\Misc\route.txt"
        RunCmd "netsh winsock show catalog", workdir & "\Misc\winsock_catalog.txt"
        CopyPowerManagementScripts
        BootIni
        CopyConfig
        TimeInfo

        'To get Windows 10 readable ETW WindowsUpdate.log
        On Error Resume Next
        Wsh.exec("powershell -command Get-WindowsUpdateLog -LogPath " & workdir & "\SYSTEMP\ps-WindowsUpdate.log")
        On Error Goto 0

        Service

        Update VMSUPPORT_RUNNING

        MSInfo
        CopyEventLogs

        currDir = Wsh.CurrentDirectory
        Wsh.CurrentDirectory = tmpdir
        RunCmd Quote(szaExe) & " a -tzip " & workdir & ".zip " & Fso.GetBaseName(workdir), _
            tmpDir & "\out.txt"
        Fso.DeleteFile tmpDir & "\out.txt", true
        Wsh.CurrentDirectory = currDir

        If transfer = True Then
            Wsh.exec(Quote(xferlogs) & " enc " & workdir & ".zip ")
            Wscript.Echo "Support data is available at " & workdir & ".zip. "_
            & "The same support data has been transferred to the virtual "_
            & "machine's log file, please run vm-support on the host to send "_
            & "the data to VMware support."
        Else
            Wscript.Echo "Support data is available at " & workdir & ".zip. "_
            & "Please upload this file to VMware support if requested."
        End If
        If Fso.FolderExists(workdir) Then
           Fso.DeleteFolder workdir, true
        End If

        Update VMSUPPORT_ENDING

    End Sub

End class

If ScriptEngineMajorVersion < 5 or (ScriptEngineMajorVersion = 5 and ScriptEngineMinorVersion < 6) Then
    Wscript.Echo "This vm-support script expects Windows Script Version 5.6 or above.", _
                 Chr(10), _
                 "Windows Script update can be obtained from:", _
                 Chr(10), _
                 "http://www.microsoft.com/downloads/details.aspx?FamilyId=C717D943-7E4B-4622-86EB-95A22B832CAA&displaylang=en"
    Wscript.quit 0
End If

updateMode = False
transfer = False
'Parse the command line arguments
ParseArgs
Dim info
Set info = new VMsupport
info.Generate
