1580 lines
69 KiB
PowerShell
1580 lines
69 KiB
PowerShell
### To Modify as of January 27 2025
|
||
|
||
### Notes:
|
||
### - This script creates a GUI with tabs (On-Boarding, Off-Boarding, Tweaks, Steph's Pick).
|
||
### - In the On-Boarding tab, if the user selects “Select All,” then all checkboxes are checked.
|
||
### In particular, the DattoRMM checkbox will be checked and its sub‑options will expand.
|
||
### - All client‑side JavaScript is wrapped in a DOMContentLoaded event listener to ensure proper initialization.
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 1) CREATE A GLOBAL LOG CACHE
|
||
# ---------------------------------------------------------------------------
|
||
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-Log -Message "Missing required parameters. Please provide ApiUrl, ApiKey, and ApiSecretKey." -Level "Error" -LogToEvent
|
||
return
|
||
}
|
||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||
Write-Log -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-Log -Message "OAuth token fetched successfully." -Level "Success" -LogToEvent
|
||
} catch {
|
||
Write-Log -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 {
|
||
$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 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
|
||
|
||
#region NEW: Install-StephsPick
|
||
function Install-StephsPick {
|
||
param (
|
||
[array]$Packages
|
||
)
|
||
Write-LogHybrid -Message "Starting Steph's Pick installation" -Level "Info"
|
||
foreach ($package in $Packages) {
|
||
try {
|
||
$cmd = "winget install --id $package --silent"
|
||
Write-LogHybrid -Message "Executing: $cmd" -Level "Info"
|
||
Invoke-Expression $cmd
|
||
}
|
||
catch {
|
||
Write-LogHybrid -Message "Error installing package $package`: $($_.Exception.Message)" -Level "Error"
|
||
}
|
||
}
|
||
Write-LogHybrid -Message "Steph's Pick installation completed" -Level "Success"
|
||
}
|
||
#endregion
|
||
|
||
# ----------------------------------------------------------------------------------
|
||
# START THE HTTP LISTENER
|
||
# ----------------------------------------------------------------------------------
|
||
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 $_
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
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 {
|
||
--background-color: rgba(18, 18, 18, 1);
|
||
--border-color: rgba(255, 127, 0, 0.25);
|
||
--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);
|
||
--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;
|
||
--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="stephsPickTab" aria-expanded="false">Steph's Pick</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>
|
||
<!-- When "Install" is clicked, triggerInstall() will first install the module if needed -->
|
||
<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">
|
||
<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 class="button-group">
|
||
<button class="install-button" onclick="triggerOffboard()">Offboard</button>
|
||
</div>
|
||
</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>
|
||
<!-- Steph's Pick Tab -->
|
||
<div id="stephsPickTab" class="tab-content inactive">
|
||
<h2>Steph's Pick</h2>
|
||
<div class="column">
|
||
<h3 style="font-size: 1.5rem; font-weight: bold;">Apps</h3>
|
||
<div class="checkbox-group">
|
||
<label>
|
||
<input type="checkbox" id="installAppleiCloudCheckbox" name="installAppleiCloud">
|
||
Install Apple iCloud
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="installObsidianCheckbox" name="installObsidian">
|
||
Install Obsidian
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="installFlameshotCheckbox" name="installFlameshot">
|
||
Install Flameshot
|
||
</label>
|
||
<label>
|
||
<input type="checkbox" id="installSublimeTextCheckbox" name="installSublimeText">
|
||
Install Sublime Text 4
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="button-group">
|
||
<button class="install-button" onclick="triggerStephsPick()">Install Steph's Pick</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>
|
||
// Wrap all JavaScript in DOMContentLoaded to ensure proper initialization.
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
|
||
// Tab Switching
|
||
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');
|
||
});
|
||
});
|
||
|
||
// Updated Select All functionality for the left column:
|
||
// This now calls toggleDattoRMMOptions() to ensure Datto sub‑items expand.
|
||
window.toggleLeftColumnCheckboxes = function(selectAllCheckbox) {
|
||
const leftCheckboxes = document.querySelectorAll('#leftColumn input[type="checkbox"]:not(#selectAllLeftCheckbox)');
|
||
leftCheckboxes.forEach(checkbox => {
|
||
checkbox.checked = selectAllCheckbox.checked;
|
||
});
|
||
// Instead of toggleDattoRMMVisibility, call toggleDattoRMMOptions to handle sub-items.
|
||
toggleDattoRMMOptions();
|
||
};
|
||
|
||
// Offboard Select All
|
||
window.toggleOffboardCheckboxes = function(selectAllCheckbox) {
|
||
const checkboxes = document.querySelectorAll('#offboardTab input[type="checkbox"]:not(#selectAllOffboardCheckbox)');
|
||
checkboxes.forEach(checkbox => {
|
||
checkbox.checked = selectAllCheckbox.checked;
|
||
});
|
||
};
|
||
|
||
// DattoRMM options toggling
|
||
window.toggleDattoRMMOptions = function() {
|
||
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;
|
||
});
|
||
}
|
||
};
|
||
|
||
// Trigger Offboard
|
||
window.triggerOffboard = function() {
|
||
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");
|
||
});
|
||
};
|
||
|
||
// Toggle radio buttons for Windows Performance
|
||
window.toggleRadioButtons = function(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;
|
||
}
|
||
};
|
||
|
||
// triggerInstall() function for On-Boarding tab
|
||
window.triggerInstall = async function() {
|
||
// If the "Install SVSMSP Module" checkbox is checked, install that module first.
|
||
if (document.querySelector('input[name="installSVSMSPModule"]').checked) {
|
||
appendLog("Installing SVSMSP Module (Priority 1)...", "cyan");
|
||
try {
|
||
let response = await fetch('/installSVSMSPModule', { method: 'GET' });
|
||
if (!response.ok) {
|
||
throw new Error("Failed to install SVSMSP Module.");
|
||
}
|
||
appendLog("SVSMSP Module installation completed.", "green");
|
||
} catch (error) {
|
||
appendLog("Error installing SVSMSP Module: " + error.message, "red");
|
||
return; // Abort further installation if module installation fails.
|
||
}
|
||
}
|
||
// Continue with other tasks.
|
||
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 dropdown = document.getElementById('dattoRmmDropdown');
|
||
const UID = dropdown && dropdown.value ? dropdown.value : null;
|
||
const Name = dropdown && dropdown.options[dropdown.selectedIndex] ? dropdown.options[dropdown.selectedIndex].text : null;
|
||
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");
|
||
}
|
||
}
|
||
};
|
||
|
||
// Steph's Pick trigger
|
||
window.triggerStephsPick = function() {
|
||
const packages = [];
|
||
if (document.getElementById('installAppleiCloudCheckbox').checked) {
|
||
packages.push("Apple.iCloud");
|
||
}
|
||
if (document.getElementById('installObsidianCheckbox').checked) {
|
||
packages.push("Obsidian.Obsidian");
|
||
}
|
||
if (document.getElementById('installFlameshotCheckbox').checked) {
|
||
packages.push("Flameshot.Flameshot");
|
||
}
|
||
if (document.getElementById('installSublimeTextCheckbox').checked) {
|
||
packages.push("SublimeHQ.SublimeText.4");
|
||
}
|
||
if (packages.length === 0) {
|
||
appendLog("Please select at least one package to install.", "red");
|
||
return;
|
||
}
|
||
appendLog("Installing Steph's Pick packages: " + packages.join(", "), "cyan");
|
||
fetch('/installStephsPick', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ packages: packages })
|
||
})
|
||
.then(response => {
|
||
if (!response.ok) {
|
||
throw new Error("Failed to install Steph's Pick packages.");
|
||
}
|
||
return response.text();
|
||
})
|
||
.then(message => {
|
||
appendLog(message, "green");
|
||
})
|
||
.catch(error => {
|
||
appendLog("Error: " + error.message, "red");
|
||
});
|
||
};
|
||
|
||
// End session
|
||
window.endSession = function() {
|
||
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");
|
||
});
|
||
};
|
||
|
||
// Append log messages
|
||
window.appendLog = function(message, color = "white") {
|
||
const log = document.createElement('p');
|
||
log.style.color = color;
|
||
log.textContent = message;
|
||
document.getElementById('logArea').appendChild(log);
|
||
};
|
||
|
||
// Poll server logs every 3 seconds
|
||
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);
|
||
|
||
}); // End DOMContentLoaded
|
||
</script>
|
||
</body>
|
||
</html>
|
||
"@
|
||
}
|
||
|
||
Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:8081/"
|
||
|
||
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 {
|
||
$response.StatusCode = 405
|
||
$response.StatusDescription = "Method Not Allowed"
|
||
$responseString = "Error: Only POST requests are allowed."
|
||
$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()
|
||
}
|
||
"/installSVSHelpDesk" {
|
||
if ($request.HttpMethod -eq "GET") {
|
||
try {
|
||
Install-SVSHelpDesk
|
||
$responseString = "Install SVSHelpDesk triggered successfully."
|
||
$response.StatusCode = 200
|
||
} catch {
|
||
$responseString = "Error triggering Install SVSHelpDesk: $_"
|
||
$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()
|
||
}
|
||
"/EdgeDefaultSearchEngine" {
|
||
if ($request.HttpMethod -eq "GET") {
|
||
try {
|
||
Write-LogHybrid -Message "Setting Edge Default Search Engine started." -Level "Info"
|
||
Set-EdgeDefaultSearchEngine
|
||
Write-LogHybrid -Message "Edge Default Search Engine set successfully." -Level "Success"
|
||
$responseString = "Edge Default Search Engine triggered successfully."
|
||
$response.StatusCode = 200
|
||
} catch {
|
||
Write-LogHybrid -Message "Error setting Edge Default Search Engine: $($_.Exception.Message)" -Level "Error"
|
||
$responseString = "Error attempting to set Edge Default Search Engine: $_"
|
||
$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()
|
||
}
|
||
# Steph's Pick Route
|
||
"/installStephsPick" {
|
||
if ($request.HttpMethod -eq "POST") {
|
||
try {
|
||
$bodyStream = New-Object IO.StreamReader $request.InputStream
|
||
$body = $bodyStream.ReadToEnd()
|
||
$data = ConvertFrom-Json $body
|
||
$selectedPackages = $data.packages
|
||
if (-not $selectedPackages -or $selectedPackages.Count -eq 0) {
|
||
$selectedPackages = @("Apple.iCloud", "Obsidian.Obsidian", "Flameshot.Flameshot", "SublimeHQ.SublimeText.4")
|
||
}
|
||
Install-StephsPick -Packages $selectedPackages
|
||
$responseString = "Steph's Pick installation triggered successfully."
|
||
$response.StatusCode = 200
|
||
}
|
||
catch {
|
||
$responseString = "Error triggering Steph's Pick 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()
|
||
}
|
||
"/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()
|
||
}
|
||
}
|
||
"/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"
|
||
}
|
||
}
|