EventMonitor/EventProcessors/EventProcessorBase.ps1
|
# ── Event Processor Base ────────────────────────────────────────────────────── # Shared helper functions used by all event processor modules. # Provides a consistent, performant pattern for reading and processing # Windows events with proper error handling and time-range filtering. <# .SYNOPSIS Reads Windows events with time-range filtering pushed down to the EventLog API. .DESCRIPTION Wraps Get-WinEvent with a FilterHashtable that includes StartTime, so the Windows EventLog API performs the time filtering instead of pulling all events and post-filtering with Where-Object. This is critical for performance on machines with large Security logs. .PARAMETER EventId One or more Windows Event IDs to query. .PARAMETER LogName The event log name (Security, System, Application, OpenSSH/Operational, etc.). .PARAMETER StartTime Only return events created at or after this timestamp. .PARAMETER ProviderName Optional provider name filter for the event query. .OUTPUTS Array of EventLogRecord objects, or empty array if no events found. .EXAMPLE Read-WindowsEvents -EventId 4624, 4625 -LogName 'Security' -StartTime (Get-Date).AddMinutes(-5) #> function Read-WindowsEvents { [CmdletBinding()] param( [Parameter(Mandatory)] [int[]]$EventId, [Parameter(Mandatory)] [string]$LogName, [Parameter(Mandatory)] [DateTime]$StartTime, [string]$ProviderName ) $filter = @{ LogName = $LogName Id = $EventId StartTime = $StartTime } if ($ProviderName) { $filter['ProviderName'] = $ProviderName } try { Get-WinEvent -FilterHashtable $filter -ErrorAction Stop } catch { if ($_.Exception.Message -notlike '*No events were found*') { Write-EMLog -Message "Read-WindowsEvents($LogName/$($EventId -join ',')): $($_.Exception.Message)" -Level Error } @() } } <# .SYNOPSIS Reads all events from a log (no Event ID filter) with time-range filtering. .DESCRIPTION Used for logs like OpenSSH/Operational where events don't have consistent numeric IDs and must be filtered by message content post-retrieval. .PARAMETER LogName The event log name. .PARAMETER StartTime Only return events created at or after this timestamp. .OUTPUTS Array of EventLogRecord objects, or empty array if no events found. #> function Read-WindowsEventsByLog { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$LogName, [Parameter(Mandatory)] [DateTime]$StartTime ) try { Get-WinEvent -FilterHashtable @{ LogName = $LogName StartTime = $StartTime } -ErrorAction Stop } catch { if ($_.Exception.Message -notlike '*No events were found*') { Write-EMLog -Message "Read-WindowsEventsByLog($LogName): $($_.Exception.Message)" -Level Error } @() } } <# .SYNOPSIS Creates a standard error properties dictionary for exception tracking. .PARAMETER SessionId The monitoring session correlation ID. .PARAMETER FunctionName The name of the function that failed. .PARAMETER User Optional username context. .OUTPUTS Dictionary[string, string] with standard error context fields. #> function New-ErrorProperties { [CmdletBinding()] param( [string]$SessionId, [Parameter(Mandatory)] [string]$FunctionName, [string]$User ) $props = [System.Collections.Generic.Dictionary[string, string]]::new() if ($SessionId) { $props['SessionId'] = $SessionId } $props['Function'] = $FunctionName if ($User) { $props['User'] = $User } return $props } <# .SYNOPSIS Creates a new event properties dictionary with standard fields pre-populated. .PARAMETER SessionId The monitoring session correlation ID. .PARAMETER EventType The event direction/category: Connect, Disconnect, Alert, Info. .PARAMETER Severity Event severity: Critical, High, Medium, Low, Info. .OUTPUTS Dictionary[string, string] ready to have event-specific fields added. #> function New-EventProperties { [CmdletBinding()] param( [string]$SessionId, [Parameter(Mandatory)] [ValidateSet('Connect', 'Disconnect', 'Alert', 'Info')] [string]$EventType, [ValidateSet('Critical', 'High', 'Medium', 'Low', 'Info')] [string]$Severity = 'Info' ) $props = [System.Collections.Generic.Dictionary[string, string]]::new() if ($SessionId) { $props['SessionId'] = $SessionId } $props['EventType'] = $EventType $props['Severity'] = $Severity return $props } <# .SYNOPSIS Returns the registered event processor categories and their event IDs. .DESCRIPTION Provides a structured inventory of every event category this module monitors, including event IDs, log sources, severity, and descriptions. Useful for documentation, dashboards, and understanding coverage. .OUTPUTS Array of hashtables with Category, Description, Events (nested array). .EXAMPLE Get-MonitoredEventCategories | Format-Table Category, Description .EXAMPLE Get-MonitoredEventCategories | ForEach-Object { $_.Events } | Format-Table EventId, Severity, Description #> function Get-MonitoredEventCategories { [CmdletBinding()] param() @( @{ Category = 'Logon' Description = 'User authentication and session creation events' Events = @( @{ EventId = 4624; Log = 'Security'; Severity = 'Info'; Description = 'Successful logon' } @{ EventId = 4625; Log = 'Security'; Severity = 'High'; Description = 'Failed logon attempt' } @{ EventId = 4648; Log = 'Security'; Severity = 'Medium'; Description = 'Explicit credential logon' } @{ EventId = 4800; Log = 'Security'; Severity = 'Info'; Description = 'Workstation locked' } @{ EventId = 4801; Log = 'Security'; Severity = 'Info'; Description = 'Workstation unlocked' } ) } @{ Category = 'Logoff' Description = 'User session termination and disconnect events' Events = @( @{ EventId = 4647; Log = 'Security'; Severity = 'Info'; Description = 'User-initiated logoff' } @{ EventId = 4779; Log = 'Security'; Severity = 'Info'; Description = 'Terminal Services disconnect' } ) } @{ Category = 'SSH' Description = 'OpenSSH server connection and disconnection events' Events = @( @{ EventId = 0; Log = 'OpenSSH/Operational'; Severity = 'Info'; Description = 'SSH connect (public key accepted)' } @{ EventId = 0; Log = 'OpenSSH/Operational'; Severity = 'Info'; Description = 'SSH disconnect' } ) } @{ Category = 'AccountManagement' Description = 'User account creation, deletion, and modification events' Events = @( @{ EventId = 4720; Log = 'Security'; Severity = 'Critical'; Description = 'User account created' } @{ EventId = 4722; Log = 'Security'; Severity = 'High'; Description = 'User account enabled' } @{ EventId = 4723; Log = 'Security'; Severity = 'Medium'; Description = 'Password change attempted' } @{ EventId = 4724; Log = 'Security'; Severity = 'High'; Description = 'Password reset attempted' } @{ EventId = 4725; Log = 'Security'; Severity = 'High'; Description = 'User account disabled' } @{ EventId = 4726; Log = 'Security'; Severity = 'Critical'; Description = 'User account deleted' } ) } @{ Category = 'GroupManagement' Description = 'Security group membership change events' Events = @( @{ EventId = 4732; Log = 'Security'; Severity = 'Critical'; Description = 'Member added to security group' } @{ EventId = 4733; Log = 'Security'; Severity = 'High'; Description = 'Member removed from security group' } ) } @{ Category = 'PrivilegeUse' Description = 'Special privilege assignment and usage events' Events = @( @{ EventId = 4672; Log = 'Security'; Severity = 'High'; Description = 'Special privileges assigned to logon' } ) } @{ Category = 'ProcessTracking' Description = 'Process creation and termination events' Events = @( @{ EventId = 4688; Log = 'Security'; Severity = 'Medium'; Description = 'New process created' } @{ EventId = 4689; Log = 'Security'; Severity = 'Low'; Description = 'Process terminated' } ) } @{ Category = 'Persistence' Description = 'Service and scheduled task installation events (persistence indicators)' Events = @( @{ EventId = 4697; Log = 'Security'; Severity = 'Critical'; Description = 'Service installed on system' } @{ EventId = 4698; Log = 'Security'; Severity = 'Critical'; Description = 'Scheduled task created' } @{ EventId = 4702; Log = 'Security'; Severity = 'High'; Description = 'Scheduled task updated' } @{ EventId = 7045; Log = 'System'; Severity = 'High'; Description = 'New service installed (System)' } ) } @{ Category = 'AuditTampering' Description = 'Audit log and policy modification events (anti-forensics indicators)' Events = @( @{ EventId = 1102; Log = 'Security'; Severity = 'Critical'; Description = 'Audit log cleared' } @{ EventId = 4719; Log = 'Security'; Severity = 'Critical'; Description = 'System audit policy changed' } ) } @{ Category = 'PowerShellSecurity' Description = 'PowerShell script block logging events' Events = @( @{ EventId = 4104; Log = 'Microsoft-Windows-PowerShell/Operational'; Severity = 'Medium'; Description = 'PowerShell script block executed' } ) } @{ Category = 'NetworkShare' Description = 'Network share access events' Events = @( @{ EventId = 5140; Log = 'Security'; Severity = 'Medium'; Description = 'Network share accessed' } ) } @{ Category = 'SystemHealth' Description = 'System startup, shutdown, and crash events' Events = @( @{ EventId = 41; Log = 'System'; Severity = 'Critical'; Description = 'Unexpected shutdown (kernel power)' } @{ EventId = 1074; Log = 'System'; Severity = 'Info'; Description = 'Planned shutdown/restart' } @{ EventId = 1076; Log = 'System'; Severity = 'High'; Description = 'Unexpected shutdown reason' } @{ EventId = 6005; Log = 'System'; Severity = 'Info'; Description = 'Event Log service started' } @{ EventId = 6006; Log = 'System'; Severity = 'Info'; Description = 'Event Log service stopped' } @{ EventId = 6008; Log = 'System'; Severity = 'High'; Description = 'Unexpected shutdown detected' } @{ EventId = 6009; Log = 'System'; Severity = 'Info'; Description = 'OS version info at boot' } @{ EventId = 6013; Log = 'System'; Severity = 'Info'; Description = 'System uptime' } ) } @{ Category = 'NetworkFirewall' Description = 'Firewall rule changes and blocked connections' Events = @( @{ EventId = 4946; Log = 'Security'; Severity = 'High'; Description = 'Firewall rule added' } @{ EventId = 4947; Log = 'Security'; Severity = 'High'; Description = 'Firewall rule modified' } @{ EventId = 4948; Log = 'Security'; Severity = 'Critical'; Description = 'Firewall rule deleted' } @{ EventId = 5152; Log = 'Security'; Severity = 'Medium'; Description = 'Packet dropped by firewall' } @{ EventId = 5157; Log = 'Security'; Severity = 'Medium'; Description = 'Connection blocked by firewall' } ) } @{ Category = 'RDP' Description = 'Remote Desktop Protocol session lifecycle events' Events = @( @{ EventId = 21; Log = 'TerminalServices-LocalSessionManager/Operational'; Severity = 'Info'; Description = 'RDP session logon' } @{ EventId = 23; Log = 'TerminalServices-LocalSessionManager/Operational'; Severity = 'Info'; Description = 'RDP session logoff' } @{ EventId = 24; Log = 'TerminalServices-LocalSessionManager/Operational'; Severity = 'Info'; Description = 'RDP session disconnected' } @{ EventId = 25; Log = 'TerminalServices-LocalSessionManager/Operational'; Severity = 'Info'; Description = 'RDP session reconnected' } ) } @{ Category = 'WinRM' Description = 'WinRM/PowerShell remoting session events (lateral movement detection)' Events = @( @{ EventId = 6; Log = 'Microsoft-Windows-WinRM/Operational'; Severity = 'High'; Description = 'WinRM session created' } @{ EventId = 91; Log = 'Microsoft-Windows-WinRM/Operational'; Severity = 'High'; Description = 'WinRM connection failed' } ) } @{ Category = 'Defender' Description = 'Windows Defender malware detection and protection state changes' Events = @( @{ EventId = 1116; Log = 'Microsoft-Windows-Windows Defender/Operational'; Severity = 'Critical'; Description = 'Malware detected' } @{ EventId = 1117; Log = 'Microsoft-Windows-Windows Defender/Operational'; Severity = 'Critical'; Description = 'Malware action taken' } @{ EventId = 5001; Log = 'Microsoft-Windows-Windows Defender/Operational'; Severity = 'Critical'; Description = 'Real-time protection disabled' } ) } ) } |