Add ignore.lst filtering for Security logon alerts

Support user/workstation/IP rules and Telegram-style lines; add ignore.lst.example; bump to 1.3.14.
This commit is contained in:
PTah
2026-05-04 07:55:04 +10:00
parent fe600790e8
commit d3154ceb1b
3 changed files with 156 additions and 2 deletions
+131 -1
View File
@@ -69,7 +69,7 @@ $script:MonitorSingletonLockStream = $null
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
$ScriptVersion = "1.3.13"
$ScriptVersion = "1.3.14"
# Логи (все под InstallRoot)
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
@@ -84,6 +84,10 @@ $LogRotationMinute = 0
$HeartbeatInterval = 3600
$HeartbeatFile = Join-Path $script:InstallRoot "Logs\last_heartbeat.txt"
$DeployUpdateMarkerFile = Join-Path $script:InstallRoot "deploy_last_update.txt"
# Построчные правила подавления уведомлений Security 4624/4625 (см. ignore.lst.example в репозитории).
$script:IgnoreListPath = Join-Path $script:InstallRoot "ignore.lst"
$script:IgnoreListCache = $null
$script:IgnoreListCacheStampUtc = $null
# Ежедневный отчет
$DailyReportHour = 9
@@ -1105,6 +1109,126 @@ function Get-LogonTypeName {
}
}
function Test-RdpMonitorUsernameMatchesToken {
param([string]$Username, [string]$Token)
if ([string]::IsNullOrWhiteSpace($Username) -or [string]::IsNullOrWhiteSpace($Token)) { return $false }
if ($Username -ieq $Token) { return $true }
if ($Token.Contains('\')) {
return ($Username -ieq $Token)
}
$i = $Username.LastIndexOf('\')
if ($i -ge 0 -and $i -lt ($Username.Length - 1)) {
$sam = $Username.Substring($i + 1)
if ($sam -ieq $Token) { return $true }
}
return $false
}
function Parse-RdpMonitorIgnoreListLine {
param([string]$RawLine)
$line = ([string]$RawLine).Trim()
if ($line.Length -eq 0) { return $null }
if ($line[0] -eq '#' -or $line[0] -eq ';') { return $null }
if ($line.StartsWith([char]0xFEFF)) { $line = $line.TrimStart([char]0xFEFF) }
if ($line -notmatch ':') {
return [pscustomobject]@{ Kind = 'Any'; Value = $line }
}
$idx = $line.IndexOf(':')
$left = $line.Substring(0, $idx).Trim()
$right = $line.Substring($idx + 1).Trim()
if ([string]::IsNullOrWhiteSpace($right)) { return $null }
if ($left -match '(?i)(рабоч|workstation|wks)') {
return [pscustomobject]@{ Kind = 'Workstation'; Value = $right }
}
if ($left -match '(?i)(польз|username|subject|account|target\s*user|\buser\b)') {
return [pscustomobject]@{ Kind = 'User'; Value = $right }
}
if ($left -match '(?i)(\bip\b|ip\s*адрес|ipaddress|адрес\s*ip)') {
return [pscustomobject]@{ Kind = 'Ip'; Value = $right }
}
return [pscustomobject]@{ Kind = 'Any'; Value = $right }
}
function Get-RdpMonitorIgnoreListEntries {
if (-not (Test-Path -LiteralPath $script:IgnoreListPath)) {
$script:IgnoreListCache = @()
$script:IgnoreListCacheStampUtc = $null
return $script:IgnoreListCache
}
try {
$fi = Get-Item -LiteralPath $script:IgnoreListPath -ErrorAction Stop
$stamp = $fi.LastWriteTimeUtc
if ($null -ne $script:IgnoreListCache -and $script:IgnoreListCacheStampUtc -eq $stamp) {
return $script:IgnoreListCache
}
$entries = [System.Collections.Generic.List[object]]::new()
foreach ($ln in (Get-Content -LiteralPath $script:IgnoreListPath -Encoding UTF8 -ErrorAction Stop)) {
$e = Parse-RdpMonitorIgnoreListLine -RawLine $ln
if ($null -ne $e) { $entries.Add($e) | Out-Null }
}
$script:IgnoreListCache = @($entries)
$script:IgnoreListCacheStampUtc = $stamp
return $script:IgnoreListCache
} catch {
Write-Log "Предупреждение: не удалось прочитать ignore.lst: $($_.Exception.Message)"
$script:IgnoreListCache = @()
$script:IgnoreListCacheStampUtc = $null
return $script:IgnoreListCache
}
}
function Test-RdpMonitorIgnoreListMatch {
param(
[string]$Username,
[string]$ComputerName,
[string]$SourceIP
)
$entries = @(Get-RdpMonitorIgnoreListEntries)
if ($entries.Count -eq 0) { return $false }
foreach ($e in $entries) {
$v = [string]$e.Value
if ([string]::IsNullOrWhiteSpace($v)) { continue }
switch ($e.Kind) {
'User' {
if (Test-RdpMonitorUsernameMatchesToken -Username $Username -Token $v) { return $true }
}
'Workstation' {
if (-not [string]::IsNullOrWhiteSpace($ComputerName) -and $ComputerName -ne '-' -and ($ComputerName -ieq $v)) {
return $true
}
}
'Ip' {
if (-not [string]::IsNullOrWhiteSpace($SourceIP) -and $SourceIP -ne '-' -and ($SourceIP -ieq $v)) {
return $true
}
}
'Any' {
if (Test-RdpMonitorStringLooksLikeIPv4 $v) {
if (-not [string]::IsNullOrWhiteSpace($SourceIP) -and $SourceIP -ne '-' -and ($SourceIP -ieq $v)) {
return $true
}
continue
}
if ($v.Contains('\')) {
if (Test-RdpMonitorUsernameMatchesToken -Username $Username -Token $v) { return $true }
continue
}
if (-not [string]::IsNullOrWhiteSpace($ComputerName) -and $ComputerName -ne '-' -and ($ComputerName -ieq $v)) {
return $true
}
if (Test-RdpMonitorUsernameMatchesToken -Username $Username -Token $v) { return $true }
}
}
}
return $false
}
function Should-IgnoreEvent {
param(
[string]$Username,
@@ -1162,6 +1286,12 @@ function Should-IgnoreEvent {
if ($ComputerName -like $pattern) { return $true }
}
if ($EventID -in 4624, 4625) {
if (Test-RdpMonitorIgnoreListMatch -Username $Username -ComputerName $ComputerName -SourceIP $SourceIP) {
return $true
}
}
return $false
}
+24
View File
@@ -0,0 +1,24 @@
# Файл ignore.lst (UTF-8): положите рядом с Login_Monitor.ps1 в каталоге установки:
# C:\ProgramData\RDP-login-monitor\ignore.lst
#
# Каждая непустая строка — одно правило. Строки с # или ; в начале — комментарии.
# Подавляет только уведомления Security 4624/4625 (не RD Gateway, не RCM 1149).
#
# Форматы:
# user:DOMAIN\user
# user:user
# workstation:KHALILOV
# ip:212.19.6.53
# Можно вставить «как в Telegram» (берётся значение после первого «:»):
# 👤 Пользователь: user
# 🖥️ Рабочая станция (клиент из события): KHALILOV
# 🌐 IP адрес: 212.19.6.53
#
# Строка без префикса:
# KHALILOV — совпадение с именем рабочей станции ИЛИ с пользователем (sam) ИЛИ с IP (если строка — IPv4)
# 212.19.6.53 — только IP
# B26\user — пользователь целиком
# user:B26\scanner
# workstation:KHALILOV
# ip:212.19.6.53
+1 -1
View File
@@ -1 +1 @@
1.3.13
1.3.14