Add six-month domain and broker monitoring
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
#Requires -Version 5.1
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[datetime]$Since = (Get-Date).AddDays(-183),
|
||||
[datetime]$Until = (Get-Date),
|
||||
[string]$UserName,
|
||||
[string]$ComputerName,
|
||||
[string]$MonitoringRoot = 'C:\ProgramData\SGU\Monitoring',
|
||||
[string]$OutputCsv
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$eventIds = @(4624,4625,4634,4647,4778,4779,6005,6006,6008)
|
||||
$events = [Collections.Generic.List[object]]::new()
|
||||
|
||||
try {
|
||||
# Windows Server 2025 can crash the Windows Event Log service when a
|
||||
# structured query is evaluated against ForwardedEvents (wevtsvc.dll,
|
||||
# exception 0xc0000420). Read the channel without a server-side query and
|
||||
# apply every predicate in this process instead.
|
||||
Get-WinEvent -LogName 'ForwardedEvents' -ErrorAction Stop |
|
||||
Where-Object {
|
||||
$_.Id -in $eventIds -and
|
||||
$_.TimeCreated -ge $Since -and
|
||||
$_.TimeCreated -le $Until
|
||||
} |
|
||||
ForEach-Object { $events.Add($_) }
|
||||
}
|
||||
catch [System.Exception] {
|
||||
if ($_.FullyQualifiedErrorId -notlike 'NoMatchingEventsFound*') {
|
||||
Write-Verbose $_.Exception.Message
|
||||
}
|
||||
}
|
||||
|
||||
$archiveRoot = Join-Path $MonitoringRoot 'Archive'
|
||||
Get-ChildItem -LiteralPath $archiveRoot -Filter '*.evtx' -File -ErrorAction SilentlyContinue |
|
||||
Where-Object LastWriteTime -ge $Since.AddDays(-1) |
|
||||
ForEach-Object {
|
||||
try {
|
||||
Get-WinEvent -Path $_.FullName -Oldest -ErrorAction Stop |
|
||||
Where-Object { $_.Id -in $eventIds -and $_.TimeCreated -ge $Since -and $_.TimeCreated -le $Until } |
|
||||
ForEach-Object { $events.Add($_) }
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not read archive $($_.FullName): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-EventData {
|
||||
param([Parameter(Mandatory)]$EventRecord)
|
||||
|
||||
$xml = [xml]$EventRecord.ToXml()
|
||||
$data = @{}
|
||||
foreach ($item in @($xml.Event.EventData.Data)) {
|
||||
if ($item.Name) {
|
||||
$data[[string]$item.Name] = [string]$item.'#text'
|
||||
}
|
||||
}
|
||||
[pscustomobject]@{
|
||||
Computer = [string]$xml.Event.System.Computer
|
||||
Data = $data
|
||||
}
|
||||
}
|
||||
|
||||
$openSessions = @{}
|
||||
$rows = [Collections.Generic.List[object]]::new()
|
||||
$ignoredUsers = @('ANONYMOUS LOGON','DWM-1','DWM-2','DWM-3','LOCAL SERVICE','NETWORK SERVICE','SYSTEM','UMFD-0','UMFD-1','UMFD-2','UMFD-3')
|
||||
|
||||
foreach ($eventRecord in @($events | Sort-Object TimeCreated,RecordId)) {
|
||||
$parsed = Get-EventData -EventRecord $eventRecord
|
||||
$machine = ($parsed.Computer -split '\.')[0].ToUpperInvariant()
|
||||
$data = $parsed.Data
|
||||
|
||||
if ($eventRecord.Id -in 6005,6006,6008) {
|
||||
foreach ($key in @($openSessions.Keys | Where-Object { $_ -like "$machine|*" })) {
|
||||
$session = $openSessions[$key]
|
||||
$rows.Add([pscustomobject]@{
|
||||
User = $session.User
|
||||
Computer = $machine
|
||||
StartedAt = $session.StartedAt
|
||||
EndedAt = $eventRecord.TimeCreated
|
||||
Duration = $eventRecord.TimeCreated - $session.StartedAt
|
||||
DurationMinutes = [math]::Round(($eventRecord.TimeCreated - $session.StartedAt).TotalMinutes, 2)
|
||||
LogonType = $session.LogonType
|
||||
Result = 'Interrumpida por apagado o reinicio'
|
||||
FailureStatus = $null
|
||||
})
|
||||
$openSessions.Remove($key)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if ($eventRecord.Id -eq 4625) {
|
||||
$failedUser = [string]$data.TargetUserName
|
||||
if ($failedUser -and $failedUser -notlike '*$' -and $failedUser.ToUpperInvariant() -notin $ignoredUsers) {
|
||||
$rows.Add([pscustomobject]@{
|
||||
User = if ($data.TargetDomainName) { "$($data.TargetDomainName)\$failedUser" } else { $failedUser }
|
||||
Computer = $machine
|
||||
StartedAt = $eventRecord.TimeCreated
|
||||
EndedAt = $eventRecord.TimeCreated
|
||||
Duration = [timespan]::Zero
|
||||
DurationMinutes = 0
|
||||
LogonType = [string]$data.LogonType
|
||||
Result = 'Fallida'
|
||||
FailureStatus = "$($data.Status)/$($data.SubStatus)"
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if ($eventRecord.Id -eq 4624) {
|
||||
$logonType = [string]$data.LogonType
|
||||
$targetUser = [string]$data.TargetUserName
|
||||
if ($logonType -notin @('2','10','11') -or -not $targetUser -or $targetUser -like '*$' -or
|
||||
$targetUser.ToUpperInvariant() -in $ignoredUsers) {
|
||||
continue
|
||||
}
|
||||
$logonId = [string]$data.TargetLogonId
|
||||
$key = "$machine|$logonId"
|
||||
$openSessions[$key] = [pscustomobject]@{
|
||||
User = if ($data.TargetDomainName) { "$($data.TargetDomainName)\$targetUser" } else { $targetUser }
|
||||
StartedAt = $eventRecord.TimeCreated
|
||||
LogonType = $logonType
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if ($eventRecord.Id -in 4634,4647) {
|
||||
$logonId = if ($eventRecord.Id -eq 4634) { [string]$data.TargetLogonId } else { [string]$data.SubjectLogonId }
|
||||
$key = "$machine|$logonId"
|
||||
if ($openSessions.ContainsKey($key)) {
|
||||
$session = $openSessions[$key]
|
||||
$rows.Add([pscustomobject]@{
|
||||
User = $session.User
|
||||
Computer = $machine
|
||||
StartedAt = $session.StartedAt
|
||||
EndedAt = $eventRecord.TimeCreated
|
||||
Duration = $eventRecord.TimeCreated - $session.StartedAt
|
||||
DurationMinutes = [math]::Round(($eventRecord.TimeCreated - $session.StartedAt).TotalMinutes, 2)
|
||||
LogonType = $session.LogonType
|
||||
Result = 'Completada'
|
||||
FailureStatus = $null
|
||||
})
|
||||
$openSessions.Remove($key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($key in $openSessions.Keys) {
|
||||
$session = $openSessions[$key]
|
||||
$machine = ($key -split '\|', 2)[0]
|
||||
$rows.Add([pscustomobject]@{
|
||||
User = $session.User
|
||||
Computer = $machine
|
||||
StartedAt = $session.StartedAt
|
||||
EndedAt = $null
|
||||
Duration = $Until - $session.StartedAt
|
||||
DurationMinutes = [math]::Round(($Until - $session.StartedAt).TotalMinutes, 2)
|
||||
LogonType = $session.LogonType
|
||||
Result = 'Sesión posiblemente activa'
|
||||
FailureStatus = $null
|
||||
})
|
||||
}
|
||||
|
||||
$result = @($rows | Where-Object {
|
||||
(-not $UserName -or $_.User -like "*$UserName*") -and
|
||||
(-not $ComputerName -or $_.Computer -like "*$ComputerName*")
|
||||
} | Sort-Object StartedAt -Descending)
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user