Files
Logo/testTaskGate.ps1
2025-05-17 14:39:37 -04:00

568 lines
28 KiB
PowerShell

### 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 from 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) }
}
$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 "⚠ [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 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
}
if ($FetchSitesOnly) {
Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan
try {
$getSites = Invoke-WebRequest -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers @{ "Authorization" = "Bearer $requestToken" } -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: $($_.Exception.Message)" -ForegroundColor Red
return
}
}
}
#endregion
#region LastPass Extensions
function ForceInstall-LastPassChrome {
$ExtensionID = "hdokiejnpimakedhajhdlcegeplioahd"
$UpdateURL = "https://clients2.google.com/service/update2/crx"
$RegPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
try {
New-Item -Path (Split-Path $RegPath) -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $RegPath -Force -ErrorAction SilentlyContinue | Out-Null
Set-ItemProperty -Path $RegPath -Name "1" -Value "$ExtensionID;$UpdateURL" -ErrorAction Stop
Write-Host "Configured LastPass Chrome extension."
}
catch {
Write-Host "Failed Chrome config: $($_.Exception.Message)" -ForegroundColor Red
}
}
function ForceInstall-LastPassEdge {
$ExtensionID = "bbcinlkgjjkejfdpemiealijmmooekmp"
$UpdateURL = "https://edge.microsoft.com/extensionwebstorebase/v1/crx"
$RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist"
try {
New-Item -Path (Split-Path $RegPath) -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $RegPath -Force -ErrorAction SilentlyContinue | Out-Null
Set-ItemProperty -Path $RegPath -Name "1" -Value "$ExtensionID;$UpdateURL" -ErrorAction Stop
Write-Host "Configured LastPass Edge extension."
}
catch {
Write-Host "Failed Edge config: $($_.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,
[array]$AllModules = @(@{ModuleName="SVS_Toolkit"},@{ModuleName="SVSMSP"}),
[string]$NewModuleName = "SVSMSP",
[array]$AllRepositories = @(@{RepoName="SVS_Repo"},@{RepoName="SVS_Toolkit"}),
[string]$NewRepositoryName = "SVS_Repo",
[string]$NewRepositoryURL = "http://proget.svstools.ca:8083/nuget/SVS_Repo/",
[string]$LogFilePath = "$env:SVSMSP\svstoolkit.log"
)
function Perform-Cleanup {
Write-LogHybrid -Message "Cleanup mode enabled..." -Level Info -LogToEvent
foreach ($m in $AllModules) {
if (Get-Module -Name $m.ModuleName -ListAvailable) {
Write-LogHybrid -Message "Removing $($m.ModuleName)..." -Level Warning -LogToEvent
try { Uninstall-Module -Name $m.ModuleName -AllVersions -Force; Write-LogHybrid -Message "Removed $($m.ModuleName)" -Level Success -LogToEvent }
catch { Write-LogHybrid -Message "Failed to remove $($m.ModuleName): $_" -Level Error -LogToEvent }
}
}
foreach ($r in $AllRepositories) {
if (Get-PSRepository -Name $r.RepoName -ErrorAction SilentlyContinue) {
Write-LogHybrid -Message "Unregistering $($r.RepoName)..." -Level Warning -LogToEvent
try { Unregister-PSRepository -Name $r.RepoName -ErrorAction Stop; Write-LogHybrid -Message "Unregistered $($r.RepoName)" -Level Success -LogToEvent }
catch { Write-LogHybrid -Message "Failed to unregister $($r.RepoName): $_" -Level Error -LogToEvent }
}
}
Write-LogHybrid -Message "Cleanup complete." -Level Success -LogToEvent
}
function Perform-ToolkitInstallation {
Perform-Cleanup
if ((Get-ExecutionPolicy -Scope LocalMachine) -ne "RemoteSigned") {
Write-LogHybrid -Message "Setting execution policy to RemoteSigned..." -Level Warning -LogToEvent
try { Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force; Write-LogHybrid -Message "Policy set." -Level Success -LogToEvent }
catch { Write-LogHybrid -Message "Failed to set policy: $_" -Level Error -LogToEvent; return }
}
Install-PackageProvider -Name NuGet -Force -Scope AllUsers -Confirm:$false
if (-not (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) {
Write-LogHybrid -Message "Registering $NewRepositoryName..." -Level Info -LogToEvent
try { Register-PSRepository -Name $NewRepositoryName -SourceLocation $NewRepositoryURL -InstallationPolicy Trusted; Write-LogHybrid -Message "Registered." -Level Success -LogToEvent }
catch { Write-LogHybrid -Message "Register failed: $_" -Level Error -LogToEvent }
}
Write-LogHybrid -Message "Installing $NewModuleName..." -Level Info -LogToEvent
try { Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force; Write-LogHybrid -Message "Installed." -Level Success -LogToEvent }
catch { Write-LogHybrid -Message "Install failed: $_" -Level Error -LogToEvent }
}
Write-LogHybrid -Message "Install-SVSMSP started." -Level Info -LogToEvent
if ($Cleanup) { Perform-Cleanup; return }
if ($InstallToolkit) { Perform-ToolkitInstallation; return }
Perform-ToolkitInstallation
}
#endregion
#region HTTP Listener Setup
try {
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add("http://localhost:8081/")
Write-LogHybrid -Message "Listener prefix added." -Level Info
$listener.Start()
Write-LogHybrid -Message "Listener started." -Level Info
} catch {
Write-LogHybrid -Message "Listener init error: $($_.Exception.Message)" -Level Error
throw
}
#endregion
function Get-N8nWebhookData {
param ([string]$AuthHeaderValue)
$url = "https://automate.svstools.ca/webhook/svsmspkit"
$headers = @{ "SVSMSPKit" = $AuthHeaderValue }
try {
$resp = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
foreach ($prop in $resp.PSObject.Properties) {
Set-Variable -Name $prop.Name -Value $prop.Value -Scope Global
}
return $resp
} catch {
Write-Host "Webhook GET error: $($_.Exception.Message)" -ForegroundColor Red
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">
<style>
:root {
--background-color: rgba(18, 18, 18, 1);
--border-color: rgba(255,127, 0, 0.25);
--white-color: rgba(255,255,255,1);
--gray-color: rgba(102,102,102,1);
--dark-gray-color: rgba( 51, 51, 51,1);
--light-gray-color: rgba(187,187,187,1);
--btn-sidebar-light-gray: rgba( 68, 68, 68,1);
--btn-sidebar-blue: rgba( 30,144,255,1);
--btn-hover: rgba( 0, 86,179,1);
--btn-hover-scale: 1.05;
--btn-success: rgba( 40,167, 69,1);
--btn-success-disabled: rgba(108,117,125,1);
--btn-danger: rgba(220, 53, 69,1);
}
body {
margin:0;padding:0;
font-family:Arial,sans-serif;
background:var(--background-color);
color:var(--white-color);
height:100%;overflow:hidden;
}
.logo-container { padding:20px; background:var(--background-color); }
.logo-container img { max-width:300px; }
.container { display:flex; height:100vh; overflow:hidden; }
.sidebar {
width:200px; padding:10px;
background:var(--background-color);
}
.sidebar button {
width:100%; margin-bottom:10px; padding:10px;
background:var(--btn-sidebar-light-gray);
color:var(--white-color); border:none; border-radius:5px;
text-align:left; cursor:pointer;
transition:background 0.3s,transform 0.2s;
}
.sidebar button.active { background:var(--btn-sidebar-blue); }
.sidebar button:hover { background: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 { display:flex; align-items:center; margin:0; padding:0; line-height:1.5; }
.password-input, .dropdown {
width:30%; padding:10px; margin-bottom:20px;
background:var(--background-color);
color:var(--white-color);
border:1px solid var(--border-color);
border-radius:5px;
}
#n8nPasswordContainer { display:none; margin-top:20px; }
.button-group { margin-top:20px; text-align:right; }
.log { display:none !important; }
.button-group button {
display:inline-block; padding:0.75rem 1.5rem;
margin-left:0.5rem; font-size:1rem; line-height:1.4;
border:none; border-radius:0.375rem; cursor:pointer;
transition:opacity 0.1s ease;
}
.button-group>button:first-child { margin-left:0; }
.install-button { background:var(--btn-success); color:#fff; }
.install-button:disabled { background:var(--btn-success-disabled); cursor:not-allowed; }
.exit-button { background:var(--btn-danger); color:#fff; }
.button-group button:hover:not(:disabled) { opacity:0.9; }
@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">Off-Boarding</button>
<button class="tab-button" data-tab="tweaksTab">Tweaks</button>
<button class="tab-button" data-tab="SVSAppsTab">SVS APPs</button>
</div>
<div class="content">
<!-- On-Boarding Tab -->
<div id="onboardTab" class="tab-content active">
<h2>On-Boarding</h2>
<h3 style="color:var(--gray-color);">This new deployment method ensures everything is deployed smoothly!</h3>
<div class="columns-container">
<!-- left and right columns as before -->
<div class="checkbox-group column" id="leftColumn">
<label><input type="checkbox" id="selectAllLeftCheckbox" onclick="toggleLeftColumnCheckboxes(this)"> Select All</label>
<label><input type="checkbox" class="left-checkbox" name="setSVSPowerplan"> Set SVS Powerplan</label>
<label><input type="checkbox" class="left-checkbox" name="installSVSMSPModule"> Install SVSMSP Module</label>
<label><input type="checkbox" class="left-checkbox" name="installCyberQP"> Install CyberQP</label>
<label><input type="checkbox" class="left-checkbox" name="installSplashtop"> Install Splashtop</label>
<label><input type="checkbox" class="left-checkbox" name="installSVSHelpDesk"> Install SVSHelpDesk</label>
<label><input type="checkbox" class="left-checkbox" name="installThreatLocker"> Install ThreatLocker</label>
<label><input type="checkbox" class="left-checkbox" name="installRocketCyber"> Install RocketCyber</label>
<label><input type="checkbox" class="left-checkbox" name="installDattoRMM" 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>
</div>
</div>
<div class="checkbox-group column" id="rightColumn">
<label><input type="checkbox" class="right-checkbox" name="EnableBitLocker"> Enable BitLocker</label>
<label><input type="checkbox" class="right-checkbox" name="setedgedefaultsearch"> Set Edge Default Search Engine</label>
</div>
</div>
<div id="n8nPasswordContainer">
<label for="n8nPassword">Enter Password:</label><br>
<input type="password" id="n8nPassword" class="password-input" placeholder="Enter Password">
</div>
<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">
<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"> Uninstall SVSMSP Module</label>
<label><input type="checkbox" name="uninstallThreatLocker"> Uninstall ThreatLocker</label>
<label><input type="checkbox" name="uninstallCyberQP"> Uninstall CyberQP</label>
<label><input type="checkbox" name="uninstallDattoEDR"> Uninstall DattoEDR</label>
<label><input type="checkbox" name="uninstallDattoRMM"> Uninstall DattoRMM</label>
<label><input type="checkbox" name="uninstallDattoDEB"> Uninstall DattoDEB</label>
<label><input type="checkbox" name="uninstallRocketCyber"> Uninstall RocketCyber</label>
<label><input type="checkbox" name="uninstallSplashtop"> Uninstall Splashtop</label>
<label><input type="checkbox" name="uninstallSVSHelpdesk"> Uninstall SVSHelpdesk</label>
<label><input type="checkbox" name="uninstallSVSWatchtower"> 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">
<h2>Tweaks</h2>
<div class="columns-container">
<div class="column">
<h3>System Optimizations</h3>
<label><input type="checkbox" id="setedgedefaultsearchCheckbox" name="setedgedefaultsearch"> Set Edge Default Search Engine</label>
<label><input type="checkbox" id="setWindowsPerformanceCheckbox" name="setWindowsPerformance" onclick="toggleRadioButtons(this)"> Optimize Windows Performance</label>
<div id="windowsPerformanceOptions" style="display:none; margin-left:20px;">
<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" id="stopUnnecessaryServicesCheckbox" name="stopUnnecessaryServices"> Stop Unnecessary Services</label>
</div>
<div class="column">
<h3>Additional Tweaks</h3>
<label><input type="checkbox" id="disableAnimationsCheckbox" name="disableAnimations"> Disable Animations</label>
<label><input type="checkbox" id="optimizePerformanceCheckbox" name="optimizePerformance"> Optimize Application Performance</label>
<label><input type="checkbox" id="increaseFontSizeCheckbox" name="increaseFontSize"> Increase Font Size</label>
</div>
<div class="column">
<h3>Miscellaneous</h3>
<label><input type="checkbox" id="enableDarkModeCheckbox" name="enableDarkMode"> Enable Dark Mode</label>
<label><input type="checkbox" id="clearTempFilesCheckbox" name="clearTempFiles"> Clear Temporary Files</label>
</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">
<h2>SVS APPs</h2>
<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"> 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>
<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">
<button class="install-button" onclick="triggerSVSApps()">Install SVS Apps</button>
</div>
</div>
<!-- Exit -->
<div class="button-group">
<button class="exit-button" onclick="endSession()">Exit</button>
</div>
<!-- Log area is present but hidden via CSS -->
<div class="log" id="logArea"><p>Logs will appear here...</p></div>
</div>
</div>
<script>
// All your existing JS: tab navigation, toggle functions, triggerInstall, fetchLogs, etc.
</script>
</body>
</html>
"@
}
# Launch the UI
Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:8081/"
#region HTTP Listener Route Handling
try {
while ($listener.IsListening) {
$ctx = $listener.GetContext()
$req = $ctx.Request
$res = $ctx.Response
switch ($req.Url.AbsolutePath) {
"/" {
$html = GetHtmlContent
$bytes = [System.Text.Encoding]::UTF8.GetBytes($html)
$res.ContentType = "text/html"
$res.ContentLength64 = $bytes.Length
$res.OutputStream.Write($bytes,0,$bytes.Length)
$res.OutputStream.Close()
}
"/getn8npw" {
if ($req.HttpMethod -eq "POST") {
$body = (New-Object IO.StreamReader $req.InputStream).ReadToEnd() | ConvertFrom-Json
Get-N8nWebhookData -AuthHeaderValue $body.password
$sites = Install-DattoRMM-Helper -ApiUrl $ApiUrl -ApiKey $ApiKey -ApiSecretKey $ApiSecretKey -FetchSitesOnly
if ($sites) {
$json = $sites | ConvertTo-Json
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)
$res.ContentType = "application/json"
$res.ContentLength64 = $bytes.Length
$res.OutputStream.Write($bytes,0,$bytes.Length)
} else {
$res.StatusCode = 500
$res.OutputStream.Write(([System.Text.Encoding]::UTF8.GetBytes("No sites found")),0,14)
}
$res.OutputStream.Close()
}
}
"/installSVSMSPModule" {
if ($req.HttpMethod -eq "GET") {
try { Install-SVSMSP -InstallToolkit; $msg="SVS Module triggered"; $code=200 }
catch { $msg="Error: $_"; $code=500 }
$res.StatusCode = $code
$bytes = [System.Text.Encoding]::UTF8.GetBytes($msg)
$res.OutputStream.Write($bytes,0,$bytes.Length)
$res.OutputStream.Close()
}
}
# … include the rest of your endpoints (/installrmm, /setSVSPowerplan, /installCyberQP, etc.) exactly as before …
"/quit" {
if ($req.HttpMethod -eq "GET") {
$res.OutputStream.Write(([System.Text.Encoding]::UTF8.GetBytes("Shutting down")),0,12)
$res.OutputStream.Close()
$listener.Stop()
break
}
}
default {
$res.StatusCode = 404
$res.OutputStream.Write(([System.Text.Encoding]::UTF8.GetBytes("Not Found")),0,9)
$res.OutputStream.Close()
}
}
}
}
finally {
if ($listener) {
Write-LogHybrid -Message "Stopping listener." -Level Info
$listener.Stop()
$listener.Close()
}
}