#region Config & Task Definitions # Listening port for HTTP UI $Port = 8081 # Define every task once here: # Id → checkbox HTML `id` # Name → URL path (`/Name`) # Label → user-visible text # HandlerFn → the PowerShell function to invoke # Page → which tab/page it appears on $Global:Tasks = @( # On-Boarding @{ Id='setSVSPowerplan'; Name='setSVSPowerplan'; Label='Set SVS Powerplan'; HandlerFn='Set-SVSPowerPlan'; Page='onboard' }, @{ Id='installSVSMSPModule'; Name='installSVSMSPModule'; Label='Install SVSMSP Module'; HandlerFn='Install-SVSMSPModule'; Page='onboard' }, @{ Id='installCyberQP'; Name='installCyberQP'; Label='Install CyberQP'; HandlerFn='Install-CyberQP'; Page='onboard' }, # Off-Boarding @{ Id='uninstallCyberQP'; Name='uninstallCyberQP'; Label='Uninstall CyberQP'; HandlerFn='Uninstall-CyberQP'; Page='offboard' }, @{ Id='uninstallSVSMSPModule';Name='uninstallSVSMSPModule';Label='Uninstall SVSMSP Module'; HandlerFn='Cleanup-SVSMSP'; Page='offboard' }, # Tweaks @{ Id='disableAnimations'; Name='disableAnimations'; Label='Disable Animations'; HandlerFn='Disable-Animations'; Page='tweaks' }, # SVS Apps @{ Id='wingetLastpass'; Name='wingetLastpass'; Label='LastPass Desktop App'; HandlerFn='Install-WingetLastPass'; Page='SVSApps' } ) #endregion #region Logging Helpers # Initialize a global in-memory log cache if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) { $Global:LogCache = [System.Collections.ArrayList]::new() } # Core Write-Log function (advanced with event-log support) function Write-LogHelper { [CmdletBinding()] param( [Parameter(Mandatory)][string]$Message, [ValidateSet("Info","Warning","Error","Success","General")] [string]$Level = "Info", [string]$TaskCategory = "GeneralTask", [switch]$LogToEvent, [string]$EventSource = "SVSMSP_Module", [string]$EventLog = "Application", [int]$CustomEventID ) $EventID = @{ Info=1000; Warning=2000; Error=3000; Success=4000; General=1000 }[$Level] $Icon = @{ Info="📝"; Warning="⚠️"; Error="❌"; Success="✅"; General="📦" }[$Level] $logEntry = [PSCustomObject]@{ Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") Level = $Level Message = "$Icon [$Level] [$TaskCategory] $Message (EventID:$EventID)" } [void]$Global:LogCache.Add($logEntry) if ($LogToEvent) { try { if (-not (Get-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue)) { New-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue } Write-EventLog -LogName $EventLog -Source $EventSource ` -EntryType $Level -EventId $EventID ` -Message $Message } catch { Write-Host "⚠️ [EventLog] Failed to write: $($_.Exception.Message)" -ForegroundColor Yellow } } } # Hybrid wrapper: uses your module's Write-Log if available, else falls back if (Get-Command Write-Log -ErrorAction SilentlyContinue) { function Write-LogHybrid { param($Message,$Level,$TaskCategory,$LogToEvent) Write-Log @PSBoundParameters } } else { function Write-LogHybrid { param($Message,$Level,$TaskCategory,$LogToEvent) Write-LogHelper @PSBoundParameters } } #endregion #region Handler Stubs function Respond-Text { param($Context, $Text) $bytes = [Text.Encoding]::UTF8.GetBytes($Text) $Context.Response.ContentType = 'text/plain' $Context.Response.ContentLength64 = $bytes.Length $Context.Response.OutputStream.Write($bytes,0,$bytes.Length) $Context.Response.OutputStream.Close() } function Respond-HTML { [CmdletBinding()] param( [Parameter(Mandatory = $true)][object] $Context, [Parameter(Mandatory = $true)][string] $Html ) $bytes = [Text.Encoding]::UTF8.GetBytes($Html) $Context.Response.ContentType = 'text/html' $Context.Response.ContentLength64 = $bytes.Length $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) $Context.Response.OutputStream.Close() } # On-boarding handlers function Set-SVSPowerPlan { param($Context) Write-LogHybrid "PowerPlan set" "Success" "OnBoard" Respond-Text $Context "Powerplan applied" } function Install-SVSMSPModule { param($Context) Write-LogHybrid "SVSMSP Module installed" "Success" "OnBoard" Respond-Text $Context "SVSMSP Module installed" } function Install-CyberQP { param($Context) Write-LogHybrid "CyberQP installed" "Success" "OnBoard" Respond-Text $Context "CyberQP installed" } # Off-boarding handlers function Uninstall-CyberQP { param($Context) Write-LogHybrid "CyberQP uninstalled" "Success" "OffBoard" Respond-Text $Context "CyberQP uninstalled" } function Cleanup-SVSMSP { param($Context) Write-LogHybrid "SVSMSP cleaned up" "Success" "OffBoard" Respond-Text $Context "SVSMSP cleaned up" } # Tweaks handler function Disable-Animations { param($Context) Write-LogHybrid "Animations disabled" "Success" "Tweaks" Respond-Text $Context "Animations disabled" } # SVSApps handler function Install-WingetLastPass { param($Context) Write-LogHybrid "Winget LastPass installed" "Success" "SVSApps" Respond-Text $Context "Winget LastPass installed" } #endregion #region UI Generation function Get-UIHtml { param([string]$Page = 'onboard') # # 1) Inline your full original CSS here # $style = @' '@ $script = @' '@ # # 3) The HTML skeleton with placeholders # $htmlTemplate = @"