From e3149785dce941364728b8f88177d51a9ca8a08f Mon Sep 17 00:00:00 2001 From: PTah Date: Thu, 4 Jun 2026 09:32:43 +1000 Subject: [PATCH] fix: daily report survives empty quser sessions (2.0.18-SAC) Co-authored-by: Cursor --- Login_Monitor.ps1 | 93 +++++++++++++++++++++++++++++------------------ version.txt | 2 +- 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index 8df3e60..9e1ba39 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -89,7 +89,7 @@ $script:SkipLogDetailLimit = 15 # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "2.0.17-SAC" +$ScriptVersion = "2.0.18-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" @@ -1831,23 +1831,49 @@ function Expand-DailyReportActiveUserEntries { return ,@($out) } +function Test-QuserEmptySessionsMessage { + param([string]$Line) + if ([string]::IsNullOrWhiteSpace($Line)) { return $false } + $t = $Line.Trim() + if ($t -match '(?i)No user(s)? exist(s)? for \*') { return $true } + if ($t -match '(?i)Не существуют пользователи для \*') { return $true } + if ($t -match '(?i)Пользователи отсутствуют') { return $true } + return $false +} + function Get-DailyReportActiveUsersFromQuser { $lines = [System.Collections.Generic.List[string]]::new() $quserExe = Join-Path $env:SystemRoot 'System32\quser.exe' if (-not (Test-Path -LiteralPath $quserExe)) { return ,$lines } - $quserOutput = @(& $quserExe 2>$null) - if (-not $quserOutput -or $quserOutput.Count -le 1) { + $prevEa = $ErrorActionPreference + $quserOutput = @() + try { + $ErrorActionPreference = 'SilentlyContinue' + # quser пишет «No users exist for *» в stderr; при $ErrorActionPreference Stop это рвало отчёт. + $quserOutput = @(& $quserExe 2>&1) + } catch { + Write-Log "Daily report: quser failed (ignored): $($_.Exception.Message)" + return ,$lines + } finally { + $ErrorActionPreference = $prevEa + } + $dataLines = @( + $quserOutput | ForEach-Object { [string]$_ } | Where-Object { + -not [string]::IsNullOrWhiteSpace($_) -and -not (Test-QuserEmptySessionsMessage -Line $_) + } + ) + if ($dataLines.Count -le 1) { return ,$lines } - foreach ($raw in @($quserOutput | Select-Object -Skip 1)) { + foreach ($raw in @($dataLines | Select-Object -Skip 1)) { $line = ($raw -replace '\s+', ' ').Trim() if ([string]::IsNullOrWhiteSpace($line)) { continue } $parts = $line -split ' ', 2 if ($parts.Count -lt 1) { continue } - $u = $parts[0].Trim() - if ([string]::IsNullOrWhiteSpace($u) -or $u -eq 'USERNAME') { continue } + $u = $parts[0].Trim().TrimStart('>') + if ([string]::IsNullOrWhiteSpace($u) -or $u -eq 'USERNAME' -or $u -eq 'ИМЯ') { continue } $lines.Add(('👤 {0}' -f $u)) | Out-Null } return ,$lines @@ -1888,7 +1914,7 @@ function Build-DailyReportPlainBodyWindows { if ($userCount -gt 0) { foreach ($u in $ActiveUsers) { [void]$sb.AppendLine(" $u") } } else { - [void]$sb.AppendLine(' (нет данных)') + [void]$sb.AppendLine(' (нет активных пользователей / RDP-сессий)') } [void]$sb.AppendLine('') [void]$sb.AppendLine((Get-AgentNotificationSourcePlainLine)) @@ -3321,8 +3347,8 @@ function Format-RDGatewayEvent { } function Send-DailyReport { + $reportTime = Get-Date try { - $reportTime = Get-Date $stats = Get-DailyReportAuthStats24h $activeUsers = Expand-DailyReportActiveUserEntries -Entries @(Get-DailyReportActiveUsersFromQuser) $plainBody = Build-DailyReportPlainBodyWindows -Stats $stats -ActiveUsers $activeUsers -ReportTime $reportTime @@ -3360,7 +3386,7 @@ function Send-DailyReport { -SacSummary "RDP 24ч: успех $($stats.rdp_success), неудач $($stats.rdp_failed), банов $($stats.active_bans)" ` -SacDetails $rdpReportDetails | Out-Null Write-TextFileUtf8Bom -Path $LastReportFile -Text ($reportTime.ToString('yyyy-MM-dd HH:mm:ss')) - Write-Log "Ежедневный отчет отправлен" + Write-Log "Ежедневный отчет отправлен (активных сессий: $($activeUsers.Count))" return $true } catch { Write-Log "Ошибка ежедневного отчета: $($_.Exception.Message)" @@ -3395,8 +3421,21 @@ function Read-LastDailyReportSentDate { } } -function Try-ClaimDailyReportSlotToday { - param([datetime]$Now) +function Check-AndSendDailyReport { + if (-not (Test-DailyReportEnabledFlag)) { + return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) + } + + $now = Get-Date + $reportSlotToday = Get-Date -Year $now.Year -Month $now.Month -Day $now.Day -Hour $DailyReportHour -Minute $DailyReportMinute -Second 0 + if ($now -lt $reportSlotToday) { + return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) + } + + $lastDate = Read-LastDailyReportSentDate + if ($null -ne $lastDate -and $lastDate -ge $now.Date) { + return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) + } $lockPath = Join-Path $script:InstallRoot 'Logs\.daily_report_claim.lock' $lockStream = $null @@ -3409,41 +3448,25 @@ function Try-ClaimDailyReportSlotToday { ) } catch { Write-Log 'Ежедневный отчёт: другой процесс уже отправляет (lock).' - return $false + return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) } try { $lastDate = Read-LastDailyReportSentDate - if ($null -ne $lastDate -and $lastDate -ge $Now.Date) { - return $false + if ($null -ne $lastDate -and $lastDate -ge $now.Date) { + return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) } - Write-TextFileUtf8Bom -Path $LastReportFile -Text ($Now.ToString('yyyy-MM-dd')) - return $true + if (-not (Send-DailyReport)) { + Write-Log 'Ежедневный отчёт: отправка не удалась, повтор на следующем цикле мониторинга.' + } + } catch { + Write-Log "Ежедневный отчёт: lock/send error: $($_.Exception.Message)" } finally { if ($null -ne $lockStream) { $lockStream.Dispose() } Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue } -} - -function Check-AndSendDailyReport { - if (-not (Test-DailyReportEnabledFlag)) { - return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) - } - - $now = Get-Date - $reportSlotToday = Get-Date -Year $now.Year -Month $now.Month -Day $now.Day -Hour $DailyReportHour -Minute $DailyReportMinute -Second 0 - $shouldSend = $false - if ($now -ge $reportSlotToday) { - $lastDate = Read-LastDailyReportSentDate - if ($null -eq $lastDate -or $lastDate -lt $now.Date) { - $shouldSend = $true - } - } - if ($shouldSend -and (Try-ClaimDailyReportSlotToday -Now $now)) { - Send-DailyReport | Out-Null - } return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute) } diff --git a/version.txt b/version.txt index c480f60..8bc951d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.17-SAC +2.0.18-SAC