#Requires -Version 5.1 [CmdletBinding()] param( [datetime]$Since = (Get-Date).AddDays(-183), [datetime]$Until = (Get-Date), [string]$UserName, [ValidateSet('Critical','Error','Warning','Information','Verbose')] [string]$Level, [int[]]$EventId, [string]$Text, [string]$MonitoringRoot = 'C:\ProgramData\SGU\Monitoring', [string]$BrokerEventLogName = 'SGU Auth Broker', [string]$OutputCsv ) $ErrorActionPreference = 'Stop' $events = [Collections.Generic.List[object]]::new() $eventNames = @{ 900 = 'BrokerStarted' 1000 = 'AuthenticationAuthorized' 1001 = 'AuthenticationRejected' 1002 = 'AuthenticationUnavailable' 1003 = 'AuthenticationInvalidRequest' 1100 = 'SguAuthenticationAccepted' 1101 = 'SguAuthenticationTimeout' 1102 = 'SguAuthenticationNetworkFailure' 1200 = 'ProfileEnrichmentCompleted' 1201 = 'ProfileHtmlUnexpected' 1202 = 'ProfileEnrichmentTimeout' 1203 = 'ProfileEnrichmentFailure' 1204 = 'ProfilePageUnavailable' 1300 = 'DirectorySynchronizationFailure' 1301 = 'DirectoryOptionalMetadataFailure' 1302 = 'DirectoryGroupMembershipFailure' 1303 = 'DirectoryRoleGroupMembershipAdded' } # Keep these reads unfiltered. Besides making archived and current logs behave # identically, this avoids the Windows Server 2025 ForwardedEvents query defect. if (Get-WinEvent -ListLog $BrokerEventLogName -ErrorAction SilentlyContinue) { Get-WinEvent -LogName $BrokerEventLogName -ErrorAction SilentlyContinue | Where-Object { $_.TimeCreated -ge $Since -and $_.TimeCreated -le $Until } | ForEach-Object { $events.Add($_) } } $brokerArchiveRoot = Join-Path $MonitoringRoot 'Archive\Broker' Get-ChildItem -LiteralPath $brokerArchiveRoot -Filter '*.evtx' -File -ErrorAction SilentlyContinue | Where-Object LastWriteTime -ge $Since.AddDays(-1) | ForEach-Object { try { Get-WinEvent -Path $_.FullName -Oldest -ErrorAction Stop | Where-Object { $_.TimeCreated -ge $Since -and $_.TimeCreated -le $Until } | ForEach-Object { $events.Add($_) } } catch { Write-Warning "Could not read broker archive $($_.FullName): $($_.Exception.Message)" } } $result = @($events | Where-Object { (-not $UserName -or $_.Message -like "*$UserName*") -and (-not $Level -or $_.LevelDisplayName -eq $Level) -and (-not $EventId -or $_.Id -in $EventId) -and (-not $Text -or $_.Message -like "*$Text*") } | Sort-Object TimeCreated -Descending | ForEach-Object { [pscustomobject]@{ TimeCreated = $_.TimeCreated Level = $_.LevelDisplayName EventId = $_.Id EventName = $eventNames[[int]$_.Id] Provider = $_.ProviderName Message = $_.Message } }) if ($OutputCsv) { $resolvedOutput = [IO.Path]::GetFullPath($OutputCsv) New-Item -ItemType Directory -Path (Split-Path $resolvedOutput -Parent) -Force | Out-Null $result | Export-Csv -LiteralPath $resolvedOutput -NoTypeInformation -Encoding UTF8 } $result