From f7b3597206046b0b1a9c24b007b9a67cc74aa05e Mon Sep 17 00:00:00 2001 From: PTah Date: Tue, 14 Jul 2026 10:45:56 +1000 Subject: [PATCH] fix: qwinsta username fallback when RCM 1149 user empty (2.1.14-SAC) On some Win10 Pro hosts EventLog 1149 has blank Param1/Param2; resolve the sole RDP session user from qwinsta before emitting Sac/notify events. --- Login_Monitor.ps1 | 81 ++++++++++++++++++++++++++++++++++++++++++++++- README.md | 2 +- README_eng.md | 2 +- version.txt | 2 +- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index 7f41176..b610c80 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -90,7 +90,7 @@ $script:SkipLogDetailLimit = 15 # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "2.1.13-SAC" +$ScriptVersion = "2.1.14-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" @@ -1583,6 +1583,78 @@ function Resolve-Rcm1149UsernameFromParts { return $p1 } +function Get-Rcm1149UsernameFromQwinsta { + <# + На части ПК (наблюдалось на Win10 Pro) RCM 1149 пишет пустые Param1/Param2, + хотя сеанс уже есть в qwinsta. Берём единственную RDP-сессию (rdp-tcp#N / Disc). + Состояния локализованы (Активно/Listen/…) — не завязываемся на английский STATE. + #> + $qwExe = Join-Path $env:SystemRoot 'System32\qwinsta.exe' + if (-not (Test-Path -LiteralPath $qwExe)) { return $null } + + $prevEa = $ErrorActionPreference + $rawLines = @() + try { + $ErrorActionPreference = 'SilentlyContinue' + $rawLines = @(& $qwExe 2>&1 | ForEach-Object { [string]$_ }) + } catch { + return $null + } finally { + $ErrorActionPreference = $prevEa + } + + $candidates = [System.Collections.Generic.List[string]]::new() + foreach ($raw in $rawLines) { + $text = if ($null -ne $raw) { $raw.Trim() } else { '' } + if ([string]::IsNullOrWhiteSpace($text)) { continue } + if ($text -match '(?i)^SESSION') { continue } + if ($text -match '^-+$') { continue } + + $parts = @($text -split '\s+' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) + if ($parts.Count -lt 2) { continue } + + $idIdx = -1 + $sid = -1 + for ($i = 0; $i -lt $parts.Count; $i++) { + $token = $parts[$i].TrimStart('>') + if ($token -match '^\d+$') { + $idIdx = $i + $sid = [int]$token + break + } + } + if ($idIdx -lt 1) { continue } + # Listener «rdp-tcp» / ID 65536 — не пользовательская сессия. + if ($sid -eq 65536) { continue } + + $before = @($parts[0..($idIdx - 1)]) + if ($before.Count -eq 1) { + $sessionName = '' + $userName = $before[0].TrimStart('>') + } else { + $sessionName = $before[0].TrimStart('>') + $userName = $before[1] + } + if ([string]::IsNullOrWhiteSpace($userName)) { continue } + if ($userName -match '(?i)^(services|console|rdp-tcp)$') { continue } + if ($sessionName -match '(?i)^console$') { continue } + if ($sessionName -match '(?i)^rdp-tcp$' -and $sessionName -notmatch '#') { continue } + + $isRdpNamed = $sessionName -match '(?i)^rdp-tcp#\d+' + $isDiscBare = [string]::IsNullOrWhiteSpace($sessionName) + if (-not ($isRdpNamed -or $isDiscBare)) { continue } + + if (-not $candidates.Contains($userName)) { + [void]$candidates.Add($userName) + } + } + + if ($candidates.Count -eq 1) { + return $candidates[0] + } + return $null +} + function Get-Rcm1149EventInfo { param($Event) $eventData = @{ @@ -4953,6 +5025,13 @@ function Start-LoginMonitor { foreach ($event in $rcmEvents) { if ($event.TimeCreated -le $lastRcmCheckTime) { continue } $rcmInfo = Get-Rcm1149EventInfo -Event $event + if ($rcmInfo.Username -eq '-' -or [string]::IsNullOrWhiteSpace($rcmInfo.Username)) { + $fromQw = Get-Rcm1149UsernameFromQwinsta + if (-not [string]::IsNullOrWhiteSpace($fromQw)) { + Write-Log "RCM 1149: EventLog user empty — qwinsta fallback User=$fromQw" + $rcmInfo.Username = $fromQw + } + } if ($rcmInfo.Username -like "*$") { $rcmSkipped++ Write-Log "Skip 1149: User=$($rcmInfo.Username) IP=$($rcmInfo.ClientIP) — machine account" diff --git a/README.md b/README.md index ba5b3e8..92d0845 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RDP Login Monitor -**Версия:** `2.1.11-SAC` (`$ScriptVersion` + `version.txt`) +**Версия:** `2.1.14-SAC` (`$ScriptVersion` + `version.txt`) PowerShell-мониторинг Windows: RDP/RDS, RD Gateway, WinRM, admin share, блокировки УЗ, heartbeat, отчёты. diff --git a/README_eng.md b/README_eng.md index 6ccdd90..cb9b04e 100644 --- a/README_eng.md +++ b/README_eng.md @@ -1,6 +1,6 @@ # RDP Login Monitor -**Version:** `2.1.11-SAC` (`$ScriptVersion` + `version.txt`) +**Version:** `2.1.14-SAC` (`$ScriptVersion` + `version.txt`) PowerShell toolkit for monitoring Windows logons with Telegram and/or Email (SMTP) notifications. diff --git a/version.txt b/version.txt index c681f05..2172582 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.1.13-SAC +2.1.14-SAC