feat: lifecycle notifications with telegram_via and settings reload 1.2.30-SAC

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 12:25:50 +10:00
parent 2395f536cd
commit a74c8df877
3 changed files with 69 additions and 23 deletions
+36 -10
View File
@@ -80,7 +80,7 @@ $script:MonitorLoopInitialized = $false
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
$ScriptVersion = "1.2.29-SAC" $ScriptVersion = "1.2.30-SAC"
# Логи (все под InstallRoot) # Логи (все под InstallRoot)
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
@@ -952,6 +952,23 @@ function Send-MonitorNotification {
return $anyOk return $anyOk
} }
function Send-RdpMonitorLifecycleNotification {
param(
[Parameter(Mandatory = $true)][string]$Lifecycle,
[Parameter(Mandatory = $true)][string]$Trigger,
[Parameter(Mandatory = $true)][string]$TelegramHtmlMessage,
[Parameter(Mandatory = $true)][string]$SacSummary,
[string]$SacTitle = '',
[string]$SacSeverity = 'info',
[string]$EmailSubject = 'RDP Login Monitor'
)
$title = if (-not [string]::IsNullOrWhiteSpace($SacTitle)) { $SacTitle } else { "RDP login monitor: $Lifecycle" }
Send-MonitorNotification -Message $TelegramHtmlMessage -EmailSubject $EmailSubject `
-SacEventType 'agent.lifecycle' -SacSeverity $SacSeverity -SacTitle $title -SacSummary $SacSummary `
-SacDetails @{ lifecycle = $Lifecycle; trigger = $Trigger } | Out-Null
}
function Test-Administrator { function Test-Administrator {
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser) $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
@@ -1806,8 +1823,10 @@ function Send-Heartbeat {
$message = "<b>✅ Мониторинг логинов ЗАПУЩЕН</b>`r`n" $message = "<b>✅ Мониторинг логинов ЗАПУЩЕН</b>`r`n"
$message += "🏷️ Версия скрипта: $(ConvertTo-TelegramHtml $ScriptVersion)" $message += "🏷️ Версия скрипта: $(ConvertTo-TelegramHtml $ScriptVersion)"
$upd = Get-DeployUpdateMarker $upd = Get-DeployUpdateMarker
$lifecycleTrigger = 'boot'
if ($upd.PendingStartupNotice -and $upd.Version -eq $ScriptVersion -and -not [string]::IsNullOrWhiteSpace($upd.UpdatedAt)) { if ($upd.PendingStartupNotice -and $upd.Version -eq $ScriptVersion -and -not [string]::IsNullOrWhiteSpace($upd.UpdatedAt)) {
$message += " (обновлён $(ConvertTo-TelegramHtml $upd.UpdatedAt))" $message += " (обновлён $(ConvertTo-TelegramHtml $upd.UpdatedAt))"
$lifecycleTrigger = 'deploy_recycle'
Set-DeployUpdateMarkerPendingOff -Marker $upd Set-DeployUpdateMarkerPendingOff -Marker $upd
} }
$message += "`r`n" $message += "`r`n"
@@ -1863,11 +1882,10 @@ function Send-Heartbeat {
$message += " IP из IIS не заданы (<code>ExchangeIisLogPath</code> пуст)." $message += " IP из IIS не заданы (<code>ExchangeIisLogPath</code> пуст)."
} }
} }
Send-MonitorNotification -Message $message -EmailSubject "RDP Login Monitor: запуск" ` Send-RdpMonitorLifecycleNotification -Lifecycle 'started' -Trigger $lifecycleTrigger `
-SacEventType 'agent.lifecycle' -SacSeverity 'info' ` -TelegramHtmlMessage $message -EmailSubject 'RDP Login Monitor: запуск' `
-SacTitle 'RDP login monitor started' ` -SacTitle 'RDP login monitor started' `
-SacSummary "Мониторинг запущен на $(Get-MonitorServerLabel), версия $ScriptVersion" ` -SacSummary "Мониторинг запущен на $(Get-MonitorServerLabel), версия $ScriptVersion"
-SacDetails @{ lifecycle = 'started' } | Out-Null
Write-Log "Отправлено уведомление о запуске скрипта (каналы: $notifyChain)" Write-Log "Отправлено уведомление о запуске скрипта (каналы: $notifyChain)"
} else { } else {
Write-TextFileUtf8Bom -Path $HeartbeatFile -Text $timestamp Write-TextFileUtf8Bom -Path $HeartbeatFile -Text $timestamp
@@ -1944,11 +1962,10 @@ function Send-StopNotification {
$message += "🕐 Время остановки: $timestamp`r`n" $message += "🕐 Время остановки: $timestamp`r`n"
$message += "📋 Причина: $hReason" $message += "📋 Причина: $hReason"
Send-MonitorNotification -Message $message -EmailSubject "RDP Login Monitor: остановка" ` Send-RdpMonitorLifecycleNotification -Lifecycle 'stopped' -Trigger 'shutdown' `
-SacEventType 'agent.lifecycle' -SacSeverity 'info' ` -TelegramHtmlMessage $message -EmailSubject 'RDP Login Monitor: остановка' `
-SacTitle 'RDP login monitor stopped' ` -SacTitle 'RDP login monitor stopped' -SacSeverity 'info' `
-SacSummary "Мониторинг остановлен: $Reason" ` -SacSummary "Мониторинг остановлен: $Reason"
-SacDetails @{ lifecycle = 'stopped'; reason = $Reason } | Out-Null
Write-Log "Уведомление об остановке отправлено: $Reason" Write-Log "Уведомление об остановке отправлено: $Reason"
} }
@@ -3175,6 +3192,15 @@ function Start-LoginMonitor {
} }
Write-Log "Graceful restart (settings): запрос '$($restartReq.Reason)' — перечитываю настройки в этом же процессе PowerShell." Write-Log "Graceful restart (settings): запрос '$($restartReq.Reason)' — перечитываю настройки в этом же процессе PowerShell."
Invoke-RdpMonitorReloadSettings | Out-Null Invoke-RdpMonitorReloadSettings | Out-Null
$hHost = ConvertTo-TelegramHtml (Get-MonitorServerLabel)
$reloadMsg = "<b>🔄 Настройки монитора перечитаны</b>`r`n"
$reloadMsg += "🖥️ Сервер: $hHost`r`n"
$reloadMsg += "🏷️ Версия: $(ConvertTo-TelegramHtml $ScriptVersion)`r`n"
$reloadMsg += "📢 Каналы: $(ConvertTo-TelegramHtml (Get-NotifyChainHuman))"
Send-RdpMonitorLifecycleNotification -Lifecycle 'settings_reloaded' -Trigger 'settings_reload' `
-TelegramHtmlMessage $reloadMsg -EmailSubject 'RDP Login Monitor: settings reload' `
-SacTitle 'RDP login monitor settings reloaded' `
-SacSummary "Настройки перечитаны на $(Get-MonitorServerLabel), версия $ScriptVersion"
break break
} }
+32 -12
View File
@@ -624,14 +624,9 @@ function Send-SacEvent {
return $false return $false
} }
$mergedDetails = @{} $mergedDetails = Merge-SacNotifyDetails -Details $Details -TelegramVia ''
if ($null -ne $Details) { if ($mergedDetails.Count -eq 0) {
foreach ($k in $Details.Keys) { $mergedDetails = $null
$mergedDetails[$k] = $Details[$k]
}
}
if (-not $mergedDetails.ContainsKey('generated_by')) {
$mergedDetails['generated_by'] = 'agent'
} }
$payload = $(New-SacEventPayload -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $mergedDetails) $payload = $(New-SacEventPayload -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $mergedDetails)
@@ -675,6 +670,27 @@ function Test-SacHeartbeatOnlyEventType {
return ($EventType -eq 'agent.heartbeat') return ($EventType -eq 'agent.heartbeat')
} }
function Merge-SacNotifyDetails {
param(
[hashtable]$Details = $null,
[string]$TelegramVia = ''
)
$merged = @{}
if ($null -ne $Details) {
foreach ($k in $Details.Keys) {
$merged[$k] = $Details[$k]
}
}
if (-not $merged.ContainsKey('generated_by')) {
$merged['generated_by'] = 'agent'
}
if (-not [string]::IsNullOrWhiteSpace($TelegramVia) -and -not $merged.ContainsKey('telegram_via')) {
$merged['telegram_via'] = $TelegramVia.Trim().ToLowerInvariant()
}
return $merged
}
function Send-NotifyOrSac { function Send-NotifyOrSac {
param( param(
[Parameter(Mandatory = $true)][string]$EventType, [Parameter(Mandatory = $true)][string]$EventType,
@@ -697,7 +713,8 @@ function Send-NotifyOrSac {
if ($mode -eq 'off') { if ($mode -eq 'off') {
return $false return $false
} }
return (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $Details) $hbDetails = Merge-SacNotifyDetails -Details $Details -TelegramVia 'sac'
return (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $hbDetails)
} }
switch ($mode) { switch ($mode) {
@@ -705,14 +722,17 @@ function Send-NotifyOrSac {
return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject) return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject)
} }
'exclusive' { 'exclusive' {
return (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $Details) $merged = Merge-SacNotifyDetails -Details $Details -TelegramVia 'sac'
return (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $merged)
} }
'dual' { 'dual' {
Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $Details | Out-Null $merged = Merge-SacNotifyDetails -Details $Details -TelegramVia 'agent'
Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $merged | Out-Null
return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject) return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject)
} }
'fallback' { 'fallback' {
if (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $Details) { $merged = Merge-SacNotifyDetails -Details $Details -TelegramVia 'sac'
if (Send-SacEvent -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $merged) {
return $true return $true
} }
return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject) return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject)
+1 -1
View File
@@ -1 +1 @@
1.2.29-SAC 1.2.30-SAC