This commit is contained in:
2025-05-17 14:39:37 -04:00
parent 407a165830
commit 23e414a3fc

View File

@@ -1,10 +1,10 @@
### To Modify as of January 27 2025 ### To Modify as of January 27 2025
### let's start thinking about the write-log -TaskCategory "On-boarding" or "Off-boarding" ### 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 ### need RGB color codes from john, once we picked the RGBA colors
### add the .net silent install tweaks to toolkit ### 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 ### 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 ### added offboard check boxes for DattoRMM, DattoDEB, RocketCyber, CyberQP, SVSHelpdesk and Splashtop
### need to fix path in the uninstall-DattoEDR - ### 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 ####### ❌ [Error] [GeneralTask] Uninstallation command 'C:\Program Files\Infocyte\Agent\agent.exe' not found. (Event ID: 3000) - bad path
@@ -42,13 +42,6 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
"Success" { ([char]0x2705) } "Success" { ([char]0x2705) }
"General" { ([char]0x1F4E6) } "General" { ([char]0x1F4E6) }
} }
$Color = switch ($Level) {
"Info" { "Cyan" }
"Warning" { "Yellow" }
"Error" { "Red" }
"Success" { "Green" }
"General" { "White" }
}
$logEntry = [PSCustomObject]@{ $logEntry = [PSCustomObject]@{
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
Level = $Level Level = $Level
@@ -70,7 +63,7 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
Write-EventLog -LogName $EventLog -Source $EventSource -EntryType $EntryType -EventId $EventID -Message $EventMessage Write-EventLog -LogName $EventLog -Source $EventSource -EntryType $EntryType -EventId $EventID -Message $EventMessage
} }
catch { catch {
Write-Host "([char]0x26A0) [Warning] [EventLog] Failed to write to Event Log: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host " [Warning] [EventLog] Failed to write to Event Log: $($_.Exception.Message)" -ForegroundColor Yellow
} }
} }
} }
@@ -128,11 +121,11 @@ function Install-DattoRMM-Helper {
Write-LogHybrid -Message "Fetching OAuth token..." -Level "Info" Write-LogHybrid -Message "Fetching OAuth token..." -Level "Info"
try { try {
$securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force $securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force
$apiGenToken = Invoke-WebRequest -Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword)) ` $apiGenToken = Invoke-WebRequest -Credential (New-Object System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword)) `
-Uri ('{0}/auth/oauth/token' -f $ApiUrl) ` -Uri ("{0}/auth/oauth/token" -f $ApiUrl) `
-Method 'POST' ` -Method 'POST' `
-ContentType 'application/x-www-form-urlencoded' ` -ContentType 'application/x-www-form-urlencoded' `
-Body ('grant_type=password&username={0}&password={1}' -f $ApiKey, $ApiSecretKey) ` -Body ("grant_type=password&username={0}&password={1}" -f $ApiKey, $ApiSecretKey) `
| ConvertFrom-Json | ConvertFrom-Json
$requestToken = $apiGenToken.access_token $requestToken = $apiGenToken.access_token
Write-LogHybrid -Message "OAuth token fetched successfully." -Level "Success" -LogToEvent Write-LogHybrid -Message "OAuth token fetched successfully." -Level "Success" -LogToEvent
@@ -140,23 +133,19 @@ function Install-DattoRMM-Helper {
Write-LogHybrid -Message "Failed to fetch OAuth token. Details: $($_.Exception.Message)" -Level "Error" -LogToEvent Write-LogHybrid -Message "Failed to fetch OAuth token. Details: $($_.Exception.Message)" -Level "Error" -LogToEvent
return return
} }
$getHeaders = @{"Authorization" = "Bearer $requestToken"}
if ($FetchSitesOnly) { if ($FetchSitesOnly) {
Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan
try { try {
$getSites = Invoke-WebRequest -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers $getHeaders -ContentType "application/json" $getSites = Invoke-WebRequest -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers @{ "Authorization" = "Bearer $requestToken" } -ContentType "application/json"
$sitesJson = $getSites.Content | ConvertFrom-Json $sitesJson = $getSites.Content | ConvertFrom-Json
$siteList = $sitesJson.sites | ForEach-Object { $siteList = $sitesJson.sites | ForEach-Object {
[PSCustomObject]@{ [PSCustomObject]@{ Name = $_.name; UID = $_.uid }
Name = $_.name
UID = $_.uid
}
} }
Write-Host "Successfully fetched list of sites." -ForegroundColor Green Write-Host "Successfully fetched list of sites." -ForegroundColor Green
return $siteList return $siteList
} }
catch { catch {
Write-Host "Failed to fetch sites from the API. Details: $($_.Exception.Message)" -ForegroundColor Red Write-Host "Failed to fetch sites: $($_.Exception.Message)" -ForegroundColor Red
return return
} }
} }
@@ -165,46 +154,34 @@ function Install-DattoRMM-Helper {
#region LastPass Extensions #region LastPass Extensions
function ForceInstall-LastPassChrome { function ForceInstall-LastPassChrome {
# Chrome (Web Store) extension ID and update URL for LastPass $ExtensionID = "hdokiejnpimakedhajhdlcegeplioahd"
$ExtensionID_LastPass_Chrome = "hdokiejnpimakedhajhdlcegeplioahd" $UpdateURL = "https://clients2.google.com/service/update2/crx"
$ChromeUpdateURL = "https://clients2.google.com/service/update2/crx" $RegPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
$ChromePolicyRegPath = "HKLM:\SOFTWARE\Policies\Google\Chrome\ExtensionInstallForcelist"
try { try {
New-Item -Path "HKLM:\SOFTWARE\Policies\Google" -Force -ErrorAction SilentlyContinue | Out-Null New-Item -Path (Split-Path $RegPath) -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path "HKLM:\SOFTWARE\Policies\Google\Chrome" -Force -ErrorAction SilentlyContinue | Out-Null New-Item -Path $RegPath -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $ChromePolicyRegPath -Force -ErrorAction SilentlyContinue | Out-Null Set-ItemProperty -Path $RegPath -Name "1" -Value "$ExtensionID;$UpdateURL" -ErrorAction Stop
$chromeValue = "$ExtensionID_LastPass_Chrome;$ChromeUpdateURL" Write-Host "Configured LastPass Chrome extension."
Set-ItemProperty -Path $ChromePolicyRegPath -Name "1" -Value $chromeValue -ErrorAction Stop
Write-Host "Successfully configured LastPass in Chrome ExtensionInstallForcelist."
} }
catch { catch {
Write-Host "Failed to configure Chrome: $($_.Exception.Message)" -ForegroundColor Red Write-Host "Failed Chrome config: $($_.Exception.Message)" -ForegroundColor Red
} }
} }
function ForceInstall-LastPassEdge { function ForceInstall-LastPassEdge {
# Edge (Add-ons Store) extension ID and update URL for LastPass $ExtensionID = "bbcinlkgjjkejfdpemiealijmmooekmp"
$ExtensionID_LastPass_Edge = "bbcinlkgjjkejfdpemiealijmmooekmp" $UpdateURL = "https://edge.microsoft.com/extensionwebstorebase/v1/crx"
$EdgeUpdateURL = "https://edge.microsoft.com/extensionwebstorebase/v1/crx" $RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist"
$EdgePolicyRegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionInstallForcelist"
try { try {
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft" -Force -ErrorAction SilentlyContinue | Out-Null New-Item -Path (Split-Path $RegPath) -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Edge" -Force -ErrorAction SilentlyContinue | Out-Null New-Item -Path $RegPath -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -Path $EdgePolicyRegPath -Force -ErrorAction SilentlyContinue | Out-Null Set-ItemProperty -Path $RegPath -Name "1" -Value "$ExtensionID;$UpdateURL" -ErrorAction Stop
$edgeValue = "$ExtensionID_LastPass_Edge;$EdgeUpdateURL" Write-Host "Configured LastPass Edge extension."
Set-ItemProperty -Path $EdgePolicyRegPath -Name "1" -Value $edgeValue -ErrorAction Stop
Write-Host "Successfully configured LastPass in Edge ExtensionInstallForcelist."
} }
catch { catch {
Write-Host "Failed to configure Edge: $($_.Exception.Message)" -ForegroundColor Red Write-Host "Failed Edge config: $($_.Exception.Message)" -ForegroundColor Red
} }
} }
function Install-LastPassExtensions { param([switch]$Chrome,[switch]$Edge)
function Install-LastPassExtensions {
param(
[switch]$Chrome,
[switch]$Edge
)
if ($Chrome) { ForceInstall-LastPassChrome } if ($Chrome) { ForceInstall-LastPassChrome }
if ($Edge) { ForceInstall-LastPassEdge } if ($Edge) { ForceInstall-LastPassEdge }
} }
@@ -215,167 +192,80 @@ function Install-SVSMSP {
param ( param (
[switch]$Cleanup, [switch]$Cleanup,
[switch]$InstallToolkit, [switch]$InstallToolkit,
[Parameter(Mandatory = $false)] [array]$AllModules = @(@{ModuleName="SVS_Toolkit"},@{ModuleName="SVSMSP"}),
[array]$AllModules = @(
@{ ModuleName = "SVS_Toolkit" },
@{ ModuleName = "SVSMSP" }
),
[Parameter(Mandatory = $false)]
[string]$NewModuleName = "SVSMSP", [string]$NewModuleName = "SVSMSP",
[Parameter(Mandatory = $false)] [array]$AllRepositories = @(@{RepoName="SVS_Repo"},@{RepoName="SVS_Toolkit"}),
[array]$AllRepositories = @(
@{ RepoName = "SVS_Repo" },
@{ RepoName = "SVS_Toolkit" }
),
[Parameter(Mandatory = $false)]
[string]$NewRepositoryName = "SVS_Repo", [string]$NewRepositoryName = "SVS_Repo",
[Parameter(Mandatory = $false)]
[string]$NewRepositoryURL = "http://proget.svstools.ca:8083/nuget/SVS_Repo/", [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" [string]$LogFilePath = "$env:SVSMSP\svstoolkit.log"
) )
function Perform-Cleanup { function Perform-Cleanup {
Write-LogHybrid -Message "Cleanup mode enabled. Starting cleanup process..." -Level "Info" -LogToEvent Write-LogHybrid -Message "Cleanup mode enabled..." -Level Info -LogToEvent
Write-LogHybrid -Message "Starting cleanup of old modules..." -Level "Info" -LogToEvent foreach ($m in $AllModules) {
foreach ($module in $AllModules) { if (Get-Module -Name $m.ModuleName -ListAvailable) {
$ModuleName = $module.ModuleName Write-LogHybrid -Message "Removing $($m.ModuleName)..." -Level Warning -LogToEvent
if (Get-Module -Name $ModuleName -ListAvailable) { try { Uninstall-Module -Name $m.ModuleName -AllVersions -Force; Write-LogHybrid -Message "Removed $($m.ModuleName)" -Level Success -LogToEvent }
Write-LogHybrid -Message "Removing module '$ModuleName'..." -Level "Warning" -LogToEvent catch { Write-LogHybrid -Message "Failed to remove $($m.ModuleName): $_" -Level Error -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 { foreach ($r in $AllRepositories) {
Write-LogHybrid -Message "Module '$ModuleName' not found. Skipping..." -Level "Info" -LogToEvent 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 "Starting cleanup of old repositories..." -Level "Info" -LogToEvent Write-LogHybrid -Message "Cleanup complete." -Level Success -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 { function Perform-ToolkitInstallation {
Perform-Cleanup Perform-Cleanup
$localMachineExecutionPolicy = Get-ExecutionPolicy -Scope LocalMachine if ((Get-ExecutionPolicy -Scope LocalMachine) -ne "RemoteSigned") {
if ($localMachineExecutionPolicy -ne "RemoteSigned") { Write-LogHybrid -Message "Setting execution policy to RemoteSigned..." -Level Warning -LogToEvent
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 }
try { catch { Write-LogHybrid -Message "Failed to set policy: $_" -Level Error -LogToEvent; return }
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
Write-LogHybrid -Message "Execution policy set to RemoteSigned successfully." -Level "Success" -LogToEvent
} }
catch { Install-PackageProvider -Name NuGet -Force -Scope AllUsers -Confirm:$false
Write-LogHybrid -Message "Failed to set execution policy. Error: $_" -Level "Error" -LogToEvent if (-not (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) {
return 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 }
} }
Install-PackageProvider -Name "NuGet" -Force -Scope AllUsers -Confirm:$false Write-LogHybrid -Message "Install-SVSMSP started." -Level Info -LogToEvent
Write-LogHybrid -Message "Registering the new repository '$NewRepositoryName'..." -Level "Info" -LogToEvent if ($Cleanup) { Perform-Cleanup; return }
try { if ($InstallToolkit) { Perform-ToolkitInstallation; return }
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 Perform-ToolkitInstallation
} }
#endregion SVS Module #endregion
#region HTTP Listener Setup #region HTTP Listener Setup
try { try {
$listener = New-Object System.Net.HttpListener $listener = New-Object System.Net.HttpListener
if (-not $listener) {
throw "Failed to initialize HttpListener."
}
$listener.Prefixes.Add("http://localhost:8081/") $listener.Prefixes.Add("http://localhost:8081/")
Write-LogHybrid -Message "Listener initialized with prefix http://localhost:8081/" -Level "Info" Write-LogHybrid -Message "Listener prefix added." -Level Info
$listener.Start() $listener.Start()
Write-LogHybrid -Message "Listener started successfully." -Level "Info" Write-LogHybrid -Message "Listener started." -Level Info
} catch { } catch {
Write-LogHybrid -Message "Critical error initializing listener: $($_.Exception.Message)" -Level "Error" Write-LogHybrid -Message "Listener init error: $($_.Exception.Message)" -Level Error
throw $_ throw
} }
#endregion #endregion
function Get-N8nWebhookData { function Get-N8nWebhookData {
param ( param ([string]$AuthHeaderValue)
[Parameter(Mandatory = $true)]
[string]$AuthHeaderValue
)
$url = "https://automate.svstools.ca/webhook/svsmspkit" $url = "https://automate.svstools.ca/webhook/svsmspkit"
$headers = @{ $headers = @{ "SVSMSPKit" = $AuthHeaderValue }
"SVSMSPKit" = $AuthHeaderValue
}
try { try {
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get $resp = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
Write-Host "Response received successfully:" -ForegroundColor Green foreach ($prop in $resp.PSObject.Properties) {
$data = $response Set-Variable -Name $prop.Name -Value $prop.Value -Scope Global
$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 { return $resp
Write-Host "Error making the GET request:" -ForegroundColor Red } catch {
Write-Host $_.Exception.Message Write-Host "Webhook GET error: $($_.Exception.Message)" -ForegroundColor Red
return $null return $null
} }
} }
@@ -386,191 +276,77 @@ function GetHtmlContent {
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SVS TaskGate</title> <title>SVS TaskGate</title>
<link rel="icon" href="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_Favicon.ico" type="image/x-icon"> <link rel="icon" href="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_Favicon.ico">
<style> <style>
:root { :root {
/* Cool Palette */
--background-color: rgba(18, 18, 18, 1); --background-color: rgba(18, 18, 18, 1);
--border-color: rgba(255, 127, 0, 0.25); --border-color: rgba(255,127, 0, 0.25);
/* Neutral Colors */ --white-color: rgba(255,255,255,1);
--white-color: rgba(255, 255, 255); --gray-color: rgba(102,102,102,1);
--gray-color: rgba(102, 102, 102); --dark-gray-color: rgba( 51, 51, 51,1);
--dark-gray-color: rgba(51, 51, 51); --light-gray-color: rgba(187,187,187,1);
--light-gray-color: rgba(187, 187, 187); --btn-sidebar-light-gray: rgba( 68, 68, 68,1);
/* Sidebar Button Colors */ --btn-sidebar-blue: rgba( 30,144,255,1);
--btn-sidebar-light-gray: rgba(68, 68, 68); --btn-hover: rgba( 0, 86,179,1);
--btn-sidebar-blue: rgba(30, 144, 255, 1);
--btn-hover: rgba(0, 86, 179, 1);
--btn-hover-scale: 1.05; --btn-hover-scale: 1.05;
/* Fixed go button colors */ --btn-success: rgba( 40,167, 69,1);
--btn-success: rgba(40, 167, 69, 1); --btn-success-disabled: rgba(108,117,125,1);
--btn-success-disabled: rgba(108, 117, 125, 1); --btn-danger: rgba(220, 53, 69,1);
--btn-danger: rgba(220, 53, 69, 1);
} }
body { body {
font-family: Arial, sans-serif; margin:0;padding:0;
margin: 0; font-family:Arial,sans-serif;
padding: 0; background:var(--background-color);
background-color: var(--background-color); color:var(--white-color);
color: var(--white-color); height:100%;overflow:hidden;
height: 100%;
overflow: hidden;
} }
.logo-container { padding:20px; background:var(--background-color); }
.logo-container { .logo-container img { max-width:300px; }
text-align: left; .container { display:flex; height:100vh; overflow:hidden; }
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 { .sidebar {
width: 200px; width:200px; padding:10px;
height: 100%; background:var(--background-color);
background-color: var(--background-color);
padding: 10px;
} }
.sidebar button { .sidebar button {
display: block; width:100%; margin-bottom:10px; padding:10px;
width: 100%; background:var(--btn-sidebar-light-gray);
margin-bottom: 10px; color:var(--white-color); border:none; border-radius:5px;
padding: 10px; text-align:left; cursor:pointer;
color: var(--white-color); transition:background 0.3s,transform 0.2s;
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:var(--btn-sidebar-blue); }
.sidebar button.active { .sidebar button:hover { background:var(--btn-hover); transform:scale(var(--btn-hover-scale)); }
background-color: var(--btn-sidebar-blue);
}
.sidebar button:hover {
background-color: var(--btn-hover);
transform: scale(var(--btn-hover-scale));
}
.content { .content {
flex: 1; flex:1; padding:20px;
padding: 20px; overflow-y:auto; max-height:calc(100vh-50px);
overflow-y: auto;
max-height: calc(100vh - 50px);
} }
.tab-content { display:none; }
.tab-content { .tab-content.active { display:block; }
display: none; .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; }
.tab-content.active { .button-group { margin-top:20px; text-align:right; }
display: block; .log { display:none !important; }
}
.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;
}
/* Hide the entire log pane */
.log {
display: none !important;
}
/* Uniform styling for all .button-group buttons */
.button-group button { .button-group button {
display: inline-block; display:inline-block; padding:0.75rem 1.5rem;
padding: 0.75rem 1.5rem; margin-left:0.5rem; font-size:1rem; line-height:1.4;
margin-left: 0.5rem; border:none; border-radius:0.375rem; cursor:pointer;
font-size: 1rem; transition:opacity 0.1s ease;
line-height: 1.4;
text-align: center;
border: none;
border-radius: 0.375rem;
cursor: pointer;
transition: opacity 0.1s ease;
}
/* Remove left margin on first button */
.button-group > button:first-child {
margin-left: 0;
}
/* Green go buttons */
.install-button {
background-color: var(--btn-success);
color: #fff;
}
.install-button:disabled {
background-color: var(--btn-success-disabled);
cursor: not-allowed;
}
/* Red danger buttons */
.exit-button {
background-color: var(--btn-danger);
color: #fff;
}
/* Hover effect */
.button-group button:hover:not(:disabled) {
opacity: 0.9;
}
@media (max-width: 768px) {
.container {
flex-direction: column;
}
.sidebar {
width: 100%;
}
} }
.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> </style>
</head> </head>
<body> <body>
@@ -580,24 +356,43 @@ function GetHtmlContent {
<div class="container"> <div class="container">
<div class="sidebar"> <div class="sidebar">
<button class="tab-button active" data-tab="onboardTab" aria-expanded="true">On-Boarding</button> <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="offboardTab">Off-Boarding</button>
<button class="tab-button" data-tab="tweaksTab" aria-expanded="false">Tweaks</button> <button class="tab-button" data-tab="tweaksTab">Tweaks</button>
<button class="tab-button" data-tab="SVSAppsTab" aria-expanded="false">SVS APPs</button> <button class="tab-button" data-tab="SVSAppsTab">SVS APPs</button>
</div> </div>
<div class="content"> <div class="content">
<!-- On-Boarding Tab --> <!-- On-Boarding Tab -->
<div id="onboardTab" class="tab-content active"> <div id="onboardTab" class="tab-content active">
<h2>On-Boarding</h2> <h2>On-Boarding</h2>
<h3 class="subtitle">This new deployment method ensures everything is successfully deployed with greater ease!</h3> <h3 style="color:var(--gray-color);">This new deployment method ensures everything is deployed smoothly!</h3>
<div class="columns-container"> <div class="columns-container">
<!-- leftColumn, rightColumn, etc... (unchanged) --> <!-- 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 id="n8nPasswordContainer" style="display: none;"> </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> <label for="n8nPassword">Enter Password:</label><br>
<input type="password" id="n8nPassword" class="password-input" placeholder="Enter Password"> <input type="password" id="n8nPassword" class="password-input" placeholder="Enter Password">
</div> </div>
<br> <div id="DattoRMMContainer" style="display:none;">
<div id="DattoRMMContainer" style="display: none;">
<label for="dattoRmmDropdown">Select a Datto RMM site:</label><br> <label for="dattoRmmDropdown">Select a Datto RMM site:</label><br>
<select id="dattoRmmDropdown" class="dropdown"> <select id="dattoRmmDropdown" class="dropdown">
<option value="">Fetching sites...</option> <option value="">Fetching sites...</option>
@@ -609,48 +404,164 @@ function GetHtmlContent {
<button class="install-button" onclick="triggerInstall()">Install</button> <button class="install-button" onclick="triggerInstall()">Install</button>
</div> </div>
</div> </div>
<!-- Off-Boarding, Tweaks, SVS Apps tabs all unchanged --> <!-- Off-Boarding Tab -->
<!-- ... --> <div id="offboardTab" class="tab-content">
<!-- Shared Exit Button --> <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"> <div class="button-group">
<button class="exit-button" onclick="endSession()">Exit</button> <button class="exit-button" onclick="endSession()">Exit</button>
</div> </div>
<!-- Log Area (now hidden via CSS) --> <!-- Log area is present but hidden via CSS -->
<div class="log" id="logArea"> <div class="log" id="logArea"><p>Logs will appear here...</p></div>
<p>Logs will appear here...</p>
</div> </div>
</div> </div>
</div> <script>
<script> // All your existing JS: tab navigation, toggle functions, triggerInstall, fetchLogs, etc.
// (All your existing JS unchanged: tab nav, toggle functions, triggerInstall, fetchLogs, etc.) </script>
</script>
</body> </body>
</html> </html>
"@ "@
} }
# Save and launch the HTML # Launch the UI
Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:8081/" Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:8081/"
#region HTTP Listener Route Handling #region HTTP Listener Route Handling
try { try {
while ($listener.IsListening) { while ($listener.IsListening) {
# (All your listener routing code as before) $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()
}
}
} }
}
catch {
Write-Host "Error: $($_.Exception.Message)"
} }
finally { finally {
if ($listener -ne $null) { if ($listener) {
try { Write-LogHybrid -Message "Stopping listener." -Level Info
Write-LogHybrid -Message "Stopping the listener." -Level "Info"
$listener.Stop() $listener.Stop()
$listener.Close() $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"
} }
} }