fix: daily report survives empty quser sessions (2.0.18-SAC)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+58
-35
@@ -89,7 +89,7 @@ $script:SkipLogDetailLimit = 15
|
|||||||
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
||||||
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
||||||
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
||||||
$ScriptVersion = "2.0.17-SAC"
|
$ScriptVersion = "2.0.18-SAC"
|
||||||
|
|
||||||
# Логи (все под InstallRoot)
|
# Логи (все под InstallRoot)
|
||||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||||
@@ -1831,23 +1831,49 @@ function Expand-DailyReportActiveUserEntries {
|
|||||||
return ,@($out)
|
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 {
|
function Get-DailyReportActiveUsersFromQuser {
|
||||||
$lines = [System.Collections.Generic.List[string]]::new()
|
$lines = [System.Collections.Generic.List[string]]::new()
|
||||||
$quserExe = Join-Path $env:SystemRoot 'System32\quser.exe'
|
$quserExe = Join-Path $env:SystemRoot 'System32\quser.exe'
|
||||||
if (-not (Test-Path -LiteralPath $quserExe)) {
|
if (-not (Test-Path -LiteralPath $quserExe)) {
|
||||||
return ,$lines
|
return ,$lines
|
||||||
}
|
}
|
||||||
$quserOutput = @(& $quserExe 2>$null)
|
$prevEa = $ErrorActionPreference
|
||||||
if (-not $quserOutput -or $quserOutput.Count -le 1) {
|
$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
|
return ,$lines
|
||||||
}
|
}
|
||||||
foreach ($raw in @($quserOutput | Select-Object -Skip 1)) {
|
foreach ($raw in @($dataLines | Select-Object -Skip 1)) {
|
||||||
$line = ($raw -replace '\s+', ' ').Trim()
|
$line = ($raw -replace '\s+', ' ').Trim()
|
||||||
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
||||||
$parts = $line -split ' ', 2
|
$parts = $line -split ' ', 2
|
||||||
if ($parts.Count -lt 1) { continue }
|
if ($parts.Count -lt 1) { continue }
|
||||||
$u = $parts[0].Trim()
|
$u = $parts[0].Trim().TrimStart('>')
|
||||||
if ([string]::IsNullOrWhiteSpace($u) -or $u -eq 'USERNAME') { continue }
|
if ([string]::IsNullOrWhiteSpace($u) -or $u -eq 'USERNAME' -or $u -eq 'ИМЯ') { continue }
|
||||||
$lines.Add(('👤 {0}' -f $u)) | Out-Null
|
$lines.Add(('👤 {0}' -f $u)) | Out-Null
|
||||||
}
|
}
|
||||||
return ,$lines
|
return ,$lines
|
||||||
@@ -1888,7 +1914,7 @@ function Build-DailyReportPlainBodyWindows {
|
|||||||
if ($userCount -gt 0) {
|
if ($userCount -gt 0) {
|
||||||
foreach ($u in $ActiveUsers) { [void]$sb.AppendLine(" $u") }
|
foreach ($u in $ActiveUsers) { [void]$sb.AppendLine(" $u") }
|
||||||
} else {
|
} else {
|
||||||
[void]$sb.AppendLine(' (нет данных)')
|
[void]$sb.AppendLine(' (нет активных пользователей / RDP-сессий)')
|
||||||
}
|
}
|
||||||
[void]$sb.AppendLine('')
|
[void]$sb.AppendLine('')
|
||||||
[void]$sb.AppendLine((Get-AgentNotificationSourcePlainLine))
|
[void]$sb.AppendLine((Get-AgentNotificationSourcePlainLine))
|
||||||
@@ -3321,8 +3347,8 @@ function Format-RDGatewayEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Send-DailyReport {
|
function Send-DailyReport {
|
||||||
|
$reportTime = Get-Date
|
||||||
try {
|
try {
|
||||||
$reportTime = Get-Date
|
|
||||||
$stats = Get-DailyReportAuthStats24h
|
$stats = Get-DailyReportAuthStats24h
|
||||||
$activeUsers = Expand-DailyReportActiveUserEntries -Entries @(Get-DailyReportActiveUsersFromQuser)
|
$activeUsers = Expand-DailyReportActiveUserEntries -Entries @(Get-DailyReportActiveUsersFromQuser)
|
||||||
$plainBody = Build-DailyReportPlainBodyWindows -Stats $stats -ActiveUsers $activeUsers -ReportTime $reportTime
|
$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)" `
|
-SacSummary "RDP 24ч: успех $($stats.rdp_success), неудач $($stats.rdp_failed), банов $($stats.active_bans)" `
|
||||||
-SacDetails $rdpReportDetails | Out-Null
|
-SacDetails $rdpReportDetails | Out-Null
|
||||||
Write-TextFileUtf8Bom -Path $LastReportFile -Text ($reportTime.ToString('yyyy-MM-dd HH:mm:ss'))
|
Write-TextFileUtf8Bom -Path $LastReportFile -Text ($reportTime.ToString('yyyy-MM-dd HH:mm:ss'))
|
||||||
Write-Log "Ежедневный отчет отправлен"
|
Write-Log "Ежедневный отчет отправлен (активных сессий: $($activeUsers.Count))"
|
||||||
return $true
|
return $true
|
||||||
} catch {
|
} catch {
|
||||||
Write-Log "Ошибка ежедневного отчета: $($_.Exception.Message)"
|
Write-Log "Ошибка ежедневного отчета: $($_.Exception.Message)"
|
||||||
@@ -3395,8 +3421,21 @@ function Read-LastDailyReportSentDate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Try-ClaimDailyReportSlotToday {
|
function Check-AndSendDailyReport {
|
||||||
param([datetime]$Now)
|
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'
|
$lockPath = Join-Path $script:InstallRoot 'Logs\.daily_report_claim.lock'
|
||||||
$lockStream = $null
|
$lockStream = $null
|
||||||
@@ -3409,41 +3448,25 @@ function Try-ClaimDailyReportSlotToday {
|
|||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
Write-Log 'Ежедневный отчёт: другой процесс уже отправляет (lock).'
|
Write-Log 'Ежедневный отчёт: другой процесс уже отправляет (lock).'
|
||||||
return $false
|
return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$lastDate = Read-LastDailyReportSentDate
|
$lastDate = Read-LastDailyReportSentDate
|
||||||
if ($null -ne $lastDate -and $lastDate -ge $Now.Date) {
|
if ($null -ne $lastDate -and $lastDate -ge $now.Date) {
|
||||||
return $false
|
return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute)
|
||||||
}
|
}
|
||||||
Write-TextFileUtf8Bom -Path $LastReportFile -Text ($Now.ToString('yyyy-MM-dd'))
|
if (-not (Send-DailyReport)) {
|
||||||
return $true
|
Write-Log 'Ежедневный отчёт: отправка не удалась, повтор на следующем цикле мониторинга.'
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Log "Ежедневный отчёт: lock/send error: $($_.Exception.Message)"
|
||||||
} finally {
|
} finally {
|
||||||
if ($null -ne $lockStream) {
|
if ($null -ne $lockStream) {
|
||||||
$lockStream.Dispose()
|
$lockStream.Dispose()
|
||||||
}
|
}
|
||||||
Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue
|
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)
|
return (Get-NextLocalSlotBoundary -Hour $DailyReportHour -Minute $DailyReportMinute)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.0.17-SAC
|
2.0.18-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user