Update Scriptmonkey_Beta.ps1
This commit is contained in:
@@ -410,7 +410,285 @@ $ConfirmPreference = 'None'
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region Write-Log
|
#region Write-Log
|
||||||
|
|
||||||
|
# Fallback logger used when the SVSMSP module (and its Write-Log) is not available.
|
||||||
|
# Mirrors the behaviour of the toolkit Write-Log (v1.5), including:
|
||||||
|
# - Default EventLog: "SVSMSP Events" (out of Application log)
|
||||||
|
# - Default EventSource: "SVSMSP_Module"
|
||||||
|
# - Level-based Event IDs and console colors
|
||||||
|
# - Global in-memory log cache
|
||||||
|
# - One-time Event Log/source initialization with optional auto-elevation
|
||||||
|
function Write-LogHelper {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Standardized logging utility with console/file output and Windows Event Log support,
|
||||||
|
including one-time event source initialization and optional auto-elevated creation
|
||||||
|
of a custom log/source. (Fallback implementation for ScriptMonkey.)
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Mirrors the SVSMSP toolkit Write-Log so that Write-LogHybrid can safely fall back
|
||||||
|
when the module isn’t loaded.
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
Default EventLog : SVSMSP Events
|
||||||
|
Default Source : SVSMSP_Module
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Message,
|
||||||
|
|
||||||
|
[ValidateSet("Info", "Warning", "Error", "Success", "General")]
|
||||||
|
[string]$Level = "Info",
|
||||||
|
|
||||||
|
[string]$TaskCategory = "GeneralTask",
|
||||||
|
|
||||||
|
[switch]$LogToEvent = $false,
|
||||||
|
|
||||||
|
[string]$EventSource = "SVSMSP_Module",
|
||||||
|
|
||||||
|
# Custom log name so you get your own node under "Applications and Services Logs"
|
||||||
|
[string]$EventLog = "SVSMSP Events",
|
||||||
|
|
||||||
|
[int]$CustomEventID,
|
||||||
|
|
||||||
|
[string]$LogFile,
|
||||||
|
|
||||||
|
[switch]$PassThru
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------- Event ID / console color ----------
|
||||||
|
$EventID = if ($CustomEventID) { $CustomEventID } else {
|
||||||
|
switch ($Level) {
|
||||||
|
"Info" { 1000 }
|
||||||
|
"Warning" { 2000 }
|
||||||
|
"Error" { 3000 }
|
||||||
|
"Success" { 4000 }
|
||||||
|
default { 1000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$Color = switch ($Level) {
|
||||||
|
"Info" { "Cyan" }
|
||||||
|
"Warning" { "Yellow" }
|
||||||
|
"Error" { "Red" }
|
||||||
|
"Success" { "Green" }
|
||||||
|
default { "White" }
|
||||||
|
}
|
||||||
|
|
||||||
|
$FormattedMessage = "[$Level] [$TaskCategory] $Message (Event ID: $EventID)"
|
||||||
|
Write-Host $FormattedMessage -ForegroundColor $Color
|
||||||
|
|
||||||
|
# ---------- In-memory cache ----------
|
||||||
|
if (-not $Global:LogCache -or -not ($Global:LogCache -is [System.Collections.ArrayList])) {
|
||||||
|
$Global:LogCache = [System.Collections.ArrayList]::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
$logEntry = [PSCustomObject]@{
|
||||||
|
Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
|
||||||
|
Level = $Level
|
||||||
|
Message = $FormattedMessage
|
||||||
|
}
|
||||||
|
[void]$Global:LogCache.Add($logEntry)
|
||||||
|
|
||||||
|
# ---------- Optional file output ----------
|
||||||
|
if ($LogFile) {
|
||||||
|
try {
|
||||||
|
"$($logEntry.Timestamp) $FormattedMessage" |
|
||||||
|
Out-File -FilePath $LogFile -Append -Encoding UTF8
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "[Warning] Failed to write to log file: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- Windows Event Log handling with one-time init + optional auto-elevate ----------
|
||||||
|
if ($LogToEvent) {
|
||||||
|
|
||||||
|
# Per-run cache for (LogName|Source) init state
|
||||||
|
if (-not $Global:EventSourceInitState) {
|
||||||
|
$Global:EventSourceInitState = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
$EntryType = switch ($Level) {
|
||||||
|
"Info" { "Information" }
|
||||||
|
"Warning" { "Warning" }
|
||||||
|
"Error" { "Error" }
|
||||||
|
"Success" { "Information" } # treat success as info in Event Log
|
||||||
|
default { "Information" }
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceKey = "$EventLog|$EventSource"
|
||||||
|
|
||||||
|
if (-not $Global:EventSourceInitState.ContainsKey($sourceKey) -or
|
||||||
|
-not $Global:EventSourceInitState[$sourceKey]) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Only bother if the source doesn't already exist
|
||||||
|
if (-not [System.Diagnostics.EventLog]::SourceExists($EventSource)) {
|
||||||
|
|
||||||
|
# Check if current token is admin
|
||||||
|
$isAdmin = $false
|
||||||
|
try {
|
||||||
|
$current = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$principal = New-Object Security.Principal.WindowsPrincipal($current)
|
||||||
|
$isAdmin = $principal.IsInRole(
|
||||||
|
[Security.Principal.WindowsBuiltInRole]::Administrator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$isAdmin = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isAdmin) {
|
||||||
|
# Elevated already: create log/source directly
|
||||||
|
New-EventLog -LogName $EventLog -Source $EventSource -ErrorAction Stop
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Not elevated: run a one-off helper as admin to create log/source
|
||||||
|
$helperScript = @"
|
||||||
|
if (-not [System.Diagnostics.EventLog]::SourceExists('$EventSource')) {
|
||||||
|
New-EventLog -LogName '$EventLog' -Source '$EventSource'
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
|
||||||
|
$tempPath = [System.IO.Path]::Combine(
|
||||||
|
$env:TEMP,
|
||||||
|
"Init_${EventLog}_$EventSource.ps1".Replace(' ', '_')
|
||||||
|
)
|
||||||
|
|
||||||
|
$helperScript | Set-Content -Path $tempPath -Encoding UTF8
|
||||||
|
|
||||||
|
try {
|
||||||
|
# This will trigger UAC prompt in interactive sessions
|
||||||
|
$null = Start-Process -FilePath "powershell.exe" `
|
||||||
|
-ArgumentList "-ExecutionPolicy Bypass -File `"$tempPath`"" `
|
||||||
|
-Verb RunAs -Wait -PassThru
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "[Warning] Auto-elevation to create Event Log '$EventLog' / source '$EventSource' failed: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Remove-Item -Path $tempPath -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Re-check after creation attempt
|
||||||
|
if ([System.Diagnostics.EventLog]::SourceExists($EventSource)) {
|
||||||
|
$Global:EventSourceInitState[$sourceKey] = $true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$Global:EventSourceInitState[$sourceKey] = $false
|
||||||
|
Write-Host "[Warning] Event source '$EventSource' does not exist and could not be created. Skipping Event Log write." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "[Warning] Failed to initialize Event Log '$EventLog' / source '$EventSource': $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
|
$Global:EventSourceInitState[$sourceKey] = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only write if initialization succeeded
|
||||||
|
if ($Global:EventSourceInitState[$sourceKey]) {
|
||||||
|
try {
|
||||||
|
$EventMessage = "TaskCategory: $TaskCategory | Message: $Message"
|
||||||
|
Write-EventLog -LogName $EventLog -Source $EventSource -EntryType $EntryType -EventId $EventID -Message $EventMessage
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "[Warning] Failed to write to Event Log: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# ------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ($PassThru) {
|
||||||
|
return $logEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# WRITE-LOG HYBRID
|
||||||
|
# Uses module Write-Log if present; otherwise falls back to Write-LogHelper.
|
||||||
|
# Defaults aligned with toolkit:
|
||||||
|
# EventSource = "SVSMSP_Module"
|
||||||
|
# EventLog = "SVSMSP Events"
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
function Write-LogHybrid {
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Message,
|
||||||
|
|
||||||
|
[ValidateSet("Info", "Warning", "Error", "Success", "General")]
|
||||||
|
[string]$Level = "Info",
|
||||||
|
|
||||||
|
[string]$TaskCategory = "GeneralTask",
|
||||||
|
|
||||||
|
[switch]$LogToEvent,
|
||||||
|
|
||||||
|
[string]$EventSource = "SVSMSP_Module",
|
||||||
|
|
||||||
|
[string]$EventLog = "SVSMSP Events",
|
||||||
|
|
||||||
|
[int]$CustomEventID,
|
||||||
|
|
||||||
|
[string]$LogFile,
|
||||||
|
|
||||||
|
[switch]$PassThru,
|
||||||
|
|
||||||
|
[ValidateSet("Black","DarkGray","Gray","White","Red","Green","Blue","Yellow","Magenta","Cyan")]
|
||||||
|
[string]$ForegroundColorOverride
|
||||||
|
)
|
||||||
|
|
||||||
|
$formatted = "[$Level] [$TaskCategory] $Message"
|
||||||
|
|
||||||
|
# Build the common parameter set for forwarding into Write-Log / Write-LogHelper
|
||||||
|
$invokeParams = @{
|
||||||
|
Message = $Message
|
||||||
|
Level = $Level
|
||||||
|
TaskCategory = $TaskCategory
|
||||||
|
LogToEvent = $LogToEvent
|
||||||
|
EventSource = $EventSource
|
||||||
|
EventLog = $EventLog
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PSBoundParameters.ContainsKey('CustomEventID')) {
|
||||||
|
$invokeParams.CustomEventID = $CustomEventID
|
||||||
|
}
|
||||||
|
if ($PSBoundParameters.ContainsKey('LogFile')) {
|
||||||
|
$invokeParams.LogFile = $LogFile
|
||||||
|
}
|
||||||
|
if ($PassThru) {
|
||||||
|
$invokeParams.PassThru = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (Get-Command Write-Log -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Log @invokeParams
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-LogHelper @invokeParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# No override: let Write-Log / Write-LogHelper handle everything (including console color)
|
||||||
|
if (Get-Command Write-Log -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Log @invokeParams
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-LogHelper @invokeParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Write-Log
|
||||||
|
|
||||||
|
|
||||||
# This function is used as a fallback if the SVSMSP module is not installed
|
# This function is used as a fallback if the SVSMSP module is not installed
|
||||||
# Should change this "[string]$EventLog = "Application", => [string]$EventLog = "SVS Scripting", "
|
# Should change this "[string]$EventLog = "Application", => [string]$EventLog = "SVS Scripting", "
|
||||||
|
|||||||
Reference in New Issue
Block a user