Ни один «логгер» не поможет, если не включены корректные политики аудита. Правильная конфигурация даёт:
прозрачность: кто/когда/откуда вошёл по RDP;
быстрые алерты при неожиданных входах;
доказательную базу при инцидентах.
Включаем аудит входов/выходов и RDP‑сессий
Выполните от имени администратора (PowerShell или CMD):
REM Базовый аудит входов/выходов
AuditPol /set /subcategory:"Logon" /success:enable /failure:enable
AuditPol /set /subcategory:"Logoff" /success:enable
AuditPol /set /subcategory:"Special Logon" /success:enable
AuditPol /set /subcategory:"Logon with explicit credentials" /success:enable /failure:enable
REM Дополнительные события логона/логаута (RDP‑сессии, тайм-ауты и т.п.)
AuditPol /set /subcategory:"Other Logon/Logoff Events" /success:enable /failure:enable
REM Рекомендуется: отслеживание изменений политик аутентификации/авторизации
AuditPol /set /subcategory:"Authentication Policy Change" /success:enable /failure:enable
AuditPol /set /subcategory:"Authorization Policy Change" /success:enable /failure:enable
Проверить состояние:
AuditPol /get /category:"Logon/Logoff"
Где смотреть события:
журнал безопасности Event Viewer → Windows Logs → Security
Ключевые события:
4624 — успешный вход (RDP = LogonType 10)
4625 — неудачный вход (ошибка пароля, несуществующая учётка и т.п.)
4634 — выход из системы
4778/4779 — подключение/отключение от RDP‑сеанса
Фильтрация RDP:
LogonType = 10 (RemoteInteractive)
Создаем триггер на событие
Мы будем запускать PowerShell‑скрипт только когда срабатывает RDP‑событие (например, 4624 с LogonType=10). Это делается через Планировщик заданий с Event Trigger.
Вариант A. Через графический интерфейс
Откройте Event Viewer → Windows Logs → Security.
Отфильтруйте события по ID = 4624.
Найдите любую успешную RDP‑событие (вкладка Details →
EventData → LogonType = 10).Правый клик → Attach Task To This Event…
Имя:
RDP_Alert_On_4624_Lt10Действие: Start a Program →
powershell.exeАргументы:
-NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\RdpAlert.ps1"Готово.
Затем отредактируйте триггер → вкладка Triggers → Edit… → вкладка Custom → New Event Filter → XML → Edit query manually и вставьте точный XML‑фильтр:
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[(EventID=4624)]]
and
*[EventData[Data[@Name='LogonType']='10']]
</Select>
</Query>
</QueryList>
Вариант B. Одной командой
Создайте задачу через schtasks:
schtasks /Create /TN "RDP_Alert_On_4624_Lt10" ^
/SC ONEVENT ^
/EC Security ^
/MO "*[System[(EventID=4624)]] and *[EventData[Data[@Name='LogonType']='10']]" ^
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RdpAlert.ps1" ^
/RU SYSTEM
Аналогично можно создать задачи для 4625 (неудачные входы) и для 4778/4779 (подключение/отключение сеансов).
Скрипт уведомлений (Telegram и/или email)
Создайте папку и скрипт:
New-Item -ItemType Directory -Path C:\Scripts -Force | Out-Null
notepad C:\Scripts\RdpAlert.ps1
Вставьте скрипт ниже и сохраните.
🔔 RdpAlert.ps1 — универсальный алёртер
Парсит полученное событие;
Проверяет «белый список» аккаунтов/IP;
Проверяет «разрешённые часы»;
Шлёт алерт в Telegram и/или на email.
Заполните константы
$BotToken,$ChatId,$Smtp*.
# RdpAlert.ps1
# Работает как целевое действие в Task Scheduler (ONEVENT). Не требует резидентного агента.
param()
# -------------------- Настройки --------------------
# Telegram Bot API
$BotToken = "123456789:REPLACE_WITH_YOUR_BOT_TOKEN"
$ChatId = "REPLACE_WITH_YOUR_CHAT_ID" # например, свой user/chat id
# Email SMTP (по желанию)
$SmtpServer = "smtp.example.com"
$SmtpPort = 587
$SmtpFrom = "rdp-alert@example.com"
$SmtpTo = "security@example.com"
$SmtpUser = "rdp-alert@example.com"
$SmtpPassword = "REPLACE_WITH_PASSWORD"
$UseTLS = $true
# Бизнес-логика: белый список и рабочие часы
$AllowedUsers = @('Administrator','svc.admin') # ожидаемые аккаунты
$AllowedIPs = @('203.0.113.10','198.51.100.25') # строками
$WorkingHours = 8..20 # разрешённые часы (локальное время сервера)
$AlertOnWorkingHoursOnly = $false # если true — алерты только в рабочие часы
# Посылать дубль e-mail?
$SendEmail = $false
# -------------------- Вспомогательные функции --------------------
function Send-Telegram {
param(
[string]$Text
)
try {
$uri = "https://api.telegram.org/bot$BotToken/sendMessage"
$body = @{
chat_id = $ChatId
text = $Text
parse_mode = "HTML"
disable_web_page_preview = $true
}
Invoke-RestMethod -Method Post -Uri $uri -Body $body -ErrorAction Stop | Out-Null
} catch {
# Лог ошибки в локальный файл
Add-Content -Path "C:\Scripts\RdpAlert.log" -Value ("Telegram error: " + $_.Exception.Message)
}
}
function Send-Mail {
param(
[string]$Subject,
[string]$Body
)
try {
$secure = ConvertTo-SecureString $SmtpPassword -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($SmtpUser, $secure)
Send-MailMessage -To $SmtpTo -From $SmtpFrom -Subject $Subject -Body $Body `
-SmtpServer $SmtpServer -Port $SmtpPort -UseSsl:$UseTLS -Credential $cred -ErrorAction Stop
} catch {
Add-Content -Path "C:\Scripts\RdpAlert.log" -Value ("SMTP error: " + $_.Exception.Message)
}
}
# -------------------- Получение контекста события --------------------
# Когда задача запускается триггером ONEVENT, последняя событие доступно так:
# $Args[0] может содержать XML события; в Task Scheduler этого нет,
# поэтому дочитываем последнее событие, подходящее под фильтр (4624 + LogonType=10).
$evt = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624} -MaxEvents 50 |
Where-Object {
($_.Properties | Where-Object { $_.Value -eq '10' }).Count -gt 0
} |
Select-Object -First 1
if (-not $evt) { exit 0 }
# Разбор EventData
$xml = [xml]$evt.ToXml()
$data = @{}
foreach ($d in $xml.Event.EventData.Data) {
$name = $d.Name
if (-not [string]::IsNullOrEmpty($name)) { $data[$name] = [string]$d.'#text' }
}
# Типовые поля
$TargetUser = $data['TargetUserName']
$IpAddress = $data['IpAddress']
$Workstation = $data['WorkstationName']
$LogonType = $data['LogonType']
$LogonProcess = $data['LogonProcessName']
$AuthPackage = $data['AuthenticationPackageName']
$When = $evt.TimeCreated
# -------------------- Бизнес‑правила --------------------
$hour = (Get-Date).Hour
$hourOk = $WorkingHours -contains $hour
$ipOk = ($IpAddress -and ($AllowedIPs -contains $IpAddress))
$userOk = ($TargetUser -and ($AllowedUsers -contains $TargetUser))
$expected = ($ipOk -or $userOk) -and ($AlertOnWorkingHoursOnly ? $hourOk : $true)
# Формируем сообщение
$header = if ($expected) { "✅ Expected/Allowed RDP logon" } else { "🚨 RDP logon ALERT" }
$msg = @"
$header
Time: $When
User: $TargetUser
Source IP: $IpAddress
Workstation: $Workstation
LogonType: $LogonType
Process: $LogonProcess
AuthPkg: $AuthPackage
EventID: 4624 (Success Logon)
Host: $(hostname)
"@
# Условие уведомления: шлём всегда, или только при неожиданных событиях
$send = $true # смените на: (!$expected) — если хотите тревожить только о неожиданных
# Отправка
if ($send) {
Send-Telegram -Text $msg
if ($SendEmail) {
Send-Mail -Subject "[RDP] $header on $(hostname)" -Body $msg
}
}
Хотите алерт только при неожиданных входах? В скрипте смените
$send = $trueна:$send = (!$expected)
Добавьте ещё триггеры (необязательно, но полезно)
Неудачные входы (4625) — подбор пароля, ошибки логина:
schtasks /Create /TN "RDP_Alert_On_4625" ^ /SC ONEVENT /EC Security ^ /MO "*[System[(EventID=4625)]] and *[EventData[Data[@Name='LogonType']='10']]" ^ /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RdpAlert.ps1" ^ /RU SYSTEM
Подключение/отключение RDP‑сеанса (4778/4779):
schtasks /Create /TN "RDP_Session_Connect_4778" ^ /SC ONEVENT /EC Security ^ /MO "*[System[(EventID=4778)]]" ^ /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RdpAlert.ps1" ^ /RU SYSTEM schtasks /Create /TN "RDP_Session_Disconnect_4779" ^ /SC ONEVENT /EC Security ^ /MO "*[System[(EventID=4779)]]" ^ /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RdpAlert.ps1" ^ /RU SYSTEM
Советы по безопасности (практический минимум)
Всегда включайте NLA (Network Level Authentication) для RDP.
Ограничьте доступ брандмауэром: разрешайте RDP только с белых IP или через VPN.
2FA / LAPS (локальные пароли с ротацией), регулярная смена паролей служебных аккаунтов.
Разведите админские учётки и повседневную работу (админ — только для админ‑сессий).
Резервируйте журналы (минимум 512–1024 МБ для Security) и экспортируйте их централизованно.
Вариант для многих серверов: Windows Event Forwarding (WEF)
Если у вас несколько хостов, вместо того чтобы ставить триггеры на каждом, сделайте:
Collector (pull): настройте один сервер как «Windows Event Collector».
На серверах‑источниках включите подписки (GPO → Subscriptions).
Сделайте одно задание с триггером на Коллекторе по 4624/4625/4778/4779 → запускайте там же
RdpAlert.ps1.
Это даёт:
единую точку настройки алертов и правил;
централизованное хранение логов (удобно для ретроспективы/форенсики).
Проверка и отладка
Убедитесь, что события появляются: Event Viewer → Security (4624/4625/4778/4779).
Протестируйте вход по RDP с внешнего IP из белого списка — должно прийти «✅ Expected…».
Протестируйте с IP вне списка — должно прийти «🚨 ALERT…».
Если Telegram не доходит — проверьте
C:\Scripts\RdpAlert.logи токен/чат‑ID.Если email не доходит — проверьте TLS/порт/аккаунты SMTP, не блокирует ли почтовый сервер.
Итог
Включили правильный аудит → события RDP появились в Security.
Поставили Event Trigger в Task Scheduler → нет резидентных сервисов, срабатывает только «по факту».
Добавили Telegram/email‑алерты → мгновенное сообщение при входе или при аномалиях.
По желанию — централизация через WEF, дополнительные триггеры на 4625/4778/4779, белые списки/рабочие часы.
Это надёжная, минималистичная и одновременно «боевая» схема: работает на чистом Windows, легко масштабируется и понятна даже непрофессионалам (админу достаточно выполнить приведённые шаги один‑в‑один).