diff --git a/TGBeta.ps1 b/TGBeta.ps1 index 5357c7f..d441ee2 100644 --- a/TGBeta.ps1 +++ b/TGBeta.ps1 @@ -1,2 +1,1102 @@ -## need to take a copy of TaskGate -write-host "copy the TaskGate App" \ No newline at end of file +### Known issues as of January 5 2025 + +### Install-DattoRMM version 25.1.4 is missing functions you'll need version 25.1.5 + +### Missing Function in module, are added in 25.1.5 +### Install-SVSHelpDesk +### Install SVSWatchtower + +### add tweek to set default provider, add to toolkit? +### need to see if there's anything else we could take from Theo script? +### make sure that when using select all option +### Module install first +### Rmm Second + +# --------------------------------------------------------------------------- +# 1) CREATE A GLOBAL LOG CACHE (NEW) +# --------------------------------------------------------------------------- +if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) { + $Global:LogCache = New-Object System.Collections.ArrayList +} + + +# Check if the Write-Log function exists +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", # 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 + $EventID = switch ($Level) { + "Info" { 1000 } + "Warning" { 2000 } + "Error" { 3000 } + "Success" { 4000 } + "General" { 1000 } + } + + # Icons for each level + $Icon = switch ($Level) { + "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 + $Color = switch ($Level) { + "Info" { "Cyan" } + "Warning" { "Yellow" } + "Error" { "Red" } + "Success" { "Green" } + "General" { "White" } + } + + # Write to the PowerShell console + Write-Host "$Icon [$Level] [$TaskCategory] $Message (Event ID: $EventID)" -ForegroundColor $Color + + # ------------------------------------------------------------------- + # 2) ALSO STORE THE LOG IN OUR GLOBAL LOG CACHE (NEW) + # ------------------------------------------------------------------- + $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) + # ------------------------------------------------------------------- + + # Optionally log to the Windows Event Log + 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 { + # If Write-Log exists, define Write-LogHybrid to use Write-Log + 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 + } +} + +# Example usage of Write-LogHybrid +Write-LogHybrid -Message "This is a test log message. Write-logHybrid" -Level "Info" -TaskCategory "TestCategory" -LogToEvent:$true +Write-Log -Message "This is a test log message. Write-log" -Level "Info" -TaskCategory "TestCategory" -LogToEvent:$true + + +function Install-SVSMSP { + param ( + # Cleanup flag + [switch]$Cleanup, + + # Toolkit installation flag + [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", + "Install-CyberQP", + "Install-RocketCyber", + "Install-Splashtop", + "Install-ThreatLocker" + ), + + # Log file path + [Parameter(Mandatory = $false)] + [string]$LogFilePath = "$env:temp\svstoolkit.log", + + # DRMM API Settings + [Parameter(Mandatory = $false)] + [string]$ApiUrl = "https://example-api-url.com", + + [Parameter(Mandatory = $false)] + [string]$ApiKey = "YOUR_API_KEY_HERE", + + [Parameter(Mandatory = $false)] + [string]$ApiSecretKey = "YOUR_API_SECRET_HERE" + ) + + function Perform-Cleanup { + Write-LogHybrid -Message "Cleanup mode enabled. Starting cleanup process..." -Level "Info" -LogToEvent -EventID 1502 + + # Step 1: Remove all old modules + 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 + } + } + + # Step 2: Remove all old repositories + 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 -EventID 1510 + } + + function Perform-ToolkitInstallation { + # Perform cleanup + Perform-Cleanup + + # Step 1: Set Execution Policy + $localMachineExecutionPolicy = Get-ExecutionPolicy -Scope LocalMachine + if ($localMachineExecutionPolicy -ne "RemoteSigned") { + Write-LogHybrid -Message "Setting execution policy to RemoteSigned..." -Level "Warning" -LogToEvent -EventID 1522 + try { + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force + Write-LogHybrid -Message "Execution policy set to RemoteSigned successfully." -Level "Success" -LogToEvent -EventID 1513 + } + catch { + Write-LogHybrid -Message "Failed to set execution policy. Error: $_" -Level "Error" -LogToEvent -EventID 1534 + return + } + } + + # Step 2: Ensure NuGet is Installed + if (!(Get-PackageProvider -Name "NuGet" -ErrorAction SilentlyContinue)) { + Write-LogHybrid -Message "NuGet package provider not found. Installing..." -Level "Warning" -LogToEvent -EventID 1520 + try { + Install-PackageProvider -Name "NuGet" -Force -Scope AllUsers -Confirm:$false + Write-LogHybrid -Message "NuGet package provider installed successfully." -Level "Success" -LogToEvent -EventID 1514 + } + catch { + Write-LogHybrid -Message "Failed to install NuGet package provider. Error: $_" -Level "Error" -LogToEvent -EventID 1535 + return + } + } + + # Step 3: Register the new repository + 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 + } + + # Step 4: 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 + 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 -EventID 1510 + } + + Write-LogHybrid -Message "Install-SVSMSP function started." -Level "Info" -LogToEvent -EventID 1500 + + 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 -EventID 1504 + Perform-ToolkitInstallation +} + + # Install-SVSMSP -InstallToolkit + + +# ---------------------------------------------------------------------------------- +# START THE LISTENER +# ---------------------------------------------------------------------------------- +$listener = New-Object System.Net.HttpListener +$listener.Prefixes.Add("http://localhost:8081/") +$listener.Start() + + +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 + + # Map fields + $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 + + + + # return $data + } + catch { + Write-Host "Error making the GET request:" -ForegroundColor Red + Write-Host $_.Exception.Message + return $null + } +} + + +# Define the HTML Content with an Off-Boarding Tab +function GetHtmlContent { + @" + + + + + + SVS TaskGate + + + + +
+ SVS Logo +
+
+ +
+ +
+

On-Boarding

+
+ + + + + + + + + + + +
+ +
+ +
+ + + +
+
+

Logs will appear here...

+
+
+
+
+ + + + +"@ +} + + + +# Save and launch the 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") { + $bodyStream = New-Object IO.StreamReader $request.InputStream + $body = $bodyStream.ReadToEnd() + $data = ConvertFrom-Json $body + $password = $data.password + + Get-N8nWebhookData -AuthHeaderValue $password + $sites = Install-DattoRMM -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() + } + } + + "/installrmm" { + if ($request.HttpMethod -eq "POST") { + try { + # Step 1: Read the Request Body + $bodyStream = New-Object IO.StreamReader $request.InputStream + $body = $bodyStream.ReadToEnd() + $requestData = ConvertFrom-Json $body + + # Step 2: Extract Data from the Request + $checkedValues = $requestData.checkedValues + $UID = $requestData.UID + $Name = $requestData.Name + + # Step 3: Validate Input + 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 + } + + # Step 4: Build the PowerShell Command Dynamically + $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" + } + + + + # Step 5: Execute the Command + 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 { + # Log General Errors + $errorString = "An error occurred while processing the /installrmm request: $($_.Exception.Message)" + Write-LogHybrid -Message $errorString -Level "Error" + $response.StatusCode = 500 + $responseString = $errorString + } + + # Step 6: Return the Response + $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 { + # Handle Invalid HTTP Methods + $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") { + Set-SVSPowerPlan + } + $responseString = "Install SVS Powerplan triggered." + $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") { + Install-Splashtop + } + $responseString = "Install Splashtop triggered." + $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") { + Install-RocketCyber + } + $responseString = "Install RocketCyber triggered." + $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") { + Install-ThreatLocker + } + $responseString = "Install ThreatLocker triggered." + $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") { + Install-SVSHelpDesk + } + $responseString = "Install SVSHelpDesk triggered." + $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() + } + + "/installSVSWatchtower" { + if ($request.HttpMethod -eq "GET") { + Install-SVSWatchtower + } + $responseString = "Install SVSWatchtower triggered." + $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() + } + + # ---------------------------------------------------------------- + # 4) NEW ROUTE: /getLogs + # Returns $Global:LogCache as JSON for the polling function + # ---------------------------------------------------------------- + "/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 { + $listener.Stop() + $listener.Close() +}