Files
RDP-login-monitor/DEPLOY.md
T

179 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Развёртывание RDP Login Monitor в домене
Монитор ставится в **`C:\ProgramData\RDP-login-monitor\`**, задачи планировщика создаёт сам **`Login_Monitor.ps1`** (параметр `-InstallTasks`). Доставку по сети выполняет **`Deploy-LoginMonitor.ps1`**.
## Файлы на файловой шаре
Создайте каталог, доступный **конечным компьютерам** на чтение (часто учётная запись компьютера домена), например:
`\\dc.contoso.local\NETLOGON\RDP-login-monitor\`
Внутри должны лежать **три файла** (имена фиксированы):
| Файл | Назначение |
|------|------------|
| `Login_Monitor.ps1` | Основной скрипт (токен/chat id plain или DPAPI в параметрах). |
| `version.txt` | **Одна строка** — номер версии пакета на шаре (см. раздел «Версии» ниже). |
| `Deploy-LoginMonitor.ps1` | Установщик: сравнивает версию, копирует монитор, вызывает `-InstallTasks`, при необходимости запускает процесс монитора. |
При выпуске новой сборки обновляйте на шаре **`Login_Monitor.ps1`** и при необходимости **`version.txt`** (логика описана в разделе «Версии»).
## Как это работает
1. **`Deploy-LoginMonitor.ps1`** определяет корень дистрибутива:
- параметр **`-SourceShareRoot`** `\\server\share\RDP-login-monitor`, **или**
- если скрипт запущен по UNC, берётся **родительская папка** этого файла (удобно вызывать шару без параметров).
2. Читается **`version.txt`** на шаре и сравнивается с локальной меткой **`C:\ProgramData\RDP-login-monitor\deployed_version.txt`**. Если метки ещё нет — для сравнения подтягивается **`$ScriptVersion`** из уже установленного **`Login_Monitor.ps1`**.
3. Если версия на шаре **совпадает** с зафиксированной локально — выход без копирования (быстро, можно при каждой загрузке).
4. Если версия на шаре **новее** — останавливаются процессы монитора с каноническим путём → копируется **`Login_Monitor.ps1`** → выполняется **`Login_Monitor.ps1 -InstallTasks`** → записывается **`deployed_version.txt`** → запускается монитор (если не указан **`-SkipStartMonitorAfterUpdate`**).
5. Если версия на шаре **старее** локальной — обновление **не выполняется** (защита от отката), пока не указан **`-AllowDowngrade`**.
Лог установки: **`C:\ProgramData\RDP-login-monitor\Logs\deploy.log`**.
## Задачи планировщика после `-InstallTasks`
Параметр **`Login_Monitor.ps1 -InstallTasks`** создаёт две задачи:
| Имя | Назначение |
|-----|------------|
| **`RDP-Login-Monitor`** | Запуск основного монитора при старте ОС (`Register-ScheduledTask`, триггер «При запуске компьютера»). |
| **`RDP-Login-Monitor-Watchdog`** | Тот же файл **`Login_Monitor.ps1`** с аргументом **`-Watchdog`**: короткая проверка «жив ли монитор», при необходимости поднимает процесс. |
Watchdog регистрируется через **`schtasks.exe /Create /SC MINUTE /MO 5`** (а не через CIM-триггеры PowerShell): на части ОС у объектов триггера нет настраиваемых **`RepetitionInterval`** / длительность «раз и навсегда» режется планировщиком — из‑за этого раньше вторая задача могла не создаваться.
Перед созданием выполняется **`schtasks /Delete … /F`** (если задачи ещё не было, сообщение об ошибке подавляется — это нормально).
Сразу после регистрации задач вызывается **`schtasks /Run`** и для **основной задачи**, и для **watchdog**: первый запуск не ждёт перезагрузку и ближайшее 5‑минутное окно.
Если watchdog срабатывает, а основной монитор «не поднимается», смотрите **`Logs\watchdog.log`** (сообщение о PID и предупреждение, если процесс сразу завершился) и **конец `Logs\login_monitor.log`** — частая причина (исправлено в **1.3.5+**): пустой **`$PSCommandPath`** у процесса, запущенного через **`Start-Process`**; скрипт теперь подставляет путь через **`$PSScriptRoot`**.
Один экземпляр монитора фиксируется **файлом блокировки** в **`C:\ProgramData\RDP-login-monitor\.login_monitor_single_instance.lock`** (не Global mutex): так и **SYSTEM** (задача планировщика), и **интерактивный администратор** могут корректно запускать скрипт вручную без «Отказано в доступе» к mutex (версия **1.3.6+**).
Проверка:
```powershell
Get-ScheduledTask -TaskName 'RDP-Login-Monitor','RDP-Login-Monitor-Watchdog' -ErrorAction SilentlyContinue
schtasks /Query /TN "RDP-Login-Monitor-Watchdog"
```
Логи: **`...\Logs\login_monitor.log`**, **`...\Logs\watchdog.log`**.
## Запуск Deploy и политики с файловой шары
Если при запуске **`Deploy-LoginMonitor.ps1`** или **`Login_Monitor.ps1`** с UNC по **FQDN** (`\\dc.domain.local\...`) PowerShell сообщает про **цифровую подпись** / политику выполнения, чаще всего помогает путь по **короткому имени** контроллера: **`\\DC01\NETLOGON\...`** (клиент относит UNC к интрасети иначе). Параллельно убедитесь, что команда реально с **`powershell.exe -ExecutionPolicy Bypass -File "..."`**.
## Версии: `version.txt` и `$ScriptVersion`
| Что | Роль |
|-----|------|
| **`version.txt` на шаре** | Единственный источник для **`Deploy-LoginMonitor.ps1`**: решение «класть ли новый файл на компьютер». Поднимайте номер **всякий раз**, когда нужно, чтобы доменные машины забрали **новую копию** скрипта с шары — в том числе при мелких правках **без** изменения «видимой» версии в логах. |
| **`$ScriptVersion` в `Login_Monitor.ps1`** | Версия для **логов и Telegram** (что видит администратор). Меняйте при **значимых** релизах; для полной ясности можно держать ту же строку, что и в **`version.txt`**. |
**Типичные сценарии:**
- Крупный релиз: обновили **`Login_Monitor.ps1`**, подняли **`$ScriptVersion`** (например `1.4.0`) и записали то же в **`version.txt`** на шаре.
- Мелкая правка на шаре (опечатка, узкий фикс), не хотите путать отчёты по версии в логах: поднимите только **`version.txt`** (например с `1.3.0` на **`1.3.0.1`** — поддерживаются четырёхкомпонентные номера .NET **Version**). **`$ScriptVersion`** можно не трогать; на клиентах после деплоя в логах по-прежнему будет старая «человеческая» версия, но файл будет актуальным.
- Идеально поддерживать синхронность **`version.txt`** и **`$ScriptVersion`**, когда правки крупные и версия в логах должна совпадать с дистрибутивом.
Итого: **обновляться «по сети» обязан именно `version.txt`**; строка **`$ScriptVersion`** нужна для прозрачности в мониторинге и может совпадать с шарой или отставать по «маркетингу», если вы сознательно крутите только patch в **`version.txt`**.
## Групповая политика (GPO): проверенная схема
Ниже шаги, которые были проверены на практике для запуска деплоя при старте компьютера.
1. Положите три файла на шару (см. выше), например:
`\\B26\NETLOGON\RDP-login-monitor\`
2. Создайте/настройте GPO и привяжите её к OU с **компьютерами** (не пользователями).
3. В GPO откройте:
**Конфигурация компьютера****Политики****Конфигурация Windows****Сценарии (запуск/завершение)****Автозагрузка**.
4. На вкладке **«Сценарии PowerShell»** добавьте скрипт:
`\\B26\NETLOGON\RDP-login-monitor\Deploy-LoginMonitor.ps1`
Параметры можно оставить пустыми, если рядом на шаре лежат `Login_Monitor.ps1` и `version.txt`.
5. Security Filtering:
- можно убрать `Authenticated Users`,
- добавить группу компьютеров (например `B26\RDP-Login`),
- убедиться, что у неё есть права **Read** + **Apply group policy**.
6. Проверьте, что в группе действительно состоит объект компьютера, например `FVG-PC$`.
7. Проверьте доступ на шару/NTFS для контекста компьютера (обычно через `Domain Computers` или целевую группу), потому что startup-скрипт выполняется от имени **SYSTEM**.
### Важные нюансы
- Кнопка **«Показать файлы»** в свойствах Startup показывает папку GPO в `SYSVOL` (`...\Policies\{GUID}\Machine\Scripts\Startup`).
- Если вы указали в настройке сценария **UNC путь в NETLOGON**, ваш `.ps1` в этой папке `SYSVOL` не появится — это нормально.
- После изменения membership компьютера в security-группе часто требуется **перезагрузка** (не только `gpupdate /force`), чтобы обновился токен компьютера.
### Как запускать без ожидания перезагрузки
- Startup-сценарий GPO штатно отрабатывает при загрузке ОС, но сам `Deploy-LoginMonitor.ps1` после `-InstallTasks` теперь инициирует немедленный `schtasks /Run`:
- `RDP-Login-Monitor`
- `RDP-Login-Monitor-Watchdog`
- Поэтому после фактического запуска deploy монитор и watchdog стартуют сразу.
### Серверы без перезагрузок: периодический Deploy
Если сервер перезагружается редко, одного Startup-сценария недостаточно для своевременного обновления. В этом случае добавьте отдельную задачу, которая периодически запускает `Deploy-LoginMonitor.ps1` с шары.
Готовый скрипт в репозитории:
- `Install-DeployScheduledTask.ps1`
Пример (каждые 60 минут и сразу запустить):
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\Install-DeployScheduledTask.ps1" `
-TaskName "RDP-Login-Monitor-Deploy" `
-DeployScriptPath "\\B26\NETLOGON\RDP-login-monitor\Deploy-LoginMonitor.ps1" `
-RepeatMinutes 60 `
-RunNow
```
Проверка:
```powershell
schtasks /Query /TN "RDP-Login-Monitor-Deploy" /V /FO LIST
```
Важно: эта задача отвечает только за доставку обновлений (через `version.txt`). За «живость» процесса по-прежнему отвечает `RDP-Login-Monitor-Watchdog`.
### Диагностика GPO/Startup
- События применения политики и startup-сценариев:
- `Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> GroupPolicy -> Operational`
- Логи на клиенте:
- `C:\ProgramData\RDP-login-monitor\Logs\deploy.log`
- `C:\ProgramData\RDP-login-monitor\Logs\login_monitor.log`
- `C:\ProgramData\RDP-login-monitor\Logs\watchdog.log`
- Быстрая ручная проверка deploy:
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "\\B26\NETLOGON\RDP-login-monitor\Deploy-LoginMonitor.ps1"
```
## Ручная проверка
```powershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "\\...\Deploy-LoginMonitor.ps1"
```
- **`-WhatIf`** — только сообщение в лог, без копирования.
- **`-SkipStartMonitorAfterUpdate`** — после обновления не запускать процесс монитора (остаются задачи планировщика и следующая загрузка / watchdog).
## Безопасность и замечания
- ACL на шару: чтение только нужным **компьютерам** / группам; файл **`Login_Monitor.ps1`** может содержать токен — ограничивайте доступ.
- DPAPI-секреты привязаны к машине: шифровать на каждой цели или использовать plain на закрытой шаре (см. комментарии в **`Login_Monitor.ps1`**).
- Deploy при ошибках пишет в **`deploy.log`** и завершается с кодом **0**, чтобы не блокировать загрузку ОС; проблемы смотрите по логу на ПК.