diff --git a/StackMonkey.ps1 b/StackMonkey.ps1 index 80ea1a4..779a18a 100644 --- a/StackMonkey.ps1 +++ b/StackMonkey.ps1 @@ -1,14 +1,5 @@ #region changes to be done -# seems like the command IS running without UI -# & ([ScriptBlock]::Create( (iwr 'https://sm.svstools.com').Content )) -N8nPassword 'Tndmeeisdwge!' -FetchSitesOnly - -# and iwr sm.svstools.com | iex lauched the UI as intended - -# need to test - -# Write-Host "πŸ› οΈ SAMY - Script Automation Monkey (Yeah!)" -ForegroundColor Cyan - #endregion changes to be done <# @@ -228,15 +219,15 @@ # Attempt to uninstall all versions of SVSMSP try { Uninstall-Module -Name SVSMSP -AllVersions -Force -ErrorAction Stop - Write-LogHybrid "SVSMSP module uninstalled from system." "Success" "SVSModule" + Write-LogHybrid "SVSMSP module uninstalled from system." "Success" "SVSModule" -LogToEvent } catch { # If no module was found, just warn and continue if ($_.Exception.Message -match 'No match was found') { - Write-LogHybrid "No existing SVSMSP module found to uninstall." "Warning" "SVSModule" + Write-LogHybrid "No existing SVSMSP module found to uninstall." "Warning" "SVSModule" -LogToEvent } else { - Write-LogHybrid "Failed to uninstall SVSMSP: $($_.Exception.Message)" "Error" "SVSModule" + Write-LogHybrid "Failed to uninstall SVSMSP: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent } } @@ -244,10 +235,10 @@ if (Get-PSRepository -Name SVS_Repo -ErrorAction SilentlyContinue) { try { Unregister-PSRepository -Name SVS_Repo -ErrorAction Stop - Write-LogHybrid "SVS_Repo repository unregistered." "Success" "SVSModule" + Write-LogHybrid "SVS_Repo repository unregistered." "Success" "SVSModule" -LogToEvent } catch { - Write-LogHybrid "Failed to unregister SVS_Repo: $($_.Exception.Message)" "Error" "SVSModule" + Write-LogHybrid "Failed to unregister SVS_Repo: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent } } @@ -255,10 +246,10 @@ if (Get-Module -Name SVSMSP) { try { Remove-Module SVSMSP -Force -ErrorAction Stop - Write-LogHybrid "SVSMSP module removed from current session." "Success" "SVSModule" + Write-LogHybrid "SVSMSP module removed from current session." "Success" "SVSModule" -LogToEvent } catch { - Write-LogHybrid "Failed to remove SVSMSP from session: $($_.Exception.Message)" "Error" "SVSModule" + Write-LogHybrid "Failed to remove SVSMSP from session: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent } } } @@ -267,16 +258,16 @@ function Perform-ToolkitInstallation { Perform-Cleanup - Write-LogHybrid "Registering repo $NewRepositoryName…" "Info" "SVSModule" + Write-LogHybrid "Registering repo $NewRepositoryName…" "Info" "SVSModule" -LogToEvent if (-not (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) { Register-PSRepository -Name $NewRepositoryName -SourceLocation $NewRepositoryURL -InstallationPolicy Trusted } - Write-LogHybrid "Installing module $NewModuleName…" "Info" "SVSModule" + Write-LogHybrid "Installing module $NewModuleName…" "Info" "SVSModule" -LogToEvent Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force - Write-LogHybrid "Toolkit installation complete." "Success" "SVSModule" + Write-LogHybrid "Toolkit installation complete." "Success" "SVSModule" -LogToEvent } - Write-LogHybrid "Install-SVSMSP called" "Info" "SVSModule" + Write-LogHybrid "Install-SVSMSP called" "Info" "SVSModule" -LogToEvent if ($Cleanup) { Perform-Cleanup; return } @@ -381,30 +372,57 @@ [string]$TaskCategory = "GeneralTask", [switch]$LogToEvent, [string]$EventSource = "Script Automation Monkey", - [string]$EventLog = "SVS Scripting" + [string]$EventLog = "SVS Scripting", + [ValidateSet("Black","DarkGray","Gray","White","Red","Green","Blue","Yellow","Magenta","Cyan")] + [string]$ForegroundColorOverride ) - if ( Get-Command -Name Write-Log -ErrorAction SilentlyContinue ) { - # Real Write-Log; pass through EventSource & EventLog too - Write-Log ` - -Message $Message ` - -Level $Level ` - -TaskCategory $TaskCategory ` - -LogToEvent:$LogToEvent ` - -EventSource $EventSource ` - -EventLog $EventLog + $formatted = "[$Level] [$TaskCategory] $Message" + + if ($PSBoundParameters.ContainsKey('ForegroundColorOverride')) { + # 1) print to console with the override color + Write-Host $formatted -ForegroundColor $ForegroundColorOverride + + # 2) then forward the call (sans the override) to Write-Log or Write-LogHelper + $invokeParams = @{ + Message = $Message + Level = $Level + TaskCategory = $TaskCategory + LogToEvent = $LogToEvent + EventSource = $EventSource + EventLog = $EventLog + } + + if (Get-Command Write-Log -ErrorAction SilentlyContinue) { + Write-Log @invokeParams + } + else { + Write-LogHelper @invokeParams + } } else { - # Fallback helper: also forward EventSource & EventLog - Write-LogHelper ` - -Message $Message ` - -Level $Level ` - -TaskCategory $TaskCategory ` - -LogToEvent:$LogToEvent ` - -EventSource $EventSource ` - -EventLog $EventLog + # No override: let Write-Log / Write-LogHelper handle everything (including console color) + if (Get-Command Write-Log -ErrorAction SilentlyContinue) { + Write-Log ` + -Message $Message ` + -Level $Level ` + -TaskCategory $TaskCategory ` + -LogToEvent:$LogToEvent ` + -EventSource $EventSource ` + -EventLog $EventLog + } + else { + Write-LogHelper ` + -Message $Message ` + -Level $Level ` + -TaskCategory $TaskCategory ` + -LogToEvent:$LogToEvent ` + -EventSource $EventSource ` + -EventLog $EventLog + } } - } + } + #endregion Write-Log @@ -520,13 +538,13 @@ $subHtml try { Dispatch-Request $ctx } catch { - Write-LogHybrid "Dispatch error: $_" "Error" "Server" + Write-LogHybrid "Dispatch error: $_" "Error" "Server" -LogToEvent } } } finally { # once the loop exits, clean up $Global:Listener.Close() - Write-LogHybrid "Listener closed." "Info" "Server" + Write-LogHybrid "Listener closed." "Info" "Server" -LogToEvent } } #endregion Strat-Server @@ -1180,7 +1198,7 @@ $script } catch { # Log the exception and return HTTP 500 - Write-LogHybrid "Handle-FetchSites error: $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Handle-FetchSites error: $($_.Exception.Message)" Error DattoRMM -LogToEvent $Context.Response.StatusCode = 500 Respond-Text $Context "Internal server error fetching sites." } @@ -1215,7 +1233,7 @@ function Handle-InstallDattoRMM { } catch { # Log the exception and return HTTP 500 - Write-LogHybrid "Handle-InstallDattoRMM error: $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Handle-InstallDattoRMM error: $($_.Exception.Message)" Error DattoRMM -LogToEvent $Context.Response.StatusCode = 500 Respond-Text $Context "Internal server error during DattoRMM install." } @@ -1315,13 +1333,13 @@ function Install-DattoRMM { # Validate mutually-dependent switches if ($SaveSitesList -and -not $FetchSites) { - Write-LogHybrid "-SaveSitesList requires -FetchSites." Error DattoRMM; return + Write-LogHybrid "-SaveSitesList requires -FetchSites." Error DattoRMM -LogToEvent; return } # 1) Optionally fetch credentials from webhook if ($UseWebhook) { if (-not $WebhookPassword) { - Write-LogHybrid "Webhook password missing." Error DattoRMM; return + Write-LogHybrid "Webhook password missing." Error DattoRMM -LogToEvent; return } try { $resp = Invoke-RestMethod -Uri $WebhookUrl ` @@ -1330,15 +1348,15 @@ function Install-DattoRMM { $ApiUrl = $resp.ApiUrl $ApiKey = $resp.ApiKey $ApiSecretKey = $resp.ApiSecretKey - Write-LogHybrid "Webhook credentials fetched." Success DattoRMM + Write-LogHybrid "Webhook credentials fetched." Success DattoRMM -LogToEvent } catch { - Write-LogHybrid "Failed to fetch webhook credentials: $($_.Exception.Message)" Error DattoRMM; return + Write-LogHybrid "Failed to fetch webhook credentials: $($_.Exception.Message)" Error DattoRMM -LogToEvent; return } } # 2) Validate API parameters if (-not $ApiUrl -or -not $ApiKey -or -not $ApiSecretKey) { - Write-LogHybrid "Missing required API parameters." Error DattoRMM; return + Write-LogHybrid "Missing required API parameters." Error DattoRMM -LogToEvent; return } # 3) Acquire OAuth token @@ -1353,9 +1371,9 @@ function Install-DattoRMM { -ContentType 'application/x-www-form-urlencoded' ` -Body "grant_type=password&username=$ApiKey&password=$ApiSecretKey" $token = $tokenResp.access_token - Write-LogHybrid "OAuth token acquired." Success DattoRMM + Write-LogHybrid "OAuth token acquired." Success DattoRMM -LogToEvent } catch { - Write-LogHybrid "OAuth token fetch failed: $($_.Exception.Message)" Error DattoRMM; return + Write-LogHybrid "OAuth token fetch failed: $($_.Exception.Message)" Error DattoRMM-LogToEvent; return } $headers = @{ Authorization = "Bearer $token" } @@ -1366,7 +1384,7 @@ function Install-DattoRMM { $siteList = $sitesResp.sites | ForEach-Object { [PSCustomObject]@{ Name = $_.name; UID = $_.uid } } - Write-LogHybrid "Fetched $($siteList.Count) sites." Success DattoRMM + Write-LogHybrid "Fetched $($siteList.Count) sites." Success DattoRMM -LogToEvent if ($SaveSitesList) { $desktop = [Environment]::GetFolderPath('Desktop') @@ -1377,12 +1395,12 @@ function Install-DattoRMM { } else { $siteList | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8 } - Write-LogHybrid "Wrote $($siteList.Count) sites to $path" Success DattoRMM + Write-LogHybrid "Wrote $($siteList.Count) sites to $path" Success DattoRMM -LogToEvent } return $siteList } catch { - Write-LogHybrid "Failed to fetch sites: $($_.Exception.Message)" Error DattoRMM; return @() + Write-LogHybrid "Failed to fetch sites: $($_.Exception.Message)" Error DattoRMM -LogToEvent; return @() } } @@ -1390,18 +1408,18 @@ function Install-DattoRMM { if ($PushSiteVars) { try { $varsResp = Invoke-RestMethod -Uri "$ApiUrl/api/v2/site/$SiteUID/variables" -Method Get -Headers $headers - Write-LogHybrid "Fetched variables for '$SiteName'." Success DattoRMM + Write-LogHybrid "Fetched variables for '$SiteName'." Success DattoRMM -LogToEvent } catch { - Write-LogHybrid "Variable fetch failed: $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Variable fetch failed: $($_.Exception.Message)" Error DattoRMM -LogToEvent } $regPath = "HKLM:\Software\SVS\Deployment" foreach ($v in $varsResp.variables) { try { if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null } New-ItemProperty -Path $regPath -Name $v.name -Value $v.value -PropertyType String -Force | Out-Null - Write-LogHybrid "Wrote '$($v.name)' to registry." Success DattoRMM + Write-LogHybrid "Wrote '$($v.name)' to registry." Success DattoRMM -LogToEvent } catch { - Write-LogHybrid "Failed to write '$($v.name)': $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Failed to write '$($v.name)': $($_.Exception.Message)" Error DattoRMM -LogToEvent } } } @@ -1413,11 +1431,11 @@ function Install-DattoRMM { $dlUrl = "https://zinfandel.centrastage.net/csm/profile/downloadAgent/$SiteUID" $tmp = "$env:TEMP\AgentInstall.exe" Invoke-WebRequest -Uri $dlUrl -OutFile $tmp -UseBasicParsing - Write-LogHybrid "Downloaded agent to $tmp." Info DattoRMM + Write-LogHybrid "Downloaded agent to $tmp." Info DattoRMM -LogToEvent Start-Process -FilePath $tmp -NoNewWindow - Write-LogHybrid "RMM agent installer launched." Success DattoRMM + Write-LogHybrid "RMM agent installer launched." Success DattoRMM -LogToEvent } catch { - Write-LogHybrid "Agent install failed: $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Agent install failed: $($_.Exception.Message)" Error DattoRMM -LogToEvent } } } @@ -1429,15 +1447,15 @@ function Install-DattoRMM { $path = "C:\Temp\AgentInstall.exe" if (-not (Test-Path 'C:\Temp')) { New-Item -Path 'C:\Temp' -ItemType Directory | Out-Null } Invoke-WebRequest -Uri $dlUrl -OutFile $path -UseBasicParsing - Write-LogHybrid "Saved installer copy to $path." Info DattoRMM + Write-LogHybrid "Saved installer copy to $path." Info DattoRMM -LogToEvent } catch { - Write-LogHybrid "Save-copy failed: $($_.Exception.Message)" Error DattoRMM + Write-LogHybrid "Save-copy failed: $($_.Exception.Message)" Error DattoRMM -LogToEvent } } # 8) Warn if no action was taken if (-not ($PushSiteVars -or $InstallRMM -or $SaveCopy)) { - Write-LogHybrid "No action specified. Use -FetchSites, -SaveSitesList, -PushSiteVars, -InstallRMM, or -SaveCopy." Warning DattoRMM + Write-LogHybrid "No action specified. Use -FetchSites, -SaveSitesList, -PushSiteVars, -InstallRMM, or -SaveCopy." Warning DattoRMM -LogToEvent } } @@ -1455,7 +1473,7 @@ function Install-DattoRMM { # ---- Shutdown handler ---- if ($path -eq 'quit') { - Write-LogHybrid "Shutdown requested" "Info" "Server" + Write-LogHybrid "Shutdown requested" "Info" "Server" -LogToEvent Respond-Text $Context "Server shutting down." # stop the listener loop $Global:Listener.Stop() @@ -1497,13 +1515,13 @@ function Install-DattoRMM { switch ($PSCmdlet.ParameterSetName) { 'Toolkit' { - Write-LogHybrid "Toolkit-only mode" Info Startup + Write-LogHybrid "Toolkit-only mode" Info Startup -LogToEvent Install-SVSMSP -InstallToolkit return } 'Cleanup' { - Write-LogHybrid "Running Toolkit cleanup mode" Info Startup + Write-LogHybrid "Running Toolkit cleanup mode" Info Startup -LogToEvent Install-SVSMSP -Cleanup return } @@ -1513,7 +1531,7 @@ function Install-DattoRMM { # ─────────────────────────────────────────────────────────── 'DattoFetch' { - Write-LogHybrid "Fetching site list only…" Info DattoAuth + Write-LogHybrid "Fetching site list only…" Info DattoAuth -LogToEvent $sites = Install-DattoRMM ` -UseWebhook ` -WebhookPassword $WebhookPassword ` @@ -1521,7 +1539,7 @@ function Install-DattoRMM { -SaveSitesList:$SaveSitesList ` -OutputFile $OutputFile - Write-LogHybrid "Done." Success DattoAuth + Write-LogHybrid "Done." Success DattoAuth -LogToEvent return } @@ -1531,7 +1549,7 @@ function Install-DattoRMM { # ──────────────────────────────────────────── 'DattoInstall' { - Write-LogHybrid "Headless DattoRMM deploy" Info DattoAuth + Write-LogHybrid "Headless DattoRMM deploy" Info DattoAuth -LogToEvent if ($PSCmdlet.ShouldProcess("Datto site '$SiteName'", "Headless install")) { Install-DattoRMM ` @@ -1549,7 +1567,7 @@ function Install-DattoRMM { } 'UI' { - Write-LogHybrid "Launching UI" Info Startup + Write-LogHybrid "Launching UI" Info Startup -LogToEvent Write-Host "Starting ScriptMonkey UI on http://localhost:$Port/" -ForegroundColor Cyan Start-Process "msedge.exe" -ArgumentList "--app=http://localhost:$Port" Start-Server # blocks until you click Exit @@ -1584,10 +1602,10 @@ function Install-DattoRMM { # re-query just for version info $found = Get-PackageProvider -Name NuGet -ListAvailable - Write-Host "Installed NuGet provider v$($found.Version)" -ForegroundColor Green + Write-LogHybrid "Installed NuGet provider v$($found.Version)" Info Bootstrap -LogToEvent } else { - Write-Host "NuGet provider already present (v$($found.Version))" -ForegroundColor DarkGray + Write-LogHybrid "NuGet provider already present (v$($found.Version))" Info Bootstrap -LogToEvent } # now import it silently @@ -1601,13 +1619,11 @@ function Install-DattoRMM { -InstallationPolicy Trusted ` -ErrorAction SilentlyContinue | Out-Null - Write-Host "PSGallery marked as Trusted" -ForegroundColor Green + Write-LogHybrid "PSGallery marked as Trusted" Info Bootstrap -LogToEvent } #endregion - - #region HTTP Listener & Routing # Handle shutdown command