Update SVSTaskGate.ps1

This commit is contained in:
2025-01-28 00:42:33 -05:00
parent 5309202724
commit 3468cf0991

View File

@@ -5,22 +5,31 @@
### add the .net silent install tweaks to toolkit ### 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 ### 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 ### added offboard check boxes for dattormm, dattodeb, rocketcyber, cyberQP, SVSHelpdesk and Splashtop
### for the offboarding button, we need to fix the uninstall-svsmsp module
### need to fix path in the uninstall-DattoEDR - ### 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 ####### ❌ [Error] [GeneralTask] Uninstallation command 'C:\Program Files\Infocyte\Agent\agent.exe' not found. (Event ID: 3000) - bad path
### need to have the fetch button check if Install-DattoRMM function exist if not run the build in helpder function to fetch sites
### need to move the tweaks to the tweeks tab
#region Write-Log
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# 1) CREATE A GLOBAL LOG CACHE (NEW) # 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])) { if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) {
$Global:LogCache = New-Object System.Collections.ArrayList $Global:LogCache = New-Object System.Collections.ArrayList
} }
#region Write-LogHelper
# Check if the Write-Log function exists # ---------------------------------------------------------------------------
# 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 (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction SilentlyContinue)) {
# If the Write-Log function doesn't exist, create the Write-LogHelper function # If the Write-Log function doesn't exist, create the Write-LogHelper function
function Write-LogHelper { function Write-LogHelper {
@@ -35,7 +44,7 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
[int]$CustomEventID # Optional custom Event ID [int]$CustomEventID # Optional custom Event ID
) )
# Simplified Event ID mapping # Simplified Event ID mapping for consistent logging
$EventID = switch ($Level) { $EventID = switch ($Level) {
"Info" { 1000 } "Info" { 1000 }
"Warning" { 2000 } "Warning" { 2000 }
@@ -53,7 +62,7 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
"General" { ([char]0x1F4E6) } # Package icon "General" { ([char]0x1F4E6) } # Package icon
} }
# Map levels to colors # Map levels to colors for console output
$Color = switch ($Level) { $Color = switch ($Level) {
"Info" { "Cyan" } "Info" { "Cyan" }
"Warning" { "Yellow" } "Warning" { "Yellow" }
@@ -66,8 +75,9 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
# Write-Host "$Icon [$Level] [$TaskCategory] $Message (Event ID: $EventID)" -ForegroundColor $Color # Write-Host "$Icon [$Level] [$TaskCategory] $Message (Event ID: $EventID)" -ForegroundColor $Color
# ------------------------------------------------------------------- # -------------------------------------------------------------------
# 2) ALSO STORE THE LOG IN OUR GLOBAL LOG CACHE (NEW) # 3) STORE LOGS IN GLOBAL CACHE
# ------------------------------------------------------------------- # -------------------------------------------------------------------
# - Cache format: Timestamp, Level, and Message for each log entry.
$logEntry = [PSCustomObject]@{ $logEntry = [PSCustomObject]@{
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
Level = $Level Level = $Level
@@ -75,8 +85,11 @@ if (-not (Get-Command -Name Write-Log -CommandType Function -ErrorAction Silentl
} }
[void]$Global:LogCache.Add($logEntry) [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"
# Optionally log to the Windows Event Log # Optional: Log to Windows Event Log for system-wide visibility.
if ($LogToEvent) { if ($LogToEvent) {
$EntryType = switch ($Level) { $EntryType = switch ($Level) {
"Info" { "Information" } "Info" { "Information" }
@@ -98,6 +111,8 @@ 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 { function Write-LogHybrid {
param ( param (
[string]$Message, [string]$Message,
@@ -136,10 +151,77 @@ else {
# Example usage of Write-LogHybrid # Example usage of Write-LogHybrid
Write-LogHybrid -Message "Starting SVS TaskGate" -Level "Info" -TaskCategory "SVSTaskGate" -LogToEvent:$true Write-LogHybrid -Message "Starting SVS TaskGate" -Level "Info" -TaskCategory "SVSTaskGate" -LogToEvent:$true
#endregion #endregion
#region Install-DattoRMM-Helper
function Install-DattoRMM-Helper {
param (
[string]$ApiUrl,
[string]$ApiKey,
[string]$ApiSecretKey,
[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
$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
}
# 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 {
[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 #region SVS Module
function Install-SVSMSP { function Install-SVSMSP {
param ( param (
# Cleanup flag # Cleanup flag
@@ -197,10 +279,7 @@ function Install-SVSMSP {
[Parameter(Mandatory = $false)] [Parameter(Mandatory = $false)]
[string]$ApiSecretKey [string]$ApiSecretKey
) )
function Perform-Cleanup { 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
@@ -594,6 +673,7 @@ function GetHtmlContent {
<div class="columns-container"> <div class="columns-container">
<!-- Left column --> <!-- Left column -->
<div class="checkbox-group column" id="leftColumn"> <div class="checkbox-group column" id="leftColumn">
<h3 style="font-size: 1.5rem; font-weight: bold;">SVSMSP Stack</h3>
<label> <label>
<input type="checkbox" id="selectAllLeftCheckbox" onclick="toggleLeftColumnCheckboxes(this)"> <input type="checkbox" id="selectAllLeftCheckbox" onclick="toggleLeftColumnCheckboxes(this)">
Select All Select All
@@ -650,6 +730,7 @@ function GetHtmlContent {
<!-- Right column --> <!-- Right column -->
<div class="checkbox-group column" id="rightColumn" > <div class="checkbox-group column" id="rightColumn" >
<h3 style="font-size: 1.5rem; font-weight: bold;">Optional</h3>
<label> <label>
<input type="checkbox" class="right-checkbox" name="EnableBitLocker" id="EnableBitLockerCheckbox"> <input type="checkbox" class="right-checkbox" name="EnableBitLocker" id="EnableBitLockerCheckbox">
Enable Bitlocker Enable Bitlocker
@@ -735,35 +816,83 @@ function GetHtmlContent {
</div> </div>
</div> </div>
</div> </div>
<!-- tweaks Tab -->
<div id="tweaksTab" class="tab-content inactive"> <div id="tweaksTab" class="tab-content inactive">
<h2>Tweaks</h2> <h2>Tweaks</h2>
<div class="checkbox-group"> <div class="columns-container">
<label> <!-- Column 1 -->
<input type="checkbox" id="selectAllTweaksCheckbox" onclick="toggleTweaksCheckboxes(this)"> <div class="column" id="tweaksColumn1">
Select All <h3>System Optimizations</h3>
</label> <div class="checkbox-group">
<label> <label>
<input type="checkbox" name="setedgedefaultsearch" id="setedgedefaultsearchCheckbox"> <input type="checkbox" name="setedgedefaultsearch" id="setedgedefaultsearchCheckbox">
Set Edge Default Search Engine Set Edge Default Search Engine
</label> </label>
<label> <label>
<input type="checkbox" name="disableAnimations" id="disableAnimationsCheckbox"> <input type="checkbox" name="setWindowsPerformance" id="setWindowsPerformanceCheckbox" onclick="toggleRadioButtons(this)">
Disable Animations Optimize Windows Performance
</label> </label>
<label> <div class="radio-group" id="windowsPerformanceOptions" style="margin-left: 20px; display: none;">
<input type="checkbox" name="optimizePerformance" id="optimizePerformanceCheckbox"> <label>
Optimize Performance <input type="radio" name="optimizeWindowsPerformanceLevel" value="full">
</label> Full
<label> </label>
<input type="checkbox" name="increaseFontSize" id="increaseFontSizeCheckbox"> <label>
Increase Font Size <input type="radio" name="optimizeWindowsPerformanceLevel" value="partial">
</label> 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>
<!-- Column 2 -->
<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>
<!-- Column 3 -->
<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>
<div class="button-group"> <div class="button-group">
<button class="install-button" onclick="triggerTweaks()">Tweaks</button> <button class="install-button" onclick="triggerTweaks()">Apply Tweaks</button>
</div> </div>
</div> </div>
<!-- Shared Exit Button --> <!-- Shared Exit Button -->
<div class="button-group"> <div class="button-group">
<button class="exit-button" onclick="endSession()">Exit</button> <button class="exit-button" onclick="endSession()">Exit</button>
@@ -891,43 +1020,97 @@ function GetHtmlContent {
}); });
} }
function toggleRadioButtons(checkbox) {
function toggleTweaksCheckboxes(selectAllCheckbox) { const radioGroup = document.getElementById("windowsPerformanceOptions");
// Get all checkboxes inside the tweaksTab container if (checkbox.checked) {
const checkboxes = document radioGroup.style.display = "block";
.getElementById('tweaksTab') } else {
.querySelectorAll('input[type="checkbox"]:not(#selectAllTweaksCheckbox)'); radioGroup.style.display = "none";
// Optionally, reset the radio buttons to their default state
// Set the checked state of all checkboxes to match the "Select All" checkbox const radios = radioGroup.querySelectorAll('input[type="radio"]');
checkboxes.forEach(checkbox => { radios.forEach(radio => {
checkbox.checked = selectAllCheckbox.checked; radio.checked = false;
}); });
} radios[2].checked = true; // Reset to "None"
function updateSelectAllTweaks() {
const selectAllCheckbox = document.getElementById('selectAllTweaksCheckbox');
const checkboxes = document
.getElementById('tweaksTab')
.querySelectorAll('input[type="checkbox"]:not(#selectAllTweaksCheckbox)');
// If any checkbox is unchecked, uncheck "Select All"
selectAllCheckbox.checked = Array.from(checkboxes).every(checkbox => checkbox.checked);
}
// Attach the updateSelectAllTweaks function to all individual checkboxes
document.querySelectorAll('#tweaksTab input[type="checkbox"]:not(#selectAllTweaksCheckbox)').forEach(checkbox => {
checkbox.addEventListener('change', updateSelectAllTweaks);
});
function triggerTweaks() {
const setedgedefaultsearch = document.querySelector('input[name="setedgedefaultsearch"]');
if (setedgedefaultsearch.checked) {
fetch('/setedgedefaultsearch', { method: 'GET' })
} }
} }
function triggerTweaks() {
// Get the state of the checkboxes
const setEdgeDefaultSearch = document.getElementById('setedgedefaultsearchCheckbox').checked;
const optimizeWindowsPerformance = document.getElementById('setWindowsPerformanceCheckbox').checked;
const stopUnnecessaryServices = document.getElementById('stopUnnecessaryServicesCheckbox').checked;
const disableAnimations = document.getElementById('disableAnimationsCheckbox').checked;
const optimizePerformance = document.getElementById('optimizePerformanceCheckbox').checked;
const increaseFontSize = document.getElementById('increaseFontSizeCheckbox').checked;
const enableDarkMode = document.getElementById('enableDarkModeCheckbox').checked;
const clearTempFiles = document.getElementById('clearTempFilesCheckbox').checked;
// Get the selected radio button for Windows Performance Optimization
let optimizeWindowsPerformanceLevel = "none";
if (optimizeWindowsPerformance) {
const radios = document.querySelectorAll('input[name="optimizeWindowsPerformanceLevel"]');
radios.forEach(radio => {
if (radio.checked) {
optimizeWindowsPerformanceLevel = radio.value;
}
});
}
// Log or handle the tweaks (replace console.log with actual logic as needed)
console.log("Set Edge Default Search Engine:", setEdgeDefaultSearch);
console.log("Optimize Windows Performance:", optimizeWindowsPerformance);
console.log("Windows Performance Optimization Level:", optimizeWindowsPerformanceLevel);
console.log("Stop Unnecessary Services:", stopUnnecessaryServices);
console.log("Disable Animations:", disableAnimations);
console.log("Optimize Application Performance:", optimizePerformance);
console.log("Increase Font Size:", increaseFontSize);
console.log("Enable Dark Mode:", enableDarkMode);
console.log("Clear Temporary Files:", clearTempFiles);
// Example: Apply tweaks (replace these comments with actual implementations)
if (setEdgeDefaultSearch) {
// Call function or API to set Edge default search engine
}
if (optimizeWindowsPerformance) {
if (optimizeWindowsPerformanceLevel === "full") {
// Apply full optimization
} else if (optimizeWindowsPerformanceLevel === "partial") {
// Apply partial optimization
} else {
// No optimization
}
}
if (stopUnnecessaryServices) {
// Stop unnecessary services
}
if (disableAnimations) {
// Disable animations in the system
}
if (optimizePerformance) {
// Optimize application performance
}
if (increaseFontSize) {
// Increase font size
}
if (enableDarkMode) {
// Enable dark mode
}
if (clearTempFiles) {
// Clear temporary files
}
// Notify user tweaks are applied
alert("Tweaks applied successfully!");
}
function toggleDattoRMMOptions() { function toggleDattoRMMOptions() {
const checkbox = document.getElementById('installDattoRMMCheckbox'); const checkbox = document.getElementById('installDattoRMMCheckbox');
@@ -964,7 +1147,7 @@ function GetHtmlContent {
}); });
// Trigger fetchSites() on Enter key press // Trigger fetchSites() on Enter key press
n8nPasswordInput.addEventListener('keydown', (event) => { n8nPasswordInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && n8nPasswordInput.value.length >= 4) { if (event.key === 'Enter' && n8nPasswordInput.value.length >= 12) {
fetchSites(); // Call the fetchSites function fetchSites(); // Call the fetchSites function
} }
}); });
@@ -1239,7 +1422,7 @@ try {
$password = $data.password $password = $data.password
Get-N8nWebhookData -AuthHeaderValue $password Get-N8nWebhookData -AuthHeaderValue $password
$sites = Install-DattoRMM -ApiUrl $ApiUrl -ApiKey $ApiKey -ApiSecretKey $ApiSecretKey -FetchSitesOnly $sites = Install-DattoRMM-Helper -ApiUrl $ApiUrl -ApiKey $ApiKey -ApiSecretKey $ApiSecretKey -FetchSitesOnly
if (-not $sites) { if (-not $sites) {
Write-Host "No sites returned. Please check the API." -ForegroundColor Red Write-Host "No sites returned. Please check the API." -ForegroundColor Red
$response.StatusCode = 500 $response.StatusCode = 500
@@ -1580,7 +1763,7 @@ try {
# Process each selected task # Process each selected task
foreach ($task in $selectedTasks) { foreach ($task in $selectedTasks) {
switch ($task) { switch ($task) {
"uninstallSVSMSPModule" { Write-LogHybrid -Message "Uninstalling SVSMSP Module..." -Level "Info"; } #Uninstall-SVSMSP } "uninstallSVSMSPModule" { Write-LogHybrid -Message "Uninstalling SVSMSP Module..." -Level "Info"; Install-SVSMSP -cleanup }
"uninstallThreatLocker" { Write-LogHybrid -Message "Uninstalling Threatlocker" -Level "Info"; Uninstall-ThreatLocker } "uninstallThreatLocker" { Write-LogHybrid -Message "Uninstalling Threatlocker" -Level "Info"; Uninstall-ThreatLocker }
"uninstallCyberQP" { Write-LogHybrid -Message "Uninstalling CyberQP" -Level "Info";Uninstall-CyberQP } "uninstallCyberQP" { Write-LogHybrid -Message "Uninstalling CyberQP" -Level "Info";Uninstall-CyberQP }
"uninstallDattoEDR" { Uninstall-DattoEDR } "uninstallDattoEDR" { Uninstall-DattoEDR }