### To Modify as of January 27 2025

### let's start thinking about the write-log -TaskCategory "On-boarding" or "Off-boarding"
### need RGB color codes form john, once we picked the RGBA colors
### add the .net silent install tweaks to toolkit
### for the reg tweak need to do/undo function maybe it should have its own check box list
### added offboard check boxes for dattormm, dattodeb, rocketcyber, cyberQP, SVSHelpdesk and Splashtop
### need to fix path in the uninstall-DattoEDR -
####### ❌ [Error] [GeneralTask] Uninstallation command 'C:\Program Files\Infocyte\Agent\agent.exe' not found. (Event ID: 3000) - bad path

# ---------------------------------------------------------------------------
# 1) CREATE A GLOBAL LOG CACHE (NEW)
# ---------------------------------------------------------------------------
if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) {
    $Global:LogCache = New-Object System.Collections.ArrayList
}

#region Write-LogHelper
if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction SilentlyContinue)) {
    function Write-LogHelper {
        param (
            [string]$Message,
            [ValidateSet("Info", "Warning", "Error", "Success", "General")]
            [string]$Level = "Info",
            [string]$TaskCategory = "GeneralTask",
            [switch]$LogToEvent = $false,
            [string]$EventSource = "SVSMSP_Module",
            [string]$EventLog = "Application",
            [int]$CustomEventID
        )
        $EventID = switch ($Level) {
            "Info"    { 1000 }
            "Warning" { 2000 }
            "Error"   { 3000 }
            "Success" { 4000 }
            "General" { 1000 }
        }
        $Icon = switch ($Level) {
            "Info"    { [System.Char]::ConvertFromUtf32(0x1F4CB) }
            "Warning" { ([char]0x26A0) }
            "Error"   { ([char]0x274C) }
            "Success" { ([char]0x2705) }
            "General" { ([char]0x1F4E6) }
        }
        $Color = switch ($Level) {
            "Info"    { "Cyan" }
            "Warning" { "Yellow" }
            "Error"   { "Red" }
            "Success" { "Green" }
            "General" { "White" }
        }
        $logEntry = [PSCustomObject]@{
            Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
            Level     = $Level
            Message   = "$Icon [$Level] [$TaskCategory] $Message (Event ID: $EventID)"
        }
        [void]$Global:LogCache.Add($logEntry)
        if ($LogToEvent) {
            $EntryType = switch ($Level) {
                "Info"    { "Information" }
                "Warning" { "Warning" }
                "Error"   { "Error" }
                default   { "Information" }
            }
            try {
                if (-not (Get-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue)) {
                    New-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue
                }
                $EventMessage = "TaskCategory: $TaskCategory | Message: $Message"
                Write-EventLog -LogName $EventLog -Source $EventSource -EntryType $EntryType -EventId $EventID -Message $EventMessage
            }
            catch {
                Write-Host "([char]0x26A0) [Warning] [EventLog] Failed to write to Event Log: $($_.Exception.Message)" -ForegroundColor Yellow
            }
        }
    }
    function Write-LogHybrid {
        param (
            [string]$Message,
            [ValidateSet("Info", "Warning", "Error", "Success", "General")]
            [string]$Level = "Info",
            [string]$TaskCategory = "GeneralTask",
            [switch]$LogToEvent = $false,
            [string]$EventSource = "SVSMSP_Module",
            [string]$EventLog = "Application",
            [int]$CustomEventID
        )
        Write-LogHelper -Message $Message -Level $Level -TaskCategory $TaskCategory `
                        -LogToEvent:$LogToEvent -EventSource $EventSource -EventLog $EventLog `
                        -CustomEventID $CustomEventID
    }
}
else {
    function Write-LogHybrid {
        param (
            [string]$Message,
            [ValidateSet("Info", "Warning", "Error", "Success", "General")]
            [string]$Level = "Info",
            [string]$TaskCategory = "GeneralTask",
            [switch]$LogToEvent = $false,
            [string]$EventSource = "SVSMSP_Module",
            [string]$EventLog = "Application",
            [int]$CustomEventID
        )
        Write-Log -Message $Message -Level $Level -TaskCategory $TaskCategory `
                  -LogToEvent:$LogToEvent -EventSource $EventSource -EventLog $EventLog `
                  -CustomEventID $CustomEventID
    }
}
Write-LogHybrid -Message "Starting SVS TaskGate" -Level "Info" -TaskCategory "SVSTaskGate" -LogToEvent:$true
#endregion

#region Install-DattoRMM-Helper
function Install-DattoRMM-Helper {
    param (
        [string]$ApiUrl,
        [string]$ApiKey,
        [string]$ApiSecretKey,
        [switch]$FetchSitesOnly,
        [string]$SiteName,
        [string]$SiteUID
    )
    if (-not $ApiUrl -or -not $ApiKey -or -not $ApiSecretKey) {
        Write-LogHybrid -Message "Missing required parameters. Please provide ApiUrl, ApiKey, and ApiSecretKey." -Level "Error" -LogToEvent
        return
    }
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    Write-LogHybrid -Message "Fetching OAuth token..." -Level "Info"
    try {
        $securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force
        $apiGenToken = Invoke-WebRequest -Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword)) `
            -Uri ('{0}/auth/oauth/token' -f $ApiUrl) `
            -Method 'POST' `
            -ContentType 'application/x-www-form-urlencoded' `
            -Body ('grant_type=password&username={0}&password={1}' -f $ApiKey, $ApiSecretKey) `
            | ConvertFrom-Json
        $requestToken = $apiGenToken.access_token
        Write-LogHybrid -Message "OAuth token fetched successfully." -Level "Success" -LogToEvent
    } catch {
        Write-LogHybrid -Message "Failed to fetch OAuth token. Details: $($_.Exception.Message)" -Level "Error" -LogToEvent
        return
    }
    $getHeaders = @{"Authorization" = "Bearer $requestToken"}
    if ($FetchSitesOnly) {
        Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan
        try {
            $getHeaders = @{"Authorization" = "Bearer $requestToken" }
            $getSites = Invoke-WebRequest -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers $getHeaders -ContentType "application/json"
            $sitesJson = $getSites.Content | ConvertFrom-Json
            $siteList = $sitesJson.sites | ForEach-Object {
                [PSCustomObject]@{
                    Name = $_.name
                    UID  = $_.uid
                }
            }
            Write-Host "Successfully fetched list of sites." -ForegroundColor Green
            return $siteList
        }
        catch {
            Write-Host "Failed to fetch sites from the API. Details: $($_.Exception.Message)" -ForegroundColor Red
            return
        }
    }
}
#endregion

#region LastPass Extensions
function ForceInstall-LastPassChrome {
    # Chrome (Web Store) extension ID and update URL for LastPass
    $ExtensionID_LastPass_Chrome = "hdokiejnpimakedhajhdlcegeplioahd"
    $ChromeUpdateURL = "https://clients2.google.com/service/update2/crx"
    $ChromePolicyRegPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
    try {
        New-Item -Path "HKLM:\SOFTWARE\Policies\Google" -Force -ErrorAction SilentlyContinue | Out-Null
        New-Item -Path "HKLM:\SOFTWARE\Policies\Google\Chrome" -Force -ErrorAction SilentlyContinue | Out-Null
        New-Item -Path $ChromePolicyRegPath -Force -ErrorAction SilentlyContinue | Out-Null
        $chromeValue = "$ExtensionID_LastPass_Chrome;$ChromeUpdateURL"
        Set-ItemProperty -Path $ChromePolicyRegPath -Name "1" -Value $chromeValue -ErrorAction Stop
        Write-Host "Successfully configured LastPass in Chrome ExtensionInstallForcelist."
    }
    catch {
        Write-Host "Failed to configure Chrome: $($_.Exception.Message)" -ForegroundColor Red
    }
}

function ForceInstall-LastPassEdge {
    # Edge (Add-ons Store) extension ID and update URL for LastPass
    $ExtensionID_LastPass_Edge = "bbcinlkgjjkejfdpemiealijmmooekmp"
    $EdgeUpdateURL = "https://edge.microsoft.com/extensionwebstorebase/v1/crx"
    $EdgePolicyRegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist"
    try {
        New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft" -Force -ErrorAction SilentlyContinue | Out-Null
        New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Edge" -Force -ErrorAction SilentlyContinue | Out-Null
        New-Item -Path $EdgePolicyRegPath -Force -ErrorAction SilentlyContinue | Out-Null
        $edgeValue = "$ExtensionID_LastPass_Edge;$EdgeUpdateURL"
        Set-ItemProperty -Path $EdgePolicyRegPath -Name "1" -Value $edgeValue -ErrorAction Stop
        Write-Host "Successfully configured LastPass in Edge ExtensionInstallForcelist."
    }
    catch {
        Write-Host "Failed to configure Edge: $($_.Exception.Message)" -ForegroundColor Red
    }
}

function Install-LastPassExtensions {
    param(
        [switch]$Chrome,
        [switch]$Edge
    )
    if ($Chrome) { ForceInstall-LastPassChrome }
    if ($Edge)   { ForceInstall-LastPassEdge }
}
#endregion

#region SVS Module
function Install-SVSMSP {
    param (
        [switch]$Cleanup,
        [switch]$InstallToolkit,
        [Parameter(Mandatory = $false)]
        [array]$AllModules = @(
            @{ ModuleName = "SVS_Toolkit" },
            @{ ModuleName = "SVSMSP" }
        ),
        [Parameter(Mandatory = $false)]
        [string]$NewModuleName = "SVSMSP",
        [Parameter(Mandatory = $false)]
        [array]$AllRepositories = @(
            @{ RepoName = "SVS_Repo" },
            @{ RepoName = "SVS_Toolkit" }
        ),
        [Parameter(Mandatory = $false)]
        [string]$NewRepositoryName = "SVS_Repo",
        [Parameter(Mandatory = $false)]
        [string]$NewRepositoryURL = "http://proget.svstools.ca:8083/nuget/SVS_Repo/",
        [Parameter(Mandatory = $false)]
        [array]$CommandsToCheck = @(
            "Install-DattoRMM",
            "Install-CyberQP",
            "Install-RocketCyber",
            "Install-Splashtop",
            "Install-ThreatLocker",
            "Install-SVSHelpdesk"
        ),
        [Parameter(Mandatory = $false)]
        [string]$LogFilePath = "$env:SVSMSP\svstoolkit.log"
    )
    function Perform-Cleanup {
        Write-LogHybrid -Message "Cleanup mode enabled. Starting cleanup process..." -Level "Info" -LogToEvent 
        Write-LogHybrid -Message "Starting cleanup of old modules..." -Level "Info" -LogToEvent
        foreach ($module in $AllModules) {
            $ModuleName = $module.ModuleName
            if (Get-Module -Name $ModuleName -ListAvailable) {
                Write-LogHybrid -Message "Removing module '$ModuleName'..." -Level "Warning" -LogToEvent
                try {
                    Get-Module -Name $ModuleName -ListAvailable | ForEach-Object {
                        Uninstall-Module -Name $_.Name -AllVersions -Force
                    }
                    Write-LogHybrid -Message "Module '$ModuleName' removed successfully." -Level "Success" -LogToEvent
                }
                catch {
                    Write-LogHybrid -Message "Failed to remove module '$ModuleName'. Error: $($_.Exception.Message)" -Level "Error" -LogToEvent
                }
            }
            else {
                Write-LogHybrid -Message "Module '$ModuleName' not found. Skipping..." -Level "Info" -LogToEvent
            }
        }
        Write-LogHybrid -Message "Starting cleanup of old repositories..." -Level "Info" -LogToEvent
        foreach ($repo in $AllRepositories) {
            $RepoName = $repo.RepoName
            Write-LogHybrid -Message "Removing repository '$RepoName'..." -Level "Warning" -LogToEvent
            if (Get-PSRepository -Name $RepoName -ErrorAction SilentlyContinue) {
                try {
                    Unregister-PSRepository -Name $RepoName -ErrorAction Stop
                    Write-LogHybrid -Message "Repository '$RepoName' removed successfully." -Level "Success" -LogToEvent
                }
                catch {
                    Write-LogHybrid -Message "Failed to remove repository '$RepoName'. Error: $($_.Exception.Message)" -Level "Error" -LogToEvent
                }
            }
            else {
                Write-LogHybrid -Message "Repository '$RepoName' does not exist. Skipping removal." -Level "Info" -LogToEvent
            }
        }
        Write-LogHybrid -Message "Cleanup process completed successfully." -Level "Success" -LogToEvent 
    }
    function Perform-ToolkitInstallation {
        Perform-Cleanup
        $localMachineExecutionPolicy = Get-ExecutionPolicy -Scope LocalMachine
        if ($localMachineExecutionPolicy -ne "RemoteSigned") {
            Write-LogHybrid -Message "Setting execution policy to RemoteSigned..." -Level "Warning" -LogToEvent 
            try {
                Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
                Write-LogHybrid -Message "Execution policy set to RemoteSigned successfully." -Level "Success" -LogToEvent 
            }
            catch {
                Write-LogHybrid -Message "Failed to set execution policy. Error: $_" -Level "Error" -LogToEvent 
                return
            }
        }
        Install-PackageProvider -Name "NuGet" -Force -Scope AllUsers -Confirm:$false
        Write-LogHybrid -Message "Registering the new repository '$NewRepositoryName'..." -Level "Info" -LogToEvent
        try {
            if (!(Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) {
                Register-PSRepository -Name $NewRepositoryName -SourceLocation $NewRepositoryURL -InstallationPolicy Trusted
                Write-LogHybrid -Message "Repository '$NewRepositoryName' registered successfully." -Level "Success" -LogToEvent
            }
        }
        catch {
            Write-LogHybrid -Message "Failed to register new repository '$NewRepositoryName'. Error: $($_.Exception.Message)" -Level "Error" -LogToEvent
        }
        Write-LogHybrid -Message "Installing the new module '$NewModuleName'..." -Level "Info" -LogToEvent
        try {
            Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force
            Write-LogHybrid -Message "Module '$NewModuleName' installed successfully." -Level "Success" -LogToEvent
        }
        catch {
            Write-LogHybrid -Message "Failed to install new module '$NewModuleName'. Error: $($_.Exception.Message)" -Level "Error" -LogToEvent
        }
        Write-LogHybrid -Message "Toolkit installation process completed successfully." -Level "Success" -LogToEvent 
    }
    Write-LogHybrid -Message "Install-SVSMSP function started." -Level "Info" -LogToEvent 
    if ($Cleanup) {
        Perform-Cleanup
        return
    }
    if ($InstallToolkit) {
        Perform-ToolkitInstallation
        return
    }
    Write-LogHybrid -Message "No specific mode specified. Defaulting to toolkit installation mode..." -Level "Info" -LogToEvent
    Perform-ToolkitInstallation
}
#endregion SVS Module

#region HTTP Listener Setup
try {
    $listener = New-Object System.Net.HttpListener
    if (-not $listener) {
        throw "Failed to initialize HttpListener."
    }
    $listener.Prefixes.Add("http://localhost:8081/")
    Write-LogHybrid -Message "Listener initialized with prefix http://localhost:8081/" -Level "Info"
    $listener.Start()
    Write-LogHybrid -Message "Listener started successfully." -Level "Info"
} catch {
    Write-LogHybrid -Message "Critical error initializing listener: $($_.Exception.Message)" -Level "Error"
    throw $_
}
#endregion

function Get-N8nWebhookData {
    param (
        [Parameter(Mandatory = $true)]
        [string]$AuthHeaderValue
    )
    $url = "https://automate.svstools.ca/webhook/svsmspkit"
    $headers = @{
        "SVSMSPKit" = $AuthHeaderValue
    }
    try {
        $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
        Write-Host "Response received successfully:" -ForegroundColor Green
        $data = $response
        $global:Comment_SVSmodule   = $data._Comment_SVSmodule
        $global:ModuleName          = $data.ModuleName
        $global:RepositoryURL       = $data.RepositoryURL
        $global:OldRepo             = $data.OldRepo
        $global:NewRepo             = $data.NewRepo
        $global:CommandsToCheck     = $data.CommandsToCheck
        $global:LogFilePath         = $data.LogFilePath
        $global:Comment_DRMM        = $data._Comment_DRMM
        $global:ApiUrl              = $data.ApiUrl
        $global:ApiKey              = $data.ApiKey
        $global:ApiSecretKey        = $data.ApiSecretKey
    }
    catch {
        Write-Host "Error making the GET request:" -ForegroundColor Red
        Write-Host $_.Exception.Message
        return $null
    }
}

#region HTML Content
function GetHtmlContent {
    @"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVS TaskGate</title>
    <link rel="icon" href="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_Favicon.ico" type="image/x-icon">
    <style>
          :root {
            /* Cool Palette */
            --background-color: rgba(18, 18, 18, 1);
            --border-color: rgba(255,  127, 0, 0.25);
            /* Neutral Colors */
            --white-color: rgba(255, 255, 255);
            --gray-color: rgba(102, 102, 102);
            --dark-gray-color: rgba(51, 51, 51);
            --light-gray-color: rgba(187, 187, 187);
            /* Sidebar Button Colors */
            --btn-sidebar-light-gray: rgba(68, 68, 68);
            --btn-sidebar-blue: rgba(30, 144, 255, 1);
            --btn-hover: rgba(0, 86, 179, 1);
            --btn-hover-scale: 1.05;
            /* Button Colors */
            --btn-success: rgba(40, 167, 69);
            --btn-success-disabled: rgba(108, 117, 125);
            --btn-danger: rgba(220, 53, 69);
        }
    
    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: var(--background-color);
        color: var(--white-color);
        height: 100%;
        overflow: hidden;
    }
    
    .logo-container {
        text-align: left;
        padding: 20px;
        background-color: var(--background-color);
    }
    
    .logo-container img {
        max-width: 300px;
        height: auto;
    }
    
    .subtitle {
        font-size: 1.2rem;
        color: var(--gray-color);
        margin-top: 0.5em;
    }
    
    .container {
        display: flex;
        height: 100vh;
        overflow: hidden;
    }
    
    .sidebar {
        width: 200px;
        height: 100%;
        background-color: var(--background-color);
        padding: 10px;
    }
    
    .sidebar button {
        display: block;
        width: 100%;
        margin-bottom: 10px;
        padding: 10px;
        color: var(--white-color);
        background-color: var(--btn-sidebar-light-gray);
        border: none;
        border-radius: 5px;
        cursor: pointer;
        text-align: left;
        transition: background-color 0.3s ease, transform 0.2s ease;
    }
    
    .sidebar button.active {
        background-color: var(--btn-sidebar-blue);
    }
    
    .sidebar button:hover {
        background-color: var(--btn-hover);
        transform: scale(var(--btn-hover-scale));
    }
    
    .content {
        flex: 1;
        padding: 20px;
        overflow-y: auto;
        max-height: calc(100vh - 50px);
    }
    
    .tab-content {
        display: none;
    }
    
    .tab-content.active {
        display: block;
    }
    
    .checkbox-group label {
        margin: 0;
        padding: 0;
        line-height: 1.5;
        display: flex;
        align-items: center;
    }
    
    .password-input,
    .dropdown {
        width: 30%;
        padding: 10px;
        margin-bottom: 20px;
        border-radius: 5px;
        border: 1px solid var(--border-color);
        background-color: var(--background-color);
        color: var(--white-color);
    }
    
    #n8nPasswordContainer {
        display: none;
        margin-top: 20px;
    }
    
    .button-group {
        margin-top: 20px;
        text-align: right;
    }
    
    .button-group button {
        padding: 10px 20px;
        margin-left: 10px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
    }
    
    .install-button {
        background-color: var(--btn-success);
        color: var(--white-color);
    }
    
    .install-button:disabled {
        background-color: var(--btn-success-disabled);
        cursor: not-allowed;
    }
    
    .exit-button {
        background-color: var(--btn-danger);
        color: var(--white-color);
    }
    
    .columns-container {
        display: flex;
        justify-content: center;
        gap: 20px;
        align-items: flex-start;
        padding: 0;
    }
    
    .column {
        width: 48%;
        border: 2px solid var(--border-color);
        border-radius: 8px;
        padding: 10px;
        background-color: var(--background-color);
        box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.3);
        margin: 0;
    }
    
    .log {
        width: 80%;
        margin-top: 20px;
        padding: 10px;
        background-color: var(--dark-gray-color);
        color: var(--light-gray-color);
        border-radius: 5px;
        max-height: 500px;
        overflow-y: auto;
    }
    
    @media (max-width: 768px) {
        .container {
            flex-direction: column;
        }
        .sidebar {
            width: 100%;
        }
    }
    
    </style>
</head>
<body>
     <div class="logo-container">
        <img src="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_logo.svg" alt="SVS Logo">
    </div>
    <div class="container">
        <div class="sidebar">
            <button class="tab-button active" data-tab="onboardTab" aria-expanded="true">On-Boarding</button>
            <button class="tab-button" data-tab="offboardTab" aria-expanded="false">Off-Boarding</button>
            <button class="tab-button" data-tab="tweaksTab" aria-expanded="false">Tweaks</button>
            <button class="tab-button" data-tab="SVSAppsTab" aria-expanded="false">SVS APPs</button>
        </div>
        <div class="content">
            <!-- On-Boarding Tab -->
            <div id="onboardTab" class="tab-content active">
                <h2>On-Boarding</h2>
                <h3 class="subtitle">This new deployment method ensures everything is successfully deployed with greater ease!</h3>
                <div class="columns-container">
                    <div class="checkbox-group column" id="leftColumn">
                       <h3 style="font-size: 1.5rem; font-weight: bold;">SVSMSP Stack</h3>
                        <label>
                            <input type="checkbox" id="selectAllLeftCheckbox" onclick="toggleLeftColumnCheckboxes(this)">
                            Select All
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="setSVSPowerplan" id="SetSVSPowerplanCheckbox">
                            Set SVS Powerplan
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installSVSMSPModule" id="installSVSMSPModuleCheckbox">
                            Install SVSMSP Module
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installCyberQP" id="installCyberQPCheckbox">
                            Install CyberQP
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installSplashtop" id="installSplashtopCheckbox">
                            Install Splashtop
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installSVSHelpDesk" id="installSVSHelpDeskCheckbox">
                            Install SVSHelpDesk
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installThreatLocker" id="installThreatLockerCheckbox">
                            Install ThreatLocker
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installRocketCyber" id="installRocketCyberCheckbox">
                            Install RocketCyber
                        </label>
                        <label>
                            <input type="checkbox" class="left-checkbox" name="installDattoRMM" id="installDattoRMMCheckbox"
                                onclick="toggleDattoRMMOptions()">
                            Install DattoRMM
                        </label>
                        <div id="dattoRMMOptionsContainer" style="display:none; padding-left: 20px;">
                            <label>
                                <input type="checkbox" class="left-checkbox" name="dattoRMMOption" value="inputVar">
                                Copy Site Variables
                            </label>
                            <label>
                                <input type="checkbox" class="left-checkbox" name="dattoRMMOption" value="rmm">
                                Install DRMM Agent
                            </label>
                            <label>
                                <input type="checkbox" class="left-checkbox" name="dattoRMMOption" value="exe">
                                Download.exe
                            </label>
                            <br><br>
                        </div>
                    </div>
                    <div class="checkbox-group column" id="rightColumn" >
                        <h3 style="font-size: 1.5rem; font-weight: bold;">Optional</h3>
                        <label>
                            <input type="checkbox" class="right-checkbox" name="EnableBitLocker" id="EnableBitLockerCheckbox">
                            Enable Bitlocker
                        </label>
                        <label>
                            <input type="checkbox" class="right-checkbox" name="setedgedefaultsearch" id="setedgedefaultsearchCheckbox">
                            Set Edge Default Search Engine
                        </label>
                    </div>
            </div>
                <div id="n8nPasswordContainer" style="display: none;">
                    <label for="n8nPassword">Enter Password:</label><br>
                    <input type="password" id="n8nPassword" class="password-input" placeholder="Enter Password">
                </div>
                <br>
                <div id="DattoRMMContainer" style="display: none;">
                    <label for="dattoRmmDropdown">Select a Datto RMM site:</label><br>
                    <select id="dattoRmmDropdown" class="dropdown">
                        <option value="">Fetching sites...</option>
                        $siteOptions
                    </select>
                </div>
                <div class="button-group">
                    <button class="install-button" id="fetchSitesButton" onclick="fetchSites()" disabled>Fetch Sites</button>
                    <button class="install-button" onclick="triggerInstall()">Install</button>
                </div>
            </div>
            <!-- Off-Boarding Tab -->
            <div id="offboardTab" class="tab-content inactive">
                <h2>Off-Boarding</h2>
                <div class="checkbox-group column">
                    <label>
                        <input type="checkbox" id="selectAllOffboardCheckbox" onclick="toggleOffboardCheckboxes(this)">
                        Select All
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallSVSMSPModule" id="uninstallSVSMSPModuleCheckbox">
                        Uninstall SVSMSP Module
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallThreatLocker" id="uninstallThreatLockerCheckbox">
                        Uninstall ThreatLocker
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallCyberQP" id="uninstallCyberQPCheckbox">
                        Uninstall CyberQP
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallDattoEDR" id="uninstallDattoEDRCheckbox">
                        Uninstall DattoEDR
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallDattoRMM" id="uninstallDattoRMMCheckbox">
                        Uninstall DattoRMM
                    </label>
                     <label>
                        <input type="checkbox" name="uninstallDattoDEB" id="uninstallDattoDEBCheckbox">
                        Uninstall DattoDEB
                    </label>
                     <label>
                        <input type="checkbox" name="uninstallRocketCyber" id="uninstallRocketCyberCheckbox">
                        Uninstall RocketCyber
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallSplashtop" id="uninstallSplashtopCheckbox">
                        Uninstall splashtop
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallSVSHelpdesk" id="uninstallSVSHelpdeskCheckbox">
                        Uninstall SVSHelpdesk
                    </label>
                    <label>
                        <input type="checkbox" name="uninstallSVSWatchtower" id="uninstallSVSWatchtowerCheckbox">
                        Uninstall SVSWatchtower
                    </label>     
                </div>
                <div class="button-group">
                    <button class="install-button" onclick="triggerOffboard()">Offboard</button>
                </div>
            </div>
            <!-- Tweaks Tab -->
            <div id="tweaksTab" class="tab-content inactive">
                <h2>Tweaks</h2>
                <div class="columns-container">
                    <div class="column" id="tweaksColumn1">
                        <h3>System Optimizations</h3>
                        <div class="checkbox-group">
                            <label>
                                <input type="checkbox" name="setedgedefaultsearch" id="setedgedefaultsearchCheckbox">
                                Set Edge Default Search Engine
                            </label>
                            <label>
                                <input type="checkbox" name="setWindowsPerformance" id="setWindowsPerformanceCheckbox" onclick="toggleRadioButtons(this)">
                                Optimize Windows Performance
                            </label>
                            <div class="radio-group" id="windowsPerformanceOptions" style="margin-left: 20px; display: none;">
                                <label>
                                    <input type="radio" name="optimizeWindowsPerformanceLevel" value="full">
                                    Full
                                </label>
                                <label>
                                    <input type="radio" name="optimizeWindowsPerformanceLevel" value="partial">
                                    Partial
                                </label>
                                <label>
                                    <input type="radio" name="optimizeWindowsPerformanceLevel" value="none" checked>
                                    None
                                </label>
                            </div>
                            <label>
                                <input type="checkbox" name="stopUnnecessaryServices" id="stopUnnecessaryServicesCheckbox">
                                Stop Unnecessary Services
                            </label>
                        </div>
                    </div>
                    <div class="column" id="tweaksColumn2">
                        <h3>Additional Tweaks</h3>
                        <div class="checkbox-group">
                            <label>
                                <input type="checkbox" name="disableAnimations" id="disableAnimationsCheckbox">
                                Disable Animations
                            </label>
                            <label>
                                <input type="checkbox" name="optimizePerformance" id="optimizePerformanceCheckbox">
                                Optimize Application Performance
                            </label>
                            <label>
                                <input type="checkbox" name="increaseFontSize" id="increaseFontSizeCheckbox">
                                Increase Font Size
                            </label>
                        </div>
                    </div>
                    <div class="column" id="tweaksColumn3">
                        <h3>Miscellaneous</h3>
                        <div class="checkbox-group">
                            <label>
                                <input type="checkbox" name="enableDarkMode" id="enableDarkModeCheckbox">
                                Enable Dark Mode
                            </label>
                            <label>
                                <input type="checkbox" name="clearTempFiles" id="clearTempFilesCheckbox">
                                Clear Temporary Files
                            </label>
                        </div>
                    </div>
                </div>
                <div class="button-group">
                    <button class="install-button" onclick="triggerTweaks()">Apply Tweaks</button>
                </div>
            </div>
            <!-- SVS Apps Tab -->
            <div id="SVSAppsTab" class="tab-content inactive">
                <h2>SVS APPs</h2>
                <!-- Winget Apps Group -->
                <div class="checkbox-group column" id="wingetGroup">
                    <h3>Winget Apps</h3>
                    <label>
                        <input type="checkbox" id="selectAllWingetCheckbox" onclick="toggleWingetCheckboxes(this)">
                        Select All
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetLastpass">
                        Lastpass Desktop App
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetBitwarden">
                        Bitwarden Desktop App
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetICloud">
                        Apple iCloud
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetBitvise">
                        Bitvise SSH Client
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetObsidian">
                        Obsidian
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetFlameshot">
                        Flameshot
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetVSCODE">
                        Microsoft Visual Studio Code
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetGit">
                        Git.Git
                    </label>
                    <label>
                        <input type="checkbox" class="winget-checkbox" name="wingetSublimeText">
                        SublimeText 4
                    </label>
                </div>
                <!-- Extensions Group -->
                <div class="checkbox-group column" id="extensionsGroup">
                    <h3>Extensions</h3>
                    <label>
                        <input type="checkbox" class="extension-checkbox" name="installLastPassChrome">
                        LastPass Extension for Chrome
                    </label>
                    <label>
                        <input type="checkbox" class="extension-checkbox" name="installLastPassEdge">
                        LastPass Extension for Edge
                    </label>
                </div>
                <div class="button-group">
                    <!-- Combined trigger calls both winget and extension installation -->
                    <button class="install-button" onclick="triggerSVSApps()">Install SVS Apps</button>
                </div>
            </div>
            <!-- Shared Exit Button -->
            <div class="button-group">
                <button class="exit-button" onclick="endSession()">Exit</button>
            </div>
            <!-- Log Area -->
            <div class="log" id="logArea">
                 <p>Logs will appear here...</p>
            </div>
        </div>
    </div>
<script>
    // =======================================================================
    // Tab Navigation
    // =======================================================================
    const tabButtons = document.querySelectorAll('.tab-button');
    const tabContents = document.querySelectorAll('.tab-content');
    tabButtons.forEach(button => {
        button.addEventListener('click', () => {
            tabButtons.forEach(btn => {
                btn.classList.remove('active');
                btn.setAttribute('aria-expanded', 'false');
            });
            tabContents.forEach(tab => tab.classList.remove('active'));
            button.classList.add('active');
            button.setAttribute('aria-expanded', 'true');
            document.getElementById(button.dataset.tab).classList.add('active');
        });
    });
    
    // =======================================================================
    // SECTION: DattoRMM Visibility and Options Management
    // =======================================================================
    function toggleDattoRMMVisibility() {
        const dattoRMMCheckbox = document.getElementById('installDattoRMMCheckbox');
        const optionsContainer = document.getElementById('dattoRMMOptionsContainer');
        const n8nPasswordContainer = document.getElementById('n8nPasswordContainer');
        const dattoRMMContainer = document.getElementById('DattoRMMContainer');
        if (dattoRMMCheckbox.checked) {
            optionsContainer.style.display = 'block';
            n8nPasswordContainer.style.display = 'block';
            dattoRMMContainer.style.display = 'block';
        } else {
            optionsContainer.style.display = 'none';
            n8nPasswordContainer.style.display = 'none';
            dattoRMMContainer.style.display = 'none';
        }
    }
    
    // =======================================================================
    // SECTION: Checkbox "Select All" Utility Functions for Onboarding and Offboarding
    // =======================================================================
    function updateSelectAllCheckbox(selectAllId, checkboxGroupSelector) {
        const selectAllCheckbox = document.getElementById(selectAllId);
        const checkboxes = document.querySelectorAll(checkboxGroupSelector);
        selectAllCheckbox.checked = Array.from(checkboxes).every(checkbox => checkbox.checked);
    }
    function toggleLeftColumnCheckboxes(selectAllCheckbox) {
        const leftCheckboxes = document.querySelectorAll('#leftColumn input[type="checkbox"]:not(#selectAllLeftCheckbox)');
        leftCheckboxes.forEach(checkbox => {
            checkbox.checked = selectAllCheckbox.checked;
        });
        toggleDattoRMMVisibility();
    }
    function toggleOnboardCheckboxes(selectedCheckbox) {
        toggleDattoRMMVisibility();
        updateSelectAllCheckbox('selectAllLeftCheckbox', '#onboardTab input[type="checkbox"]:not(#selectAllLeftCheckbox)');
    }
    document.querySelectorAll('#onboardTab input[type="checkbox"]:not(#selectAllLeftCheckbox)').forEach(checkbox => {
        checkbox.addEventListener('change', () => {
            updateSelectAllCheckbox('selectAllLeftCheckbox', '#onboardTab input[type="checkbox"]:not(#selectAllLeftCheckbox)');
        });
    });
    
    // =======================================================================
    // SECTION: Offboard Tab Checkbox Management
    // =======================================================================
    function toggleOffboardCheckboxes(selectAllCheckbox) {
        const checkboxes = document.querySelectorAll('#offboardTab input[type="checkbox"]:not(#selectAllOffboardCheckbox)');
        checkboxes.forEach(checkbox => {
            checkbox.checked = selectAllCheckbox.checked;
        });
    }
    function updateSelectAllOffboard() {
        const selectAllCheckbox = document.getElementById('selectAllOffboardCheckbox');
        const checkboxes = document.querySelectorAll('#offboardTab input[type="checkbox"]:not(#selectAllOffboardCheckbox)');
        selectAllCheckbox.checked = Array.from(checkboxes).every(checkbox => checkbox.checked);
    }
    document.querySelectorAll('#offboardTab input[type="checkbox"]:not(#selectAllOffboardCheckbox)').forEach(checkbox => {
        checkbox.addEventListener('change', updateSelectAllOffboard);
    });
    
    // =======================================================================
    // SECTION: Offboarding Task Trigger
    // =======================================================================
    function triggerOffboard() {
        const checkboxes = document.querySelectorAll('#offboardTab input[type="checkbox"]:not(#selectAllOffboardCheckbox)');
        const selectedTasks = Array.from(checkboxes)
            .filter(checkbox => checkbox.checked)
            .map(checkbox => checkbox.name);
        if (selectedTasks.length === 0) {
            appendLog("Please select at least one offboarding task.", "red");
            return;
        }
        appendLog("Starting offboarding tasks...", "yellow");
        fetch('/offboard', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ SelectedTasks: selectedTasks })
        })
            .then(response => {
                if (!response.ok) {
                    throw new Error('Failed to execute offboarding tasks.');
                }
                return response.text();
            })
            .then(message => {
                appendLog(message, "green");
            })
            .catch(error => {
                appendLog("Error: " + error.message, "red");
            });
    }
    
    // =======================================================================
    // SECTION: Windows Performance Radio Buttons Management
    // =======================================================================
    function toggleRadioButtons(checkbox) {
        const radioGroup = document.getElementById("windowsPerformanceOptions");
        if (checkbox.checked) {
            radioGroup.style.display = "block";
        } else {
            radioGroup.style.display = "none";
            const radios = radioGroup.querySelectorAll('input[type="radio"]');
            radios.forEach(radio => {
                radio.checked = false;
            });
            radios[2].checked = true;
        }
    }
    
    // =======================================================================
    // SECTION: System Tweaks Trigger
    // =======================================================================
    function triggerTweaks() {
        const setEdgeDefaultSearch = document.getElementById('setedgedefaultsearchCheckbox').checked;
        const optimizeWindowsPerformance = document.getElementById('setWindowsPerformanceCheckbox').checked;
        const stopUnnecessaryServices = document.getElementById('stopUnnecessaryServicesCheckbox').checked;
        const disableAnimations = document.getElementById('disableAnimationsCheckbox').checked;
        const optimizePerformance = document.getElementById('optimizePerformanceCheckbox').checked;
        const increaseFontSize = document.getElementById('increaseFontSizeCheckbox').checked;
        const enableDarkMode = document.getElementById('enableDarkModeCheckbox').checked;
        const clearTempFiles = document.getElementById('clearTempFilesCheckbox').checked;
        let optimizeWindowsPerformanceLevel = "none";
        if (optimizeWindowsPerformance) {
            const radios = document.querySelectorAll('input[name="optimizeWindowsPerformanceLevel"]');
            radios.forEach(radio => {
                if (radio.checked) {
                    optimizeWindowsPerformanceLevel = radio.value;
                }
            });
        }
        console.log("Set Edge Default Search Engine:", setEdgeDefaultSearch);
        console.log("Optimize Windows Performance:", optimizeWindowsPerformance);
        console.log("Windows Performance Optimization Level:", optimizeWindowsPerformanceLevel);
        console.log("Stop Unnecessary Services:", stopUnnecessaryServices);
        console.log("Disable Animations:", disableAnimations);
        console.log("Optimize Application Performance:", optimizePerformance);
        console.log("Increase Font Size:", increaseFontSize);
        console.log("Enable Dark Mode:", enableDarkMode);
        console.log("Clear Temporary Files:", clearTempFiles);
        if (setEdgeDefaultSearch) {
            // Call function to set Edge default search engine
        }
        if (optimizeWindowsPerformance) {
            if (optimizeWindowsPerformanceLevel === "full") {
                // Full optimization
            } else if (optimizeWindowsPerformanceLevel === "partial") {
                // Partial optimization
            } else {
                // No optimization
            }
        }
        if (stopUnnecessaryServices) {
            // Stop services
        }
        if (disableAnimations) {
            // Disable animations
        }
        if (optimizePerformance) {
            // Optimize performance
        }
        if (increaseFontSize) {
            // Increase font size
        }
        if (enableDarkMode) {
            // Enable dark mode
        }
        if (clearTempFiles) {
            // Clear temp files
        }
        alert("Tweaks applied successfully!");
    }
    
    // =======================================================================
    // SECTION: DattoRMM Options Toggle
    // =======================================================================
    function toggleDattoRMMOptions() {
        const dattoRMMCheckbox = document.getElementById('installDattoRMMCheckbox');
        const optionsContainer = document.getElementById('dattoRMMOptionsContainer');
        const n8nPasswordContainer = document.getElementById('n8nPasswordContainer');
        const dattoRMMContainer = document.getElementById('DattoRMMContainer');
        const subCheckboxes = document.querySelectorAll('#dattoRMMOptionsContainer input[type="checkbox"]');
        if (dattoRMMCheckbox.checked) {
            optionsContainer.style.display = 'block';
            n8nPasswordContainer.style.display = 'block';
            dattoRMMContainer.style.display = 'block';
            subCheckboxes.forEach(subCheckbox => {
                subCheckbox.checked = true;
            });
        } else {
            optionsContainer.style.display = 'none';
            n8nPasswordContainer.style.display = 'none';
            dattoRMMContainer.style.display = 'none';
            subCheckboxes.forEach(subCheckbox => {
                subCheckbox.checked = false;
            });
        }
    }
    
    // =======================================================================
    // SECTION: Winget Apps Checkbox Management (Winget Group Only)
    // =======================================================================
    function toggleWingetCheckboxes(selectAllCheckbox) {
        const wingetCheckboxes = document.querySelectorAll('#wingetGroup input[type="checkbox"].winget-checkbox:not(#selectAllWingetCheckbox)');
        wingetCheckboxes.forEach(checkbox => {
            checkbox.checked = selectAllCheckbox.checked;
        });
    }
    
    // Attach event listeners for winget checkboxes within wingetGroup
    document.querySelectorAll('#wingetGroup input[type="checkbox"].winget-checkbox').forEach(checkbox => {
        checkbox.addEventListener('change', () => {
            const selectAll = document.getElementById('selectAllWingetCheckbox');
            if (!checkbox.checked) {
                selectAll.checked = false;
            } else {
                const allChecked = Array.from(document.querySelectorAll('#wingetGroup input[type="checkbox"].winget-checkbox'))
                                        .every(cb => cb.checked);
                selectAll.checked = allChecked;
            }
        });
    });
    
    // =======================================================================
    // SECTION: SVS APPs Installation Trigger (Combined)
    // =======================================================================
    function triggerWinget() {
        const wingetCheckboxes = document.querySelectorAll('#wingetGroup input[type="checkbox"].winget-checkbox');
        const selectedWinget = Array.from(wingetCheckboxes)
                                .filter(cb => cb.checked)
                                .map(cb => cb.name);
        if (selectedWinget.length === 0) {
            appendLog("Please select at least one Winget app.", "red");
            return;
        }
        appendLog("Installing selected Winget apps: " + selectedWinget.join(', '), "yellow");
        selectedWinget.forEach(app => {
            appendLog("Installing " + app + " ...", "cyan");
            // Add backend calls to execute winget commands if desired.
        });
    }
    
    function triggerExtensions() {
        const extensionCheckboxes = document.querySelectorAll('#extensionsGroup input[type="checkbox"].extension-checkbox');
        const selectedExtensions = Array.from(extensionCheckboxes)
                                .filter(cb => cb.checked)
                                .map(cb => cb.name);
        if (selectedExtensions.length === 0) {
            appendLog("No extensions selected.", "red");
            return;
        }
        // Send a POST request to the /installExtensions route
        fetch('/installExtensions', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ 
                chrome: document.querySelector('input[name="installLastPassChrome"]').checked,
                edge: document.querySelector('input[name="installLastPassEdge"]').checked 
            })
        })
        .then(response => response.text())
        .then(message => {
            appendLog(message, "green");
        })
        .catch(error => {
            appendLog("Error: " + error.message, "red");
        });
    }
    
    // Combined trigger for SVS Apps (winget + extensions)
    function triggerSVSApps() {
        triggerWinget();
        triggerExtensions();
    }
    
    // =======================================================================
    // SECTION: n8n Password Input and Fetch Sites Button
    // =======================================================================
    const logArea = document.getElementById('logArea');
    const fetchSitesButton = document.getElementById('fetchSitesButton');
    const n8nPasswordInput = document.getElementById('n8nPassword');
    n8nPasswordInput.addEventListener('input', () => {
        fetchSitesButton.disabled = n8nPasswordInput.value.length < 4;
    });
    n8nPasswordInput.addEventListener('keydown', (event) => {
        if (event.key === 'Enter' && n8nPasswordInput.value.length >= 12) {
            fetchSites();
        }
    });
    
    // =======================================================================
    // SECTION: Fetch Sites from n8n
    // =======================================================================
    async function fetchSites() {
        const password = document.getElementById('n8nPassword').value;
        const dropdown = document.getElementById('dattoRmmDropdown');
        if (!password) {
            appendLog("Please enter the n8n password.", "red");
            return;
        }
        try {
            appendLog("Fetching sites...", "yellow");
            const response = await fetch('/getn8npw', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ password })
            });
            if (!response.ok) {
                throw new Error('Failed to fetch sites. Please try again.');
            }
            const sites = await response.json();
            dropdown.innerHTML = '';
            sites.forEach(site => {
                const option = document.createElement('option');
                option.value = site.UID;
                option.textContent = site.Name;
                dropdown.appendChild(option);
            });
            appendLog("Sites fetched successfully, please select a site!", "green");
        }
        catch (error) {
            dropdown.innerHTML = '<option value="">Fetching sites failed</option>';
            appendLog('Error:' + error.message, "red");
        }
    }
    
    // =======================================================================
    // SECTION: Installation Trigger for Modules and Tasks
    // =======================================================================
    function triggerInstall() {
        const dropdown = document.getElementById('dattoRmmDropdown');
        const UID = dropdown && dropdown.options[dropdown.selectedIndex]
            ? dropdown.options[dropdown.selectedIndex].value
            : null;
        const Name = dropdown && dropdown.options[dropdown.selectedIndex]
            ? dropdown.options[dropdown.selectedIndex].text
            : null;
        (async () => {
            if (document.querySelector('input[name="installSVSMSPModule"]').checked) {
                appendLog("Installing SVSMSP Module (Priority 1)...", "cyan");
                try {
                    await fetch('/installSVSMSPModule', { method: 'GET' });
                    appendLog("SVSMSP Module installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing SVSMSP Module: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installDattoRMM"]').checked) {
                appendLog("Installing DattoRMM (Priority 2)...", "cyan");
                try {
                    const DattoRMMCheckbox = document.querySelectorAll('input[name="dattoRMMOption"]:checked');
                    const checkedValues = Array.from(DattoRMMCheckbox).map(c => c.value);
                    const payload = {
                        checkedValues,
                        UID,
                        Name
                    };
                    await fetch('/installrmm', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(payload)
                    });
                    appendLog("DattoRMM installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing DattoRMM: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="setSVSPowerplan"]').checked) {
                appendLog("Setting SVS Powerplan (Priority 3)...", "cyan");
                try {
                    await fetch('/SetSVSPowerplan', { method: 'GET' });
                    appendLog("SVS Powerplan set successfully.", "green");
                } catch (error) {
                    appendLog("Error setting SVS Powerplan: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installCyberQP"]').checked) {
                appendLog("Installing CyberQP (Priority 3)...", "cyan");
                try {
                    await fetch('/installCyberQP', { method: 'GET' });
                    appendLog("CyberQP installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing CyberQP: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installSplashtop"]').checked) {
                appendLog("Installing Splashtop (Priority 3)...", "cyan");
                try {
                    await fetch('/installSplashtop', { method: 'GET' });
                    appendLog("Splashtop installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing Splashtop: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installSVSHelpDesk"]').checked) {
                appendLog("Installing SVS HelpDesk (Priority 3)...", "cyan");
                try {
                    await fetch('/installSVSHelpDesk', { method: 'GET' });
                    appendLog("SVS HelpDesk installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing SVS HelpDesk: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installThreatLocker"]').checked) {
                appendLog("Installing ThreatLocker (Priority 3)...", "cyan");
                try {
                    await fetch('/installThreatLocker', { method: 'GET' });
                    appendLog("ThreatLocker installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing ThreatLocker: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="installRocketCyber"]').checked) {
                appendLog("Installing RocketCyber (Priority 3)...", "cyan");
                try {
                    await fetch('/installRocketCyber', { method: 'GET' });
                    appendLog("RocketCyber installation completed.", "green");
                } catch (error) {
                    appendLog("Error installing RocketCyber: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="setedgedefaultsearch"]').checked) {
                appendLog("Setting Edge Default Search Engine (Priority 3)...", "cyan");
                try {
                    await fetch('/setedgedefaultsearch', { method: 'GET' });
                    appendLog("Edge Default Search Engine set successfully.", "green");
                } catch (error) {
                    appendLog("Error setting Edge Default Search Engine: " + error.message, "red");
                }
            }
            if (document.querySelector('input[name="EnableBitLocker"]').checked) {
                appendLog("Enabling BitLocker (Priority 3)...", "cyan");
                try {
                    await fetch('/EnableBitLocker', { method: 'GET' });
                    appendLog("BitLocker enabled successfully.", "green");
                } catch (error) {
                    appendLog("Error enabling BitLocker: " + error.message, "red");
                }
            }
        })();
    }
    
    // =======================================================================
    // SECTION: Combined Trigger for SVS Apps (Winget + Extensions)
    // =======================================================================
    function triggerSVSApps() {
        triggerWinget();
        triggerExtensions();
    }
    
    // =======================================================================
    // SECTION: Session End and Window Unload Handling
    // =======================================================================
    function endSession() {
        appendLog("Session ended. Closing application...", "yellow");
        fetch('/quit', { method: 'GET' })
          .then(response => {
              if (!response.ok) {
                  throw new Error('Failed to end session');
              }
              window.close();
          })
          .catch(error => {
              appendLog("Error ending session: " + error.message, "red");
          });
    }
    window.addEventListener('beforeunload', (event) => {
        endSession();
    });
    
    // =======================================================================
    // SECTION: Log Management and Polling
    // =======================================================================
    function appendLog(message, color = "white") {
        const log = document.createElement('p');
        log.style.color = color;
        log.textContent = message;
        document.getElementById('logArea').appendChild(log);
    }
    let lastLogCount = 0;
    async function fetchLogs() {
        try {
            const resp = await fetch('/getLogs');
            if (!resp.ok) return;
            const logs = await resp.json();
            for (let i = lastLogCount; i < logs.length; i++) {
                appendLog(logs[i].Message, "white");
            }
            lastLogCount = logs.length;
        } catch (err) {
            console.error("Error fetching logs:", err);
        }
    }
    setInterval(fetchLogs, 3000);
    
</script>
</body>
</html>
"@
}
# Save and launch the HTML
Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:8081/"

#region HTTP Listener Route Handling
try {
    while ($listener.IsListening) {
        $context  = $listener.GetContext()
        $request  = $context.Request
        $response = $context.Response
        switch ($request.Url.AbsolutePath) {
            "/" {
                $htmlContent = GetHtmlContent
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($htmlContent)
                $response.ContentType = "text/html"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/getn8npw" {
                if ($request.HttpMethod -eq "POST") {
                    try {
                        $bodyStream = New-Object IO.StreamReader $request.InputStream
                        $body       = $bodyStream.ReadToEnd()
                        $data       = ConvertFrom-Json $body
                        $password   = $data.password
                        Get-N8nWebhookData -AuthHeaderValue $password
                        $sites = Install-DattoRMM-Helper -ApiUrl $ApiUrl -ApiKey $ApiKey -ApiSecretKey $ApiSecretKey -FetchSitesOnly
                        if (-not $sites) {
                            Write-Host "No sites returned. Please check the API." -ForegroundColor Red
                            $response.StatusCode = 500
                            $buffer = [System.Text.Encoding]::UTF8.GetBytes("No sites found")
                            $response.OutputStream.Write($buffer, 0, $buffer.Length)
                            $response.OutputStream.Close()
                            continue
                        }
                        $responseData = $sites | ConvertTo-Json
                        $buffer       = [System.Text.Encoding]::UTF8.GetBytes($responseData)
                        $response.ContentType     = "application/json"
                        $response.ContentLength64 = $buffer.Length
                        $response.OutputStream.Write($buffer, 0, $buffer.Length)
                        $response.OutputStream.Close()
                    } catch {
                        Write-LogHybrid -Message "Error processing /getn8npw: $($_.Exception.Message)" -Level "Error"
                        $response.StatusCode = 500
                        $buffer = [System.Text.Encoding]::UTF8.GetBytes("Error: Failed to process the request.")
                        $response.OutputStream.Write($buffer, 0, $buffer.Length)
                        $response.OutputStream.Close()
                    }
                }
            }
            "/installSVSMSPModule" {
                if ($request.HttpMethod -eq "GET") {
                    try {
                        Install-SVSMSP -InstallToolkit
                        $responseString = "Install SVSMSP Module triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Install SVSMSP Module: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/installrmm" {
                if ($request.HttpMethod -eq "POST") {
                    try {
                        $bodyStream   = New-Object IO.StreamReader $request.InputStream
                        $body         = $bodyStream.ReadToEnd()
                        $requestData  = ConvertFrom-Json $body
                        $checkedValues = $requestData.checkedValues
                        $UID           = $requestData.UID
                        $Name          = $requestData.Name
                        if (-not $checkedValues -or -not $UID -or -not $Name) {
                            Write-LogHybrid -Message "Invalid input received. Missing required parameters: UID, Name, or checkbox values." -Level "Error"
                            $response.StatusCode = 400
                            $responseString = "Error: Missing required input parameters."
                            $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                            $response.OutputStream.Write($buffer, 0, $buffer.Length)
                            $response.OutputStream.Close()
                            return
                        }
                        $installRMMCommand = "Install-DattoRMM -ApiUrl '$ApiUrl' -ApiKey '$ApiKey' -ApiSecretKey '$ApiSecretKey' -SiteName $Name -SiteUID $UID "
                        if ($checkedValues -contains 'inputVar') {
                            $installRMMCommand += " -PushSiteVars"
                        }
                        if ($checkedValues -contains 'rmm') {
                            $installRMMCommand += " -InstallRMM"
                        }
                        if ($checkedValues -contains 'exe') {
                            $installRMMCommand += " -SaveCopy"
                        }
                        try {
                            Invoke-Expression $installRMMCommand
                            $responseString = "RMM installation triggered successfully for $Name."
                            Write-LogHybrid -Message $responseString -Level "Success"
                            $response.StatusCode = 200
                        } catch {
                            $responseString = "Error triggering RMM installation: $($_.Exception.Message)"
                            Write-LogHybrid -Message $responseString -Level "Error"
                            $response.StatusCode = 500
                        }
                    } catch {
                        $errorString = "An error occurred while processing the /installrmm request: $($_.Exception.Message)"
                        Write-LogHybrid -Message $errorString -Level "Error"
                        $response.StatusCode = 500
                        $responseString = $errorString
                    }
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.ContentType = "text/plain"
                    $response.ContentLength64 = $buffer.Length
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                } else {
                    $responseString = "Method not allowed. Use POST."
                    $response.StatusCode = 405
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                }
            }
            "/setSVSPowerplan" {
                if ($request.HttpMethod -eq "GET") {
                     try {
                        Set-SVSPowerPlan
                        $responseString = "Setting SVS PowerPlan triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Setting SVS PowerPlan: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/installCyberQP" {
                if ($request.HttpMethod -eq "GET") {
                    try {
                        Install-CyberQP
                        $responseString = "Install CyberQP triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Install CyberQP: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/installSplashtop" {
                if ($request.HttpMethod -eq "GET") {
                     try {
                        Install-Splashtop
                        $responseString = "Install Splashtop triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Install Splashtop: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/installRocketCyber" {
                if ($request.HttpMethod -eq "GET") {
                    try {
                        Install-RocketCyber
                        $responseString = "Install RocketCyber triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Install RocketCyber: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/installThreatLocker" {
                if ($request.HttpMethod -eq "GET") {
                 try {
                        Install-ThreatLocker
                        $responseString = "Install ThreatLocker triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering Install ThreatLocker: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/setedgedefaultsearch"{
                if ($request.HttpMethod -eq "GET") {
                 try {
                        set-EdgeDefaultSearchProvider
                        $responseString = "setedgedefaultsearch triggered successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error triggering setedgedefaultsearch: $_"
                        $response.StatusCode = 500
                   }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/EnableBitLocker" {
                if ($request.HttpMethod -eq "GET") {
                    try {
                        Set-SVSBitLocker -Mode Enable -DriveLetter C -SaveToRegistry $true
                        $responseString = " BitLocker enabled on C successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error Attempting to set BitLocker: $_"
                        $response.StatusCode = 500
                    }
                } else {
                    $responseString = "Method not allowed. Use GET."
                    $response.StatusCode = 405
                }
                $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType     = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/offboard" {
                if ($request.HttpMethod -eq "POST") {
                    try {
                        $bodyStream   = New-Object IO.StreamReader $request.InputStream
                        $body         = $bodyStream.ReadToEnd()
                        $requestData  = ConvertFrom-Json $body
                        $selectedTasks = $requestData.SelectedTasks
                        Write-LogHybrid -Message "Offboarding request received with tasks: $($selectedTasks -join ', ')" -Level "Info"
                        if (-not $selectedTasks -or $selectedTasks.Count -eq 0) {
                            $response.StatusCode = 400
                            $responseString = "Error: No offboarding tasks selected."
                            $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                            $response.OutputStream.Write($buffer, 0, $buffer.Length)
                            $response.OutputStream.Close()
                            return
                        }
                        foreach ($task in $selectedTasks) {
                            switch ($task) {
                                "uninstallSVSMSPModule" { Write-LogHybrid -Message "Uninstalling SVSMSP Module..." -Level "Info"; Install-SVSMSP -cleanup }
                                "uninstallThreatLocker" { Write-LogHybrid -Message "Uninstalling Threatlocker" -Level "Info"; Uninstall-ThreatLocker }
                                "uninstallCyberQP"      { Write-LogHybrid -Message "Uninstalling CyberQP" -Level "Info";Uninstall-CyberQP }
                                "uninstallDattoEDR"     { Uninstall-DattoEDR }
                                "uninstallDattoRMM"     { Uninstall-DattoRMM }
                                "uninstallRocketCyber"  { Uninstall-RocketCyber }
                                "uninstallSplashtop"    { Uninstall-Splashtop }
                                "uninstallSVSHelpdesk"  { Uninstall-SVSHelpdesk }
                                "uninstallSVSWatchtower" { Uninstall-SVSWatchtower }
                                default {
                                    Write-LogHybrid -Message "Unknown task: $task" -Level "Warning"
                                }
                            }
                        }
                        $responseString = "Offboarding tasks executed successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error processing offboarding tasks: $($_.Exception.Message)"
                        $response.StatusCode = 500
                    }
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.ContentType = "text/plain"
                    $response.ContentLength64 = $buffer.Length
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                } else {
                    $responseString = "Method not allowed. Use POST."
                    $response.StatusCode = 405
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                }
            }
            "/runTweaks" {
                if ($request.HttpMethod -eq "POST") {
                    try {
                        $bodyStream   = New-Object IO.StreamReader $request.InputStream
                        $body         = $bodyStream.ReadToEnd()
                        $requestData  = ConvertFrom-Json $body
                        $tweaks = $requestData.tweaks
                        if (-not $tweaks -or $tweaks.Count -eq 0) {
                            $response.StatusCode = 400
                            $responseString = "Error: No tweaks selected."
                            $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                            $response.OutputStream.Write($buffer, 0, $buffer.Length)
                            $response.OutputStream.Close()
                            return
                        }
                        foreach ($tweak in $tweaks) {
                            switch ($tweak) {
                                "enableDarkModeCheckbox" {
                                    Write-LogHybrid -Message "Running tweak: Set Edge Default Search Engine" -Level "Info"
                                    Set-EdgeDefaultSearchEngine
                                }
                                "disableAnimationsCheckbox" {
                                    Write-LogHybrid -Message "Running tweak: Disable Animations" -Level "Info"
                                }
                                "optimizePerformanceCheckbox" {
                                    Write-LogHybrid -Message "Running tweak: Optimize Performance" -Level "Info"
                                }
                                "increaseFontSizeCheckbox" {
                                    Write-LogHybrid -Message "Running tweak: Increase Font Size" -Level "Info"
                                }
                                default {
                                    Write-LogHybrid -Message "Unknown tweak: $tweak" -Level "Warning"
                                }
                            }
                        }
                        $responseString = "Selected tweaks executed successfully."
                        $response.StatusCode = 200
                    } catch {
                        $responseString = "Error processing tweaks: $($_.Exception.Message)"
                        $response.StatusCode = 500
                    }
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.ContentType = "text/plain"
                    $response.ContentLength64 = $buffer.Length
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                } else {
                    $responseString = "Method not allowed. Use POST."
                    $response.StatusCode = 405
                    $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                }
            }
            "/getLogs" {
                if ($request.HttpMethod -eq "GET") {
                    $jsonLogs = $Global:LogCache | ConvertTo-Json
                    $logBuffer = [System.Text.Encoding]::UTF8.GetBytes($jsonLogs)
                    $response.ContentType = "application/json"
                    $response.ContentLength64 = $logBuffer.Length
                    $response.OutputStream.Write($logBuffer, 0, $logBuffer.Length)
                    $response.OutputStream.Close()
                }
            }
            # New route for installing LastPass Extensions
            "/installExtensions" {
                if ($request.HttpMethod -eq "POST") {
                    try {
                        $bodyStream = New-Object IO.StreamReader $request.InputStream
                        $body = $bodyStream.ReadToEnd() | Out-String
                        $data = ConvertFrom-Json $body
                        $installChrome = $data.chrome
                        $installEdge = $data.edge
                        Install-LastPassExtensions -Chrome:$installChrome -Edge:$installEdge
                        $responseString = "LastPass extensions installation triggered."
                        $response.StatusCode = 200
                    }
                    catch {
                        $responseString = "Error processing extensions installation: $($_.Exception.Message)"
                        $response.StatusCode = 500
                    }
                }
                else {
                    $responseString = "Method not allowed. Use POST."
                    $response.StatusCode = 405
                }
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                $response.ContentType = "text/plain"
                $response.ContentLength64 = $buffer.Length
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
            "/quit" {
                if ($request.HttpMethod -eq "GET") {
                    $responseString = "Server shutting down."
                    $buffer         = [System.Text.Encoding]::UTF8.GetBytes($responseString)
                    $response.ContentType     = "text/plain"
                    $response.ContentLength64 = $buffer.Length
                    $response.OutputStream.Write($buffer, 0, $buffer.Length)
                    $response.OutputStream.Close()
                    Write-Host $responseString
                    $listener.stop()
                    break
                }
            }
            default {
                $response.StatusCode        = 404
                $response.StatusDescription = "Not Found"
                $buffer = [System.Text.Encoding]::UTF8.GetBytes("404 - Not Found")
                $response.OutputStream.Write($buffer, 0, $buffer.Length)
                $response.OutputStream.Close()
            }
        } 
    }
}
catch {
    Write-Host "Error: $($_.Exception.Message)"
}
finally {
    if ($listener -ne $null) {
        try {
            Write-LogHybrid -Message "Stopping the listener." -Level "Info"
            $listener.Stop()
            $listener.Close()
            Write-LogHybrid -Message "Listener stopped successfully." -Level "Info"
        } catch {
            Write-LogHybrid -Message "Error stopping the listener: $($_.Exception.Message)" -Level "Error"
        }
    } else {
        Write-LogHybrid -Message "Listener object is null; nothing to stop." -Level "Warning"
    }
}
