fix: deploy syncs Sac-Client bundle, SAC dual settings, and ServerDisplayName hint (1.2.20-SAC)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+184
-31
@@ -9,6 +9,8 @@
|
||||
|
||||
СТРУКТУРА НА ШАРЕ (пример):
|
||||
\\dc\share\RDP-login-monitor\Login_Monitor.ps1
|
||||
\\dc\share\RDP-login-monitor\Sac-Client.ps1 — обязателен для SAC
|
||||
\\dc\share\RDP-login-monitor\login_monitor.settings.example.ps1
|
||||
\\dc\share\RDP-login-monitor\version.txt — одна строка, например: 1.3.0
|
||||
\\dc\share\RDP-login-monitor\Deploy-LoginMonitor.ps1
|
||||
|
||||
@@ -51,7 +53,9 @@ $VersionStampPath = Join-Path $InstallRoot "deployed_version.txt"
|
||||
$DeployUpdateMarkerPath = Join-Path $InstallRoot "deploy_last_update.txt"
|
||||
$DeployLogPath = Join-Path $InstallRoot "Logs\deploy.log"
|
||||
$ScriptName = "Login_Monitor.ps1"
|
||||
$SacClientName = "Sac-Client.ps1"
|
||||
$VersionFileName = "version.txt"
|
||||
$DeployBundleFiles = @($ScriptName, $SacClientName)
|
||||
$PsExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
|
||||
$Utf8Bom = New-Object System.Text.UTF8Encoding $true
|
||||
@@ -194,13 +198,49 @@ function Get-RdpMonitorSettingsRaw {
|
||||
}
|
||||
}
|
||||
|
||||
function Test-RdpMonitorSettingsNeedsSacBootstrap {
|
||||
param(
|
||||
[string]$SettingsPath,
|
||||
[string]$SacClientPath
|
||||
)
|
||||
if (-not (Test-Path -LiteralPath $SacClientPath)) { return $true }
|
||||
function Get-DeployFileSha256 {
|
||||
param([string]$Path)
|
||||
if (-not (Test-Path -LiteralPath $Path)) { return $null }
|
||||
return (Get-FileHash -LiteralPath $Path -Algorithm SHA256 -ErrorAction Stop).Hash
|
||||
}
|
||||
|
||||
function Test-RdpMonitorDeployBundleNeedsSync {
|
||||
param([string]$ShareRoot)
|
||||
foreach ($rel in $DeployBundleFiles) {
|
||||
$src = Join-Path $ShareRoot $rel
|
||||
if (-not (Test-Path -LiteralPath $src)) {
|
||||
if ($rel -eq $SacClientName) {
|
||||
Write-DeployLog "ОШИБКА: на шаре нет обязательного $SacClientName — опубликуйте пакет (update-rdp-monitor.ps1)."
|
||||
}
|
||||
continue
|
||||
}
|
||||
$dst = Join-Path $InstallRoot $rel
|
||||
if (-not (Test-Path -LiteralPath $dst)) { return $true }
|
||||
$hs = Get-DeployFileSha256 -Path $src
|
||||
$hd = Get-DeployFileSha256 -Path $dst
|
||||
if ($hs -ne $hd) { return $true }
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function Copy-RdpMonitorDeployBundle {
|
||||
param([string]$ShareRoot)
|
||||
foreach ($rel in $DeployBundleFiles) {
|
||||
$src = Join-Path $ShareRoot $rel
|
||||
$dst = Join-Path $InstallRoot $rel
|
||||
if (-not (Test-Path -LiteralPath $src)) {
|
||||
if ($rel -eq $SacClientName) {
|
||||
Write-DeployLog "Предупреждение: на шаре нет $SacClientName — SAC недоступен до публикации файла на шару."
|
||||
}
|
||||
continue
|
||||
}
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
Write-DeployLog "Файл скопирован: $dst"
|
||||
}
|
||||
}
|
||||
|
||||
function Test-RdpMonitorSettingsNeedsSacBootstrap {
|
||||
param([string]$SettingsPath)
|
||||
$c = Get-RdpMonitorSettingsRaw -Path $SettingsPath
|
||||
if ([string]::IsNullOrWhiteSpace($c)) { return $true }
|
||||
|
||||
@@ -210,10 +250,112 @@ function Test-RdpMonitorSettingsNeedsSacBootstrap {
|
||||
}
|
||||
if ($c -match '(?m)^\s*\$SacApiKey\s*=\s*[''"]\s*[''"]') { return $true }
|
||||
if ($c -notmatch '(?m)^\s*\$SacApiKey\s*=\s*[''"]sac_[^''"]+[''"]') { return $true }
|
||||
if ($c -notmatch '(?m)^\s*\$SacUrl\s*=\s*[''"]https?://[^''"]+[''"]') { return $true }
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-RdpMonitorSettingsNeedsServerDisplayNameHint {
|
||||
param([string]$SettingsPath)
|
||||
if (-not (Test-Path -LiteralPath $SettingsPath)) { return $false }
|
||||
$c = Get-RdpMonitorSettingsRaw -Path $SettingsPath
|
||||
if ([string]::IsNullOrWhiteSpace($c)) { return $false }
|
||||
if ($c -match '(?m)^\s*(\#\s*)?\$ServerDisplayName\s*=') { return $false }
|
||||
return $true
|
||||
}
|
||||
|
||||
function Update-RdpMonitorSettingsServerDisplayNameHintIfMissing {
|
||||
param([string]$LocalSettings)
|
||||
if (-not (Test-Path -LiteralPath $LocalSettings)) { return $false }
|
||||
if (-not (Test-RdpMonitorSettingsNeedsServerDisplayNameHint -SettingsPath $LocalSettings)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$c = Get-RdpMonitorSettingsRaw -Path $LocalSettings
|
||||
if ([string]::IsNullOrWhiteSpace($c)) { return $false }
|
||||
|
||||
$hostLabel = if ([string]::IsNullOrWhiteSpace($env:COMPUTERNAME)) { 'New-PC' } else { $env:COMPUTERNAME.Trim() }
|
||||
$hintBlock = @(
|
||||
'# --- Подпись сервера в Telegram и SAC (host.display_name); раскомментируйте при необходимости ---'
|
||||
"# `$ServerDisplayName = '$hostLabel'"
|
||||
'# --- Явный IPv4 хоста для SAC (опционально; иначе автоопределение) ---'
|
||||
'# $ServerIPv4 = '''
|
||||
) -join "`r`n"
|
||||
|
||||
$bak = "$LocalSettings.bak.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||
Copy-Item -LiteralPath $LocalSettings -Destination $bak -Force
|
||||
Write-DeployLog "Добавление закомментированного `$ServerDisplayName в login_monitor.settings.ps1; резервная копия: $bak"
|
||||
|
||||
$insertBefore = '(?m)^\s*#\s*---\s*Security Alert Center'
|
||||
if ($c -match $insertBefore) {
|
||||
$newContent = [regex]::Replace($c, $insertBefore, ($hintBlock + "`r`n`r`n" + '$0'), 1)
|
||||
} else {
|
||||
$newContent = ($c.TrimEnd() + "`r`n`r`n" + $hintBlock + "`r`n")
|
||||
}
|
||||
[System.IO.File]::WriteAllText($LocalSettings, $newContent.TrimEnd() + "`r`n", $Utf8Bom)
|
||||
Write-DeployLog "login_monitor.settings.ps1: добавлена подсказка # `$ServerDisplayName = '$hostLabel'"
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-RdpMonitorSacBlockFromExample {
|
||||
param([string]$ExamplePath)
|
||||
if (-not (Test-Path -LiteralPath $ExamplePath)) { return $null }
|
||||
$ex = Get-RdpMonitorSettingsRaw -Path $ExamplePath
|
||||
if ([string]::IsNullOrWhiteSpace($ex)) { return $null }
|
||||
if ($ex -match '(?ms)(#\s*---\s*Security Alert Center.*?)(?=\r?\n#\s*---|\z)') {
|
||||
return $Matches[1].TrimEnd()
|
||||
}
|
||||
return @(
|
||||
'# --- Security Alert Center (SAC) ---'
|
||||
'$UseSAC = ''dual'''
|
||||
'$SacUrl = ''https://sac.kalinamall.ru'''
|
||||
'$SacApiKey = ''sac_CHANGE_ME'''
|
||||
) -join "`r`n"
|
||||
}
|
||||
|
||||
function Update-RdpMonitorSettingsSacBlockIfMissing {
|
||||
param(
|
||||
[string]$LocalSettings,
|
||||
[string]$ExampleOnShare
|
||||
)
|
||||
if (-not (Test-Path -LiteralPath $LocalSettings)) { return $false }
|
||||
|
||||
$c = Get-RdpMonitorSettingsRaw -Path $LocalSettings
|
||||
if ([string]::IsNullOrWhiteSpace($c)) { return $false }
|
||||
|
||||
if ($c -match '(?m)^\s*\$UseSAC\s*=' -and $c -match '(?m)^\s*\$SacApiKey\s*=\s*[''"]sac_[^''"]+[''"]') {
|
||||
if ($c -notmatch '(?m)^\s*\$UseSAC\s*=\s*[''"]off[''"]') {
|
||||
Write-DeployLog "login_monitor.settings.ps1: блок SAC уже задан, файл не меняем."
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
$sacBlock = Get-RdpMonitorSacBlockFromExample -ExamplePath $ExampleOnShare
|
||||
if ([string]::IsNullOrWhiteSpace($sacBlock)) {
|
||||
Write-DeployLog "Предупреждение: не удалось извлечь блок SAC из example — пропуск patch settings."
|
||||
return $false
|
||||
}
|
||||
|
||||
$bak = "$LocalSettings.bak.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||
Copy-Item -LiteralPath $LocalSettings -Destination $bak -Force
|
||||
Write-DeployLog "Добавление блока SAC (UseSAC=dual) в login_monitor.settings.ps1; резервная копия: $bak"
|
||||
|
||||
if ($c -match '(?m)^\s*\$UseSAC\s*=') {
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$UseSAC\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacUrl\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacApiKey\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacSpoolDir\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacTimeoutSec\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacTlsSkipVerify\s*=.*$', '')
|
||||
$c = [regex]::Replace($c, '(?m)^\s*\$SacFallbackFailures\s*=.*$', '')
|
||||
}
|
||||
|
||||
$newContent = ($c.TrimEnd() + "`r`n`r`n" + $sacBlock + "`r`n").TrimEnd() + "`r`n"
|
||||
[System.IO.File]::WriteAllText($LocalSettings, $newContent, $Utf8Bom)
|
||||
Write-DeployLog "login_monitor.settings.ps1: добавлен блок SAC (UseSAC=dual из example на шаре)."
|
||||
return $true
|
||||
}
|
||||
|
||||
function Sync-RdpMonitorSettingsFromShare {
|
||||
param(
|
||||
[string]$ExampleOnShare,
|
||||
@@ -224,12 +366,12 @@ function Sync-RdpMonitorSettingsFromShare {
|
||||
return
|
||||
}
|
||||
|
||||
$localSac = Join-Path $InstallRoot 'Sac-Client.ps1'
|
||||
$needsCreate = -not (Test-Path -LiteralPath $LocalSettings)
|
||||
$needsBootstrap = $needsCreate -or (Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $LocalSettings -SacClientPath $localSac)
|
||||
$needsBootstrap = $needsCreate -or (Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $LocalSettings)
|
||||
|
||||
if (-not $needsBootstrap) {
|
||||
Write-DeployLog "login_monitor.settings.ps1: SAC уже настроен, файл не перезаписываем."
|
||||
Update-RdpMonitorSettingsServerDisplayNameHintIfMissing -LocalSettings $LocalSettings | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
@@ -239,13 +381,21 @@ function Sync-RdpMonitorSettingsFromShare {
|
||||
|
||||
if ($needsCreate) {
|
||||
Write-DeployLog "Создан login_monitor.settings.ps1 из example (Telegram + SAC dual)."
|
||||
} else {
|
||||
$bak = "$LocalSettings.bak.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||
Copy-Item -LiteralPath $LocalSettings -Destination $bak -Force
|
||||
Write-DeployLog "Апгрейд с версии без SAC: резервная копия $bak, применяем example с шары."
|
||||
Copy-Item -LiteralPath $ExampleOnShare -Destination $LocalSettings -Force
|
||||
Update-RdpMonitorSettingsServerDisplayNameHintIfMissing -LocalSettings $LocalSettings | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
if (Update-RdpMonitorSettingsSacBlockIfMissing -LocalSettings $LocalSettings -ExampleOnShare $ExampleOnShare) {
|
||||
Update-RdpMonitorSettingsServerDisplayNameHintIfMissing -LocalSettings $LocalSettings | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
$bak = "$LocalSettings.bak.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||
Copy-Item -LiteralPath $LocalSettings -Destination $bak -Force
|
||||
Write-DeployLog "Апгрейд settings: резервная копия $bak, применяем example с шары."
|
||||
Copy-Item -LiteralPath $ExampleOnShare -Destination $LocalSettings -Force
|
||||
Update-RdpMonitorSettingsServerDisplayNameHintIfMissing -LocalSettings $LocalSettings | Out-Null
|
||||
}
|
||||
|
||||
function Stop-RdpLoginMonitorMainProcesses {
|
||||
@@ -317,10 +467,14 @@ try {
|
||||
$localVerRaw = Get-LocalDeployedVersion
|
||||
Write-DeployLog "Версия на шаре: $shareVerRaw; локально установлено: $(if ($localVerRaw) { $localVerRaw } else { '(нет)' })."
|
||||
|
||||
$localSacPath = Join-Path $InstallRoot 'Sac-Client.ps1'
|
||||
$sourceSacOnShare = Join-Path $shareRoot 'Sac-Client.ps1'
|
||||
$needsSacBootstrap = (Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $settingsLocal -SacClientPath $localSacPath) `
|
||||
-or ((-not (Test-Path -LiteralPath $localSacPath)) -and (Test-Path -LiteralPath $sourceSacOnShare))
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $shareRoot $SacClientName))) {
|
||||
Write-DeployLog "ОШИБКА: на шаре отсутствует $SacClientName — выполните update-rdp-monitor.ps1 на сервере публикации."
|
||||
}
|
||||
|
||||
$needsSettingsBootstrap = Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $settingsLocal
|
||||
$needsDisplayNameHint = Test-RdpMonitorSettingsNeedsServerDisplayNameHint -SettingsPath $settingsLocal
|
||||
$needsBundleSync = Test-RdpMonitorDeployBundleNeedsSync -ShareRoot $shareRoot
|
||||
$needsSacBootstrap = $needsSettingsBootstrap -or $needsBundleSync -or $needsDisplayNameHint
|
||||
|
||||
$cmp = Compare-VersionStrings -Left $shareVerRaw -Right $localVerRaw
|
||||
if ($null -ne $cmp) {
|
||||
@@ -329,7 +483,13 @@ try {
|
||||
Write-DeployLog "Актуально, копирование не требуется."
|
||||
exit 0
|
||||
}
|
||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но нужна донастройка SAC — продолжаем деплой."
|
||||
if ($needsBundleSync) {
|
||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но пакет файлов (Login_Monitor/Sac-Client) отличается — продолжаем деплой."
|
||||
} elseif ($needsSettingsBootstrap) {
|
||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но нужна донастройка SAC в settings — продолжаем деплой."
|
||||
} elseif ($needsDisplayNameHint) {
|
||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но нет подсказки `$ServerDisplayName в settings — продолжаем деплой."
|
||||
}
|
||||
}
|
||||
if ($cmp -lt 0 -and -not $AllowDowngrade) {
|
||||
Write-DeployLog "На шаре версия старше локальной — пропуск (используйте -AllowDowngrade для отката)."
|
||||
@@ -346,10 +506,13 @@ try {
|
||||
}
|
||||
|
||||
if ($WhatIf) {
|
||||
if ($needsSacBootstrap) {
|
||||
Write-DeployLog "[WhatIf] Применить login_monitor.settings.ps1 из example (SAC/Telegram)."
|
||||
if ($needsSettingsBootstrap) {
|
||||
Write-DeployLog "[WhatIf] Донастроить login_monitor.settings.ps1 (SAC dual из example)."
|
||||
}
|
||||
Write-DeployLog "[WhatIf] Скопировать $sourceScript -> $LocalScript; InstallTasks; версия $shareVerRaw"
|
||||
if ($needsBundleSync) {
|
||||
Write-DeployLog "[WhatIf] Синхронизировать пакет: $($DeployBundleFiles -join ', ')."
|
||||
}
|
||||
Write-DeployLog "[WhatIf] InstallTasks; версия $shareVerRaw"
|
||||
exit 0
|
||||
}
|
||||
|
||||
@@ -360,17 +523,7 @@ try {
|
||||
|
||||
Stop-RdpLoginMonitorMainProcesses
|
||||
|
||||
Copy-Item -LiteralPath $sourceScript -Destination $LocalScript -Force
|
||||
Write-DeployLog "Файл скопирован: $LocalScript"
|
||||
|
||||
$sourceSac = Join-Path $shareRoot 'Sac-Client.ps1'
|
||||
$localSac = Join-Path $InstallRoot 'Sac-Client.ps1'
|
||||
if (Test-Path -LiteralPath $sourceSac) {
|
||||
Copy-Item -LiteralPath $sourceSac -Destination $localSac -Force
|
||||
Write-DeployLog "Файл скопирован: $localSac"
|
||||
} else {
|
||||
Write-DeployLog "Предупреждение: на шаре нет Sac-Client.ps1 — SAC будет недоступен до следующего деплоя."
|
||||
}
|
||||
Copy-RdpMonitorDeployBundle -ShareRoot $shareRoot
|
||||
|
||||
Sync-RdpMonitorSettingsFromShare -ExampleOnShare $settingsExampleShare -LocalSettings $settingsLocal
|
||||
|
||||
|
||||
@@ -30,9 +30,11 @@
|
||||
|
||||
2. Читается **`version.txt`** на шаре и сравнивается с локальной меткой **`deployed_version.txt`**. Если метки нет — подтягивается **`$ScriptVersion`** из установленного **`Login_Monitor.ps1`**.
|
||||
|
||||
3. Версия на шаре **совпадает** с локальной — выход без копирования.
|
||||
3. Версия на шаре **совпадает** с локальной — выход **без копирования**, **кроме** случаев:
|
||||
- на ПК **нет** `Sac-Client.ps1` или его SHA256 **отличается** от шары;
|
||||
- в `login_monitor.settings.ps1` **нет** блока SAC (`$UseSAC`, `$SacUrl`, `$SacApiKey`) — тогда добавляется **`UseSAC = 'dual'`** из example (без перезаписи Telegram, если возможно).
|
||||
|
||||
4. Версия на шаре **новее** — остановка процессов монитора → копирование **`Login_Monitor.ps1`** и **`Sac-Client.ps1`** → **`Login_Monitor.ps1 -InstallTasks`** → **`deployed_version.txt`** → запуск монитора (если не **`-SkipStartMonitorAfterUpdate`**).
|
||||
4. Версия на шаре **новее** (или сработало условие выше) — остановка процессов → копирование **`Login_Monitor.ps1`** и **`Sac-Client.ps1`** → настройка SAC в settings при необходимости → **`Login_Monitor.ps1 -InstallTasks`** → **`deployed_version.txt`** → запуск монитора.
|
||||
|
||||
5. Версия на шаре **старее** — откат блокируется, пока не указан **`-AllowDowngrade`**.
|
||||
|
||||
@@ -44,8 +46,9 @@
|
||||
|
||||
- Секреты и параметры сайта (Telegram, SMTP, **4740**, `$IgnoreAdvapiNetworkLogonSourceIps`) — **только** в этом файле.
|
||||
- Образец в репозитории и на шаре: **`login_monitor.settings.example.ps1`**.
|
||||
- **`Deploy-LoginMonitor.ps1`** **не перезаписывает** `login_monitor.settings.ps1` при обновлении скрипта.
|
||||
- Если файла нет, Deploy **один раз** копирует example → settings (дальше правки только локально).
|
||||
- **`Deploy-LoginMonitor.ps1`** **не перезаписывает** существующий `login_monitor.settings.ps1`, если SAC уже настроен (`UseSAC` не `off`, заданы `$SacUrl` и `$SacApiKey`).
|
||||
- Если файла нет — Deploy **один раз** копирует example → settings (**`UseSAC = 'dual'`**).
|
||||
- Если файл есть, но **нет блока SAC** — Deploy **дописывает** блок из example (Telegram/SMTP не трогает).
|
||||
|
||||
```powershell
|
||||
$root = 'C:\ProgramData\RDP-login-monitor'
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ $script:MonitorLoopInitialized = $false
|
||||
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
||||
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
||||
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
||||
$ScriptVersion = "1.2.18-SAC"
|
||||
$ScriptVersion = "1.2.20-SAC"
|
||||
|
||||
# Логи (все под InstallRoot)
|
||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
$errs = $null
|
||||
[void][System.Management.Automation.Language.Parser]::ParseFile(
|
||||
(Join-Path $PSScriptRoot '..\Deploy-LoginMonitor.ps1'),
|
||||
[ref]$null,
|
||||
[ref]$errs
|
||||
)
|
||||
if ($errs) { $errs | ForEach-Object { $_.ToString() }; exit 1 }
|
||||
Write-Output 'OK'
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.2.18-SAC
|
||||
1.2.20-SAC
|
||||
|
||||
Reference in New Issue
Block a user