Update StackMonkey.ps1

This commit is contained in:
2025-06-29 04:27:09 -04:00
parent e49a435328
commit a3024818aa

View File

@@ -87,6 +87,21 @@
# ───────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────
# 1) ENTRYPOINT + PARAMETER DECLARATION # 1) ENTRYPOINT + PARAMETER DECLARATION
# ───────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────
function Invoke-ScriptMonkey {
[CmdletBinding(
DefaultParameterSetName='UI',
SupportsShouldProcess=$true,
ConfirmImpact='Medium'
)]
param(
[Parameter(Mandatory,ParameterSetName='Toolkit')] [switch]$SilentInstall,
[Parameter(Mandatory,ParameterSetName='DattoFetch')]
[Parameter(Mandatory,ParameterSetName='DattoInstall')]
[string]$N8nPassword,
)
# — all of your modules, helpers, functions, etc. go here —
[CmdletBinding( [CmdletBinding(
DefaultParameterSetName='UI', DefaultParameterSetName='UI',
@@ -122,19 +137,19 @@
#region — guarantee NuGet provider is present without prompting #region — guarantee NuGet provider is present without prompting
# ─── Top of script ─── # ─── Top of script ───
Import-Module PackageManagement -Force -ErrorAction SilentlyContinue | Out-Null Import-Module PackageManagement -Force -ErrorAction SilentlyContinue | Out-Null
Import-Module PowerShellGet -Force -ErrorAction SilentlyContinue | Out-Null Import-Module PowerShellGet -Force -ErrorAction SilentlyContinue | Out-Null
# ─── ensure TLS 1.2 + no prompts ─── # ─── ensure TLS 1.2 + no prompts ───
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue'
$ConfirmPreference = 'None' $ConfirmPreference = 'None'
# check if NuGet exists (no output—assigned to $nuget) # check if NuGet exists (no output—assigned to $nuget)
$nuget = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue $nuget = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue
if (-not $nuget) { if (-not $nuget) {
# install it (again, assignment suppresses the table) # install it (again, assignment suppresses the table)
Install-PackageProvider ` Install-PackageProvider `
-Name NuGet ` -Name NuGet `
@@ -146,26 +161,26 @@ if (-not $nuget) {
# re-query just for version info # re-query just for version info
$found = Get-PackageProvider -Name NuGet -ListAvailable $found = Get-PackageProvider -Name NuGet -ListAvailable
Write-Host "Installed NuGet provider v$($found.Version)" -ForegroundColor Green Write-Host "Installed NuGet provider v$($found.Version)" -ForegroundColor Green
} }
else { else {
Write-Host "NuGet provider already present (v$($found.Version))" -ForegroundColor DarkGray Write-Host "NuGet provider already present (v$($found.Version))" -ForegroundColor DarkGray
} }
# now import it silently # now import it silently
Import-PackageProvider -Name NuGet -Force -ErrorAction SilentlyContinue | Out-Null Import-PackageProvider -Name NuGet -Force -ErrorAction SilentlyContinue | Out-Null
# ensure trust PSGallery without its own output (so you don't get “untrusted repository” prompt # ensure trust PSGallery without its own output (so you don't get “untrusted repository” prompt
$gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue $gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue
if ($gallery.InstallationPolicy -ne 'Trusted') { if ($gallery.InstallationPolicy -ne 'Trusted') {
Set-PSRepository ` Set-PSRepository `
-Name PSGallery ` -Name PSGallery `
-InstallationPolicy Trusted ` -InstallationPolicy Trusted `
-ErrorAction SilentlyContinue | Out-Null -ErrorAction SilentlyContinue | Out-Null
Write-Host "PSGallery marked as Trusted" -ForegroundColor Green Write-Host "PSGallery marked as Trusted" -ForegroundColor Green
} }
#endregion #endregion
# ───────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────
@@ -178,8 +193,8 @@ if ($gallery.InstallationPolicy -ne 'Trusted') {
# Configurable endpoints # Configurable endpoints
$Global:DattoWebhookUrl = 'https://automate.svstools.ca/webhook/svsmspkit' $Global:DattoWebhookUrl = 'https://automate.svstools.ca/webhook/svsmspkit'
#region Get-DattoApiCredentials #region Get-DattoApiCredentials
function Get-DattoApiCredentials { function Get-DattoApiCredentials {
[CmdletBinding()] [CmdletBinding()]
param ( param (
[Parameter(Mandatory)][string]$Password [Parameter(Mandatory)][string]$Password
@@ -199,9 +214,9 @@ function Get-DattoApiCredentials {
Write-LogHybrid "Failed to fetch API credentials: $($_.Exception.Message)" Error DattoAuth Write-LogHybrid "Failed to fetch API credentials: $($_.Exception.Message)" Error DattoAuth
return $null return $null
} }
} }
function Get-DattoRmmSites { function Get-DattoRmmSites {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory)] [Parameter(Mandatory)]
@@ -268,15 +283,15 @@ function Get-DattoRmmSites {
catch { catch {
Throw "Failed to fetch sites from API: $_" Throw "Failed to fetch sites from API: $_"
} }
} }
# Initialize a global in-memory log cache # Initialize a global in-memory log cache
if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) { if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) {
$Global:LogCache = [System.Collections.ArrayList]::new() $Global:LogCache = [System.Collections.ArrayList]::new()
} }
# Core Write-Log function (advanced with event-log support) # Core Write-Log function (advanced with event-log support)
function Write-LogHelper { function Write-LogHelper {
[CmdletBinding()] [CmdletBinding()]
param( param(
@@ -318,12 +333,12 @@ if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.Arr
} }
if ($PassThru) { return $entry } if ($PassThru) { return $entry }
} }
# ───────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────
# WRITE-LOG HYBRID (single definition, chooses at runtime) # WRITE-LOG HYBRID (single definition, chooses at runtime)
# ───────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────
function Write-LogHybrid { function Write-LogHybrid {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory=$true)][string]$Message, [Parameter(Mandatory=$true)][string]$Message,
@@ -341,26 +356,26 @@ function Write-LogHybrid {
# fall back to your helper # fall back to your helper
Write-LogHelper -Message $Message -Level $Level -TaskCategory $TaskCategory -LogToEvent:$LogToEvent Write-LogHelper -Message $Message -Level $Level -TaskCategory $TaskCategory -LogToEvent:$LogToEvent
} }
} }
#endregion #endregion
# STACK = Scripted Tooling for Automated Client Kickoff # STACK = Scripted Tooling for Automated Client Kickoff
# MONKEY = Module-based Onboarding & Next-step Kickoff Engine Yoke # MONKEY = Module-based Onboarding & Next-step Kickoff Engine Yoke
# Conveys the idea of coupling tasks together and keeping them under control. # Conveys the idea of coupling tasks together and keeping them under control.
#region Config & Task Definitions #region Config & Task Definitions
# Define every task once here: # Define every task once here:
# Id → checkbox HTML `id` # Id → checkbox HTML `id`
# Name → URL path (`/Name`) # Name → URL path (`/Name`)
# Label → user-visible text # Label → user-visible text
# HandlerFn → the PowerShell function to invoke # HandlerFn → the PowerShell function to invoke
# Page → which tab/page it appears on # Page → which tab/page it appears on
$Global:Tasks = @( $Global:Tasks = @(
# On-Boarding, left column # On-Boarding, left column
@{ Id='setSVSPowerplan'; Name='setSVSPowerplan'; Label='Set SVS Powerplan'; HandlerFn='Handle-setSVSPowerPlan'; Page='onboard'; Column='left' }, @{ Id='setSVSPowerplan'; Name='setSVSPowerplan'; Label='Set SVS Powerplan'; HandlerFn='Handle-setSVSPowerPlan'; Page='onboard'; Column='left' },
@{ Id='installSVSMSPModule'; Name='installSVSMSPModule'; Label='Install SVSMSP Module'; HandlerFn='Handle-InstallSVSMSP'; Page='onboard'; Column='left' }, @{ Id='installSVSMSPModule'; Name='installSVSMSPModule'; Label='Install SVSMSP Module'; HandlerFn='Handle-InstallSVSMSP'; Page='onboard'; Column='left' },
@@ -390,28 +405,28 @@ $Global:Tasks = @(
# SVS Apps # SVS Apps
@{ Id='wingetLastpass'; Name='wingetLastpass'; Label='LastPass Desktop App'; HandlerFn='Install-WingetLastPass'; Page='SVSApps' } @{ Id='wingetLastpass'; Name='wingetLastpass'; Label='LastPass Desktop App'; HandlerFn='Install-WingetLastPass'; Page='SVSApps' }
) )
#endregion #endregion
# If we got here, it's the UI set—launch browser + listener: # If we got here, it's the UI set—launch browser + listener:
# ——— UI fallback starts here ——— # ——— UI fallback starts here ———
Write-LogHybrid "Launching UI" Info Startup Write-LogHybrid "Launching UI" Info Startup
#region Handler Stubs #region Handler Stubs
function Respond-Text { function Respond-Text {
param($Context, $Text) param($Context, $Text)
$bytes = [Text.Encoding]::UTF8.GetBytes($Text) $bytes = [Text.Encoding]::UTF8.GetBytes($Text)
$Context.Response.ContentType = 'text/plain' $Context.Response.ContentType = 'text/plain'
$Context.Response.ContentLength64 = $bytes.Length $Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes,0,$bytes.Length) $Context.Response.OutputStream.Write($bytes,0,$bytes.Length)
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
function Respond-HTML { function Respond-HTML {
[CmdletBinding()] [CmdletBinding()]
param( param(
[Parameter(Mandatory = $true)][object] $Context, [Parameter(Mandatory = $true)][object] $Context,
@@ -422,10 +437,10 @@ function Respond-HTML {
$Context.Response.ContentLength64 = $bytes.Length $Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
# new helper to return JSON # new helper to return JSON
function Respond-JSON { function Respond-JSON {
param($Context, $Object) param($Context, $Object)
$json = $Object | ConvertTo-Json -Depth 5 $json = $Object | ConvertTo-Json -Depth 5
$bytes = [Text.Encoding]::UTF8.GetBytes($json) $bytes = [Text.Encoding]::UTF8.GetBytes($json)
@@ -433,11 +448,11 @@ function Respond-JSON {
$Context.Response.ContentLength64 = $bytes.Length $Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes,0,$bytes.Length) $Context.Response.OutputStream.Write($bytes,0,$bytes.Length)
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
#region Install-DattoRMM-Helper #region Install-DattoRMM-Helper
function Install-DattoRMM-Helper { function Install-DattoRMM-Helper {
param ( param (
[string]$ApiUrl, [string]$ApiUrl,
[string]$ApiKey, [string]$ApiKey,
@@ -487,12 +502,12 @@ function Install-DattoRMM-Helper {
return return
} }
} }
} }
#endregion #endregion
#region SVS Module #region SVS Module
function Install-SVSMSP { function Install-SVSMSP {
param ( param (
[switch] $Cleanup, [switch] $Cleanup,
[switch] $InstallToolkit, [switch] $InstallToolkit,
@@ -528,14 +543,14 @@ function Install-SVSMSP {
} }
# default if no switch passed: # default if no switch passed:
Perform-ToolkitInstallation Perform-ToolkitInstallation
} }
#endregion #endregion
# POST /getpw → read JSON body, call helper, return JSON # POST /getpw → read JSON body, call helper, return JSON
function Handle-FetchSites { function Handle-FetchSites {
param($Context) param($Context)
# 1) Read incoming JSON (using block auto-disposes the reader) # 1) Read incoming JSON (using block auto-disposes the reader)
@@ -558,7 +573,7 @@ function Handle-FetchSites {
# 2) Fetch your Datto API creds from the webhook # 2) Fetch your Datto API creds from the webhook
Write-LogHybrid "Calling webhook for Datto credentials…" "Info" "FetchSites" Write-LogHybrid "Calling webhook for Datto credentials…" "Info" "FetchSites"
try { try {
$creds = Get-DattoApiCredentials -Password $pw $creds = Get-DattoApiCredentials -Password $pw
if (-not $creds) { if (-not $creds) {
Write-LogHybrid "Webhook returned no credentials" Error FetchSites Write-LogHybrid "Webhook returned no credentials" Error FetchSites
@@ -572,11 +587,11 @@ try {
$Global:ApiSecretKey = $creds.ApiSecretKey $Global:ApiSecretKey = $creds.ApiSecretKey
Write-LogHybrid "Fetched and stored API credentials." Success FetchSites Write-LogHybrid "Fetched and stored API credentials." Success FetchSites
} catch { } catch {
Write-LogHybrid "Credential-fetch error: $($_.Exception.Message)" Error FetchSites -LogToEvent Write-LogHybrid "Credential-fetch error: $($_.Exception.Message)" Error FetchSites -LogToEvent
returnRespondEmpty $Context 500 returnRespondEmpty $Context 500
return return
} }
# 3) Exchange for a bearer token # 3) Exchange for a bearer token
@@ -624,12 +639,12 @@ try {
$Context.Response.ContentLength64 = $bytes.Length $Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
# Helper function to consistently return an empty JSON array # Helper function to consistently return an empty JSON array
function returnRespondEmpty { function returnRespondEmpty {
param( param(
[Parameter(Mandatory)][object]$Context, [Parameter(Mandatory)][object]$Context,
[Parameter(Mandatory)][ValidateRange(100,599)][int]$StatusCode = 500 [Parameter(Mandatory)][ValidateRange(100,599)][int]$StatusCode = 500
@@ -645,12 +660,12 @@ function returnRespondEmpty {
# Write and close # Write and close
$Context.Response.OutputStream.Write($empty, 0, $empty.Length) $Context.Response.OutputStream.Write($empty, 0, $empty.Length)
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
# On-boarding handlers # On-boarding handlers
function Handle-SetSVSPowerPlan { function Handle-SetSVSPowerPlan {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -659,9 +674,9 @@ function Handle-SetSVSPowerPlan {
# 2) log & write back a simple text response # 2) log & write back a simple text response
Write-LogHybrid "PowerPlan set" "Success" "OnBoard" Write-LogHybrid "PowerPlan set" "Success" "OnBoard"
Respond-Text $Context "PowerPlan applied" Respond-Text $Context "PowerPlan applied"
} }
function Handle-InstallSVSMSP { function Handle-InstallSVSMSP {
param($Context) param($Context)
Write-LogHybrid "HTTP trigger: Handle-InstallSVSMSP" "Info" "OnBoard" Write-LogHybrid "HTTP trigger: Handle-InstallSVSMSP" "Info" "OnBoard"
try { try {
@@ -671,9 +686,9 @@ function Handle-InstallSVSMSP {
Write-LogHybrid "Error in Install-SVSMSP: $_" "Error" "OnBoard" Write-LogHybrid "Error in Install-SVSMSP: $_" "Error" "OnBoard"
Respond-Text $Context "ERROR: $_" Respond-Text $Context "ERROR: $_"
} }
} }
function Handle-InstallCyberQP { function Handle-InstallCyberQP {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -682,9 +697,9 @@ function Handle-InstallCyberQP {
# 2) log & write back a simple text response # 2) log & write back a simple text response
Write-LogHybrid "CyberQP installed" "Success" "OnBoard" Write-LogHybrid "CyberQP installed" "Success" "OnBoard"
Respond-Text $Context "CyberQP installed" Respond-Text $Context "CyberQP installed"
} }
function Handle-InstallThreatLocker { function Handle-InstallThreatLocker {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -693,9 +708,9 @@ function Handle-InstallThreatLocker {
# 2) log & write back a simple text response # 2) log & write back a simple text response
Write-LogHybrid "ThreatLocker installed" "Success" "OnBoard" Write-LogHybrid "ThreatLocker installed" "Success" "OnBoard"
Respond-Text $Context "ThreatLocker installed" Respond-Text $Context "ThreatLocker installed"
} }
function Handle-InstallRocketCyber { function Handle-InstallRocketCyber {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -704,9 +719,9 @@ function Handle-InstallRocketCyber {
# 2) log & write back a simple text response # 2) log & write back a simple text response
Write-LogHybrid "RocketCyber installed" "Success" "OnBoard" Write-LogHybrid "RocketCyber installed" "Success" "OnBoard"
Respond-Text $Context "RocketCyber installed" Respond-Text $Context "RocketCyber installed"
} }
function Handle-InstallSVSHelpDesk { function Handle-InstallSVSHelpDesk {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -715,9 +730,9 @@ function Handle-InstallSVSHelpDesk {
# 2) log & write back a simple text response # 2) log & write back a simple text response
Write-LogHybrid "SVS HelpDesk installed" "Success" "OnBoard" Write-LogHybrid "SVS HelpDesk installed" "Success" "OnBoard"
Respond-Text $Context "SVS HelpDesk installed" Respond-Text $Context "SVS HelpDesk installed"
} }
function Handle-InstallDattoRMM { function Handle-InstallDattoRMM {
param($Context) param($Context)
$req = $Context.Request $req = $Context.Request
$resp = $Context.Response $resp = $Context.Response
@@ -761,11 +776,11 @@ function Handle-InstallDattoRMM {
$resp.ContentLength64 = $b.Length $resp.ContentLength64 = $b.Length
$resp.OutputStream.Write($b,0,$b.Length) $resp.OutputStream.Write($b,0,$b.Length)
$resp.OutputStream.Close() $resp.OutputStream.Close()
} }
# Off-boarding handlers # Off-boarding handlers
function Handle-UninstallCyberQP { function Handle-UninstallCyberQP {
param($Context) param($Context)
# 1) call into your module # 1) call into your module
@@ -773,33 +788,33 @@ function Handle-UninstallCyberQP {
Write-LogHybrid "CyberQP uninstalled" "Success" "OffBoard" Write-LogHybrid "CyberQP uninstalled" "Success" "OffBoard"
Respond-Text $Context "CyberQP uninstalled" Respond-Text $Context "CyberQP uninstalled"
} }
function Cleanup-SVSMSP { function Cleanup-SVSMSP {
param($Context) param($Context)
Write-LogHybrid "SVSMSP cleaned up" "Success" "OffBoard" Write-LogHybrid "SVSMSP cleaned up" "Success" "OffBoard"
Respond-Text $Context "SVSMSP cleaned up" Respond-Text $Context "SVSMSP cleaned up"
} }
# Tweaks handler # Tweaks handler
function Disable-Animations { function Disable-Animations {
param($Context) param($Context)
Write-LogHybrid "Animations disabled" "Success" "Tweaks" Write-LogHybrid "Animations disabled" "Success" "Tweaks"
Respond-Text $Context "Animations disabled" Respond-Text $Context "Animations disabled"
} }
# SVSApps handler # SVSApps handler
function Install-WingetLastPass { function Install-WingetLastPass {
param($Context) param($Context)
Write-LogHybrid "Winget LastPass installed" "Success" "SVSApps" Write-LogHybrid "Winget LastPass installed" "Success" "SVSApps"
Respond-Text $Context "Winget LastPass installed" Respond-Text $Context "Winget LastPass installed"
} }
#endregion #endregion
#region UI Generation #region UI Generation
function Build-Checkboxes { function Build-Checkboxes {
param($Page, $Column) param($Page, $Column)
( (
@@ -826,37 +841,37 @@ function Build-Checkboxes {
) -join "`n" ) -join "`n"
$html += @" $html += @"
<div id='${taskId}OptionsContainer' style='display:none; margin-top:4px;'> <div id='${taskId}OptionsContainer' style='display:none; margin-top:4px;'>
$subHtml $subHtml
</div> </div>
"@ "@
} }
$html $html
} }
) -join "`n" ) -join "`n"
} }
### Get SVSMSP module version to display in the UI ### Get SVSMSP module version to display in the UI
function Get-ModuleVersionHtml { function Get-ModuleVersionHtml {
$mod = Get-Module -ListAvailable -Name SVSMSP | Sort-Object Version -Descending | Select-Object -First 1 $mod = Get-Module -ListAvailable -Name SVSMSP | Sort-Object Version -Descending | Select-Object -First 1
if ($mod) { if ($mod) {
return "<div style='color:#bbb; font-size:0.9em; margin-top:1em;'>Module Version: $($mod.Version)</div>" return "<div style='color:#bbb; font-size:0.9em; margin-top:1em;'>Module Version: $($mod.Version)</div>"
} }
return "<div style='color:#f66;'>SVSMSP_Module not found</div>" return "<div style='color:#f66;'>SVSMSP_Module not found</div>"
} }
function Get-UIHtml { function Get-UIHtml {
param([string]$Page = 'onboard') param([string]$Page = 'onboard')
# #
# 1) Inline your full original CSS here # 1) Inline your full original CSS here
# #
$style = @' $style = @'
<style> <style>
:root { :root {
/* Cool Palette */ /* Cool Palette */
--background-color: rgba(18, 18, 18, 1); --background-color: rgba(18, 18, 18, 1);
@@ -1011,8 +1026,8 @@ $style = @'
.container { flex-direction:column; } .container { flex-direction:column; }
.sidebar { width:100%; } .sidebar { width:100%; }
} }
</style> </style>
'@ '@
$script = @' $script = @'
<script> <script>
@@ -1267,22 +1282,22 @@ $style = @'
</script> </script>
'@ '@
# #
# 3) The HTML skeleton with placeholders # 3) The HTML skeleton with placeholders
# #
$htmlTemplate = @" $htmlTemplate = @"
<!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>Script Monkey</title> <title>Script Monkey</title>
<link rel="icon" href="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_Favicon.ico"> <link rel="icon" href="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_Favicon.ico">
$style $style
</head> </head>
<body> <body>
<div class="logo-container"> <div class="logo-container">
<div class="logo-left"> <div class="logo-left">
<img src="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_logo.svg" alt="SVS Logo"> <img src="https://git.svstools.com/syelle/Logo/raw/branch/main/SVS_logo.svg" alt="SVS Logo">
@@ -1330,32 +1345,32 @@ $htmlTemplate = @"
</div> </div>
</div> </div>
<div id="dattoRmmContainer" style="display:none; margin-bottom:1em;"> <div id="dattoRmmContainer" style="display:none; margin-bottom:1em;">
<label for="dattoDropdown">Select a Datto RMM site:</label> <label for="dattoDropdown">Select a Datto RMM site:</label>
<select id="dattoDropdown" style="width:100%;"> <select id="dattoDropdown" style="width:100%;">
<option disabled selected>Fetching sites...</option> <option disabled selected>Fetching sites...</option>
</select> </select>
</div> </div>
<div id="offboardTab" class="tab-content"> <div id="offboardTab" class="tab-content">
<h2>Off-Boarding</h2> <h2>Off-Boarding</h2>
<div class="columns-container"> <div class="columns-container">
{{offboardCheckboxes}} {{offboardCheckboxes}}
</div> </div>
</div> </div>
<div id="tweaksTab" class="tab-content"> <div id="tweaksTab" class="tab-content">
<h2>Tweaks</h2> <h2>Tweaks</h2>
<div class="columns-container"> <div class="columns-container">
{{tweaksCheckboxes}} {{tweaksCheckboxes}}
</div> </div>
</div> </div>
<div id="SVSAppsTab" class="tab-content"> <div id="SVSAppsTab" class="tab-content">
<h2>SVS APPs</h2> <h2>SVS APPs</h2>
<div class="columns-container"> <div class="columns-container">
{{appsCheckboxes}} {{appsCheckboxes}}
</div> </div>
</div> </div>
@@ -1367,10 +1382,10 @@ $htmlTemplate = @"
<button class="exit-button" onclick="endSession()">Exit</button> <button class="exit-button" onclick="endSession()">Exit</button>
<button class="run-button" onclick="triggerInstall()">Run Selected</button> <button class="run-button" onclick="triggerInstall()">Run Selected</button>
</div> </div>
</body> </body>
</html> </html>
"@ "@
# #
# 4) Build the checkbox HTML and tasks JS from $Global:Tasks # 4) Build the checkbox HTML and tasks JS from $Global:Tasks
@@ -1408,26 +1423,26 @@ $htmlTemplate = @"
return $html return $html
} }
#endregion #endregion
#region HTTP Listener & Routing #region HTTP Listener & Routing
# Handle shutdown command # Handle shutdown command
if ($path -eq 'quit') { if ($path -eq 'quit') {
Write-LogHybrid "Shutdown requested" "Info" "Server" Write-LogHybrid "Shutdown requested" "Info" "Server"
Respond-Text $Context "Server shutting down." Respond-Text $Context "Server shutting down."
# This will break out of the while loop in Start-Server # This will break out of the while loop in Start-Server
$Global:Listener.Stop() $Global:Listener.Stop()
return return
} }
# Sends the HTML for a given page or invokes a task handler # Sends the HTML for a given page or invokes a task handler
function Dispatch-Request { function Dispatch-Request {
param($Context) param($Context)
# figure out the path # figure out the path
@@ -1466,11 +1481,11 @@ function Dispatch-Request {
# ---- 404 ---- # ---- 404 ----
$Context.Response.StatusCode = 404 $Context.Response.StatusCode = 404
Respond-Text $Context '404 - Not Found' Respond-Text $Context '404 - Not Found'
} }
# Starts the HTTP listener loop # Starts the HTTP listener loop
function Start-Server { function Start-Server {
# make it accessible to Dispatch-Request # make it accessible to Dispatch-Request
$Global:Listener = [System.Net.HttpListener]::new() $Global:Listener = [System.Net.HttpListener]::new()
$Global:Listener.Prefixes.Add("http://localhost:$Port/") $Global:Listener.Prefixes.Add("http://localhost:$Port/")
@@ -1491,16 +1506,16 @@ function Start-Server {
$Global:Listener.Close() $Global:Listener.Close()
Write-LogHybrid "Listener closed." "Info" "Server" Write-LogHybrid "Listener closed." "Info" "Server"
} }
} }
#endregion #endregion
#region ScriptMonkey run silently Entrypoint #region ScriptMonkey run silently Entrypoint
# ──────────────────────────────────────────────────────────────────────── #
# 3) MAIN LOGIC (Toolkit vs DattoFetch vs DattoInstall vs UI) # 3) MAIN LOGIC (Toolkit vs DattoFetch vs DattoInstall vs UI)
# ──────────────────────────────────────────────────────────────────────── #
switch ($PSCmdlet.ParameterSetName) { switch ($PSCmdlet.ParameterSetName) {
'Toolkit' { 'Toolkit' {
@@ -1561,6 +1576,8 @@ function Start-Server {
} }
#endregion ScriptMonkey run silently Entrypoint #endregion ScriptMonkey run silently Entrypoint
Invoke-ScriptMonkey @PSBoundParameters
} # < end of Invoke-ScriptMonkey
Invoke-ScriptMonkey @PSBoundParameters