From 6ab52510915ec9731be076141ca89f7f8f77b178 Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Sat, 1 Feb 2025 22:14:17 -0500 Subject: [PATCH] Update TGBeta.ps1 --- TGBeta.ps1 | 2126 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 1249 insertions(+), 877 deletions(-) diff --git a/TGBeta.ps1 b/TGBeta.ps1 index cc14961..98a3b1e 100644 --- a/TGBeta.ps1 +++ b/TGBeta.ps1 @@ -1,30 +1,46 @@ ### 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. -### - All client-side JavaScript is wrapped in a DOMContentLoaded event listener to ensure proper initialization. +### 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 +### add the .net silent install tweaks to toolkit +### for the reg tweak need to do/undo function maybe it should have it own check box list +### added offboard check boxes for dattormm, dattodeb, rocketcyber, cyberQP, SVSHelpdesk and Splashtop +### need to fix path in the uninstall-DattoEDR - +####### ❌ [Error] [GeneralTask] Uninstallation command 'C:\Program Files\Infocyte\Agent\agent.exe' not found. (Event ID: 3000) - bad path + # --------------------------------------------------------------------------- -# 1) CREATE A GLOBAL LOG CACHE +# 1) CREATE A GLOBAL LOG CACHE (NEW) # --------------------------------------------------------------------------- +# - Global log cache stores logs for session-wide accessibility. +# - Logs are stored in a [System.Collections.ArrayList] for easy JSON conversion. +# - Ensure log cache integrity during session restarts. if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) { $Global:LogCache = New-Object System.Collections.ArrayList } #region Write-LogHelper +# --------------------------------------------------------------------------- +# 2) DEFINE THE Write-LogHelper FUNCTION +# --------------------------------------------------------------------------- +# - Write-LogHelper manages logging with customizable levels, task categories, and optional event logging. +# - Supported log levels: Info, Warning, Error, Success, General. +# - Task categories should match high-level operations (e.g., "On-boarding", "Off-boarding"). if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction SilentlyContinue)) { + # If the Write-Log function doesn't exist, create the Write-LogHelper function 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 + [string]$TaskCategory = "GeneralTask", # Task Category for the log entry + [switch]$LogToEvent = $false, # Log to Windows Event Log + [string]$EventSource = "SVSMSP_Module", # Event Source + [string]$EventLog = "Application", # Event Log (default: Application) + [int]$CustomEventID # Optional custom Event ID ) + + # Simplified Event ID mapping for consistent logging $EventID = switch ($Level) { "Info" { 1000 } "Warning" { 2000 } @@ -32,13 +48,17 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl "Success" { 4000 } "General" { 1000 } } + + # Icons for each level $Icon = switch ($Level) { - "Info" { [System.Char]::ConvertFromUtf32(0x1F4CB) } - "Warning" { ([char]0x26A0) } - "Error" { ([char]0x274C) } - "Success" { ([char]0x2705) } - "General" { ([char]0x1F4E6) } + "Info" { [System.Char]::ConvertFromUtf32(0x1F4CB) } # Information icon + "Warning" { ([char]0x26A0) } # Warning icon + "Error" { ([char]0x274C) } # Error icon + "Success" { ([char]0x2705) } # Success icon + "General" { ([char]0x1F4E6) } # Package icon } + + # Map levels to colors for console output $Color = switch ($Level) { "Info" { "Cyan" } "Warning" { "Yellow" } @@ -46,12 +66,26 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl "Success" { "Green" } "General" { "White" } } + + # Write to the PowerShell console + # Write-Host "$Icon [$Level] [$TaskCategory] $Message (Event ID: $EventID)" -ForegroundColor $Color + + # ------------------------------------------------------------------- + # 3) STORE LOGS IN GLOBAL CACHE + # ------------------------------------------------------------------- + # - Cache format: Timestamp, Level, and Message for each log entry. $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) + # ------------------------------------------------------------------- + ### TODO: Add support for exporting logs to a persistent file. + # Consider implementing a periodic export mechanism to save logs to a file. + # Example: Export-LogCacheToFile -Path "C:\Logs\TaskLogs.json" + + # Optional: Log to Windows Event Log for system-wide visibility. if ($LogToEvent) { $EntryType = switch ($Level) { "Info" { "Information" } @@ -59,6 +93,7 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl "Error" { "Error" } default { "Information" } } + try { if (-not (Get-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue)) { New-EventLog -LogName $EventLog -Source $EventSource -ErrorAction SilentlyContinue @@ -71,6 +106,9 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl } } } + + ### Hybrid Function: + # Wrapper for Write-LogHelper to simplify usage across modules. function Write-LogHybrid { param ( [string]$Message, @@ -88,6 +126,7 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl } } else { + # If Write-Log exists, define Write-LogHybrid to use Write-Log function Write-LogHybrid { param ( [string]$Message, @@ -104,24 +143,34 @@ else { -CustomEventID $CustomEventID } } + +# Example usage of Write-LogHybrid 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 + [switch]$FetchSitesOnly, # Fetch client sites without performing installation + [string]$SiteName, # For actual installation, pass the selected site Name + [string]$SiteUID # For actual installation, pass the selected site UID ) + + + # Ensure mandatory parameters are provided 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 } + + # Enable secure protocols [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + # Step 1: Fetch OAuth token Write-Log -Message "Fetching OAuth token..." -Level "Info" try { $securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force @@ -137,10 +186,15 @@ function Install-DattoRMM-Helper { Write-Log -Message "Failed to fetch OAuth token. Details: $($_.Exception.Message)" -Level "Error" -LogToEvent return } - $getHeaders = @{ "Authorization" = "Bearer $requestToken" } + + # Set headers for the API request + $getHeaders = @{"Authorization" = "Bearer $requestToken"} + + # Step 2: Fetch list of sites if ($FetchSitesOnly) { Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan try { + $getHeaders = @{"Authorization" = "Bearer $requestToken" } $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 { @@ -160,27 +214,52 @@ function Install-DattoRMM-Helper { } #endregion + + #region SVS Module + +### SVS Module Overview: +# - This section includes the Install-SVSMSP function, which handles: +# 1. Cleanup of old modules and repositories. +# 2. Installation of new modules and repositories. +# 3. Setting execution policies and prerequisites. +# - TODO: +# 1. Validate all parameters for completeness and add error messages for missing inputs. +# 2. Refactor cleanup and installation steps for modularity and reusability. + + function Install-SVSMSP { param ( + # Cleanup flag: Removes old modules and repositories if enabled. [switch]$Cleanup, + + # Toolkit installation flag: Installs required modules and repositories. [switch]$InstallToolkit, + + # Module settings [Parameter(Mandatory = $false)] [array]$AllModules = @( @{ ModuleName = "SVS_Toolkit" }, @{ ModuleName = "SVSMSP" } ), + [Parameter(Mandatory = $false)] [string]$NewModuleName = "SVSMSP", + + # Repository settings [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/", + + # Commands to check [Parameter(Mandatory = $false)] [array]$CommandsToCheck = @( "Install-DattoRMM", @@ -189,12 +268,22 @@ function Install-SVSMSP { "Install-Splashtop", "Install-ThreatLocker", "Install-SVSHelpdesk" + ), + + # Log file path for tracking installation steps [Parameter(Mandatory = $false)] [string]$LogFilePath = "$env:SVSMSP\svstoolkit.log" + ) + + ### Function: Perform-Cleanup + # - Removes all old modules and repositories. + # - Logs each step for debugging purposes. function Perform-Cleanup { - Write-LogHybrid -Message "Cleanup mode enabled. Starting cleanup process..." -Level "Info" -LogToEvent + Write-LogHybrid -Message "Cleanup mode enabled. Starting cleanup process..." -Level "Info" -LogToEvent + + # Step 1: Remove all old modules Write-LogHybrid -Message "Starting cleanup of old modules..." -Level "Info" -LogToEvent foreach ($module in $AllModules) { $ModuleName = $module.ModuleName @@ -214,6 +303,8 @@ function Install-SVSMSP { Write-LogHybrid -Message "Module '$ModuleName' not found. Skipping..." -Level "Info" -LogToEvent } } + + # Step 2: Remove all old repositories Write-LogHybrid -Message "Starting cleanup of old repositories..." -Level "Info" -LogToEvent foreach ($repo in $AllRepositories) { $RepoName = $repo.RepoName @@ -231,23 +322,36 @@ function Install-SVSMSP { Write-LogHybrid -Message "Repository '$RepoName' does not exist. Skipping removal." -Level "Info" -LogToEvent } } - Write-LogHybrid -Message "Cleanup process completed successfully." -Level "Success" -LogToEvent + + Write-LogHybrid -Message "Cleanup process completed successfully." -Level "Success" -LogToEvent } + + ### Function: Perform-ToolkitInstallation + # - Handles the installation of new repositories and modules. + # - Ensures execution policies are correctly set. function Perform-ToolkitInstallation { + + # Step 1: Cleanup old modules and repositories Perform-Cleanup + + # Step 2: Set Execution Policy $localMachineExecutionPolicy = Get-ExecutionPolicy -Scope LocalMachine 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 -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force - Write-LogHybrid -Message "Execution policy set to RemoteSigned successfully." -Level "Success" -LogToEvent + 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 + Write-LogHybrid -Message "Failed to set execution policy. Error: $_" -Level "Error" -LogToEvent return } } + + # Step 3: Ensure NuGet is Installed Install-PackageProvider -Name "NuGet" -Force -Scope AllUsers -Confirm:$false + + # Step 4: Register the new repository Write-LogHybrid -Message "Registering the new repository '$NewRepositoryName'..." -Level "Info" -LogToEvent try { if (!(Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) { @@ -258,6 +362,8 @@ function Install-SVSMSP { catch { Write-LogHybrid -Message "Failed to register new repository '$NewRepositoryName'. Error: $($_.Exception.Message)" -Level "Error" -LogToEvent } + + # Step 5: Install the new module Write-LogHybrid -Message "Installing the new module '$NewModuleName'..." -Level "Info" -LogToEvent try { Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force @@ -266,70 +372,82 @@ function Install-SVSMSP { 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 "Toolkit installation process completed successfully." -Level "Success" -LogToEvent } - Write-LogHybrid -Message "Install-SVSMSP function started." -Level "Info" -LogToEvent + + ### Function Execution Logic + # - Determines whether to run cleanup, toolkit installation, or default to toolkit installation mode. + 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 +#endregion SVS Module # ---------------------------------------------------------------------------------- # START THE HTTP LISTENER # ---------------------------------------------------------------------------------- +# This listener serves as the backend for handling requests from the GUI. +# It supports multiple routes, such as: +# - "/" (Root): Serves the HTML GUI. +# - "/getn8npw": Fetches n8n password and site information. +# - "/installSVSMSPModule": Triggers the installation of SVSMSP modules. +# - "/installrmm": Handles RMM installation with dynamic parameters. +# - Additional routes for tweaks and other tasks. + +### Listener Initialization with Error Handling try { + # Create a new HttpListener object $listener = New-Object System.Net.HttpListener + + # Check if the object was successfully created if (-not $listener) { throw "Failed to initialize HttpListener." } + + # Add prefix for the listener $listener.Prefixes.Add("http://localhost:8081/") Write-LogHybrid -Message "Listener initialized with prefix http://localhost:8081/" -Level "Info" + + # Start the listener $listener.Start() Write-LogHybrid -Message "Listener started successfully." -Level "Info" } catch { + # Log the error and rethrow it for visibility 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 } + $headers = @{ + "SVSMSPKit" = $AuthHeaderValue + } try { $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get Write-Host "Response received successfully:" -ForegroundColor Green + $data = $response + + # Map fields $global:Comment_SVSmodule = $data._Comment_SVSmodule $global:ModuleName = $data.ModuleName $global:RepositoryURL = $data.RepositoryURL @@ -341,6 +459,10 @@ function Get-N8nWebhookData { $global:ApiUrl = $data.ApiUrl $global:ApiKey = $data.ApiKey $global:ApiSecretKey = $data.ApiSecretKey + + + + # return $data } catch { Write-Host "Error making the GET request:" -ForegroundColor Red @@ -349,792 +471,984 @@ function Get-N8nWebhookData { } } + +# Define the HTML Content with an Off-Boarding Tab function GetHtmlContent { -@" + @" - - - SVS TaskGate - - + + -
- SVS Logo -
-
-