feat: graceful restart without Stop-Process; SAC key in settings example
This commit is contained in:
+46
-2
@@ -147,8 +147,52 @@ function Test-CommandLineIsWatchdog {
|
|||||||
return ($CommandLine -match '(?i)(^|\s)-Watchdog(\s|$)')
|
return ($CommandLine -match '(?i)(^|\s)-Watchdog(\s|$)')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorMainProcessRunning {
|
||||||
|
param([string]$CanonicalScript)
|
||||||
|
try {
|
||||||
|
$procs = Get-CimInstance Win32_Process -Filter "Name = 'powershell.exe' OR Name = 'pwsh.exe'" -ErrorAction Stop
|
||||||
|
foreach ($proc in $procs) {
|
||||||
|
$cl = [string]$proc.CommandLine
|
||||||
|
if ($cl -notmatch 'Login_Monitor\.ps1') { continue }
|
||||||
|
if (Test-CommandLineIsWatchdog -CommandLine $cl) { continue }
|
||||||
|
$sp = Get-ScriptPathFromCommandLine -CommandLine $cl
|
||||||
|
if ($null -eq $sp) { continue }
|
||||||
|
if ([System.IO.Path]::GetFullPath($sp) -ne $CanonicalScript) { continue }
|
||||||
|
if ([int]$proc.ProcessId -eq $PID) { continue }
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
function Stop-RdpLoginMonitorMainProcesses {
|
function Stop-RdpLoginMonitorMainProcesses {
|
||||||
|
param([int]$GracefulWaitSec = 90)
|
||||||
|
|
||||||
$canonical = [System.IO.Path]::GetFullPath($LocalScript)
|
$canonical = [System.IO.Path]::GetFullPath($LocalScript)
|
||||||
|
if (-not (Test-RdpMonitorMainProcessRunning -CanonicalScript $canonical)) {
|
||||||
|
Write-DeployLog "Монитор не запущен — остановка не требуется."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path -LiteralPath $LocalScript) {
|
||||||
|
Write-DeployLog "Graceful recycle: Login_Monitor.ps1 -RequestRestart -Recycle (без Stop-Process)."
|
||||||
|
$recycleArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $LocalScript, '-RequestRestart', '-Recycle')
|
||||||
|
$p = Start-Process -FilePath $PsExe -ArgumentList $recycleArgs -Wait -PassThru -WindowStyle Hidden
|
||||||
|
if ($p.ExitCode -ne 0) {
|
||||||
|
Write-DeployLog "Предупреждение: -RequestRestart -Recycle завершился с кодом $($p.ExitCode)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$deadline = (Get-Date).AddSeconds($GracefulWaitSec)
|
||||||
|
while ((Get-Date) -lt $deadline) {
|
||||||
|
if (-not (Test-RdpMonitorMainProcessRunning -CanonicalScript $canonical)) {
|
||||||
|
Write-DeployLog "Монитор завершился gracefully (ожидание $($GracefulWaitSec) с)."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-DeployLog "Таймаут graceful recycle — принудительная остановка оставшихся процессов монитора."
|
||||||
try {
|
try {
|
||||||
$procs = Get-CimInstance Win32_Process -Filter "Name = 'powershell.exe' OR Name = 'pwsh.exe'" -ErrorAction Stop
|
$procs = Get-CimInstance Win32_Process -Filter "Name = 'powershell.exe' OR Name = 'pwsh.exe'" -ErrorAction Stop
|
||||||
foreach ($proc in $procs) {
|
foreach ($proc in $procs) {
|
||||||
@@ -159,11 +203,11 @@ function Stop-RdpLoginMonitorMainProcesses {
|
|||||||
if ($null -eq $sp) { continue }
|
if ($null -eq $sp) { continue }
|
||||||
if ([System.IO.Path]::GetFullPath($sp) -ne $canonical) { continue }
|
if ([System.IO.Path]::GetFullPath($sp) -ne $canonical) { continue }
|
||||||
if ([int]$proc.ProcessId -eq $PID) { continue }
|
if ([int]$proc.ProcessId -eq $PID) { continue }
|
||||||
Write-DeployLog "Останавливаю процесс монитора PID $($proc.ProcessId) перед обновлением файла."
|
Write-DeployLog "Stop-Process -Force PID $($proc.ProcessId) (fallback)."
|
||||||
Stop-Process -Id $proc.ProcessId -Force -ErrorAction SilentlyContinue
|
Stop-Process -Id $proc.ProcessId -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-DeployLog "Предупреждение при остановке монитора: $($_.Exception.Message)"
|
Write-DeployLog "Предупреждение при принудительной остановке: $($_.Exception.Message)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
- `Sac-Client.ps1`
|
- `Sac-Client.ps1`
|
||||||
- `version.txt`
|
- `version.txt`
|
||||||
- `Deploy-LoginMonitor.ps1`
|
- `Deploy-LoginMonitor.ps1`
|
||||||
|
- `Restart-RdpLoginMonitor.ps1`
|
||||||
- `Exchange-MailSecurity.ps1`
|
- `Exchange-MailSecurity.ps1`
|
||||||
- `Notify-Common.ps1`
|
- `Notify-Common.ps1`
|
||||||
- `Install-DomainMonitors.ps1`
|
- `Install-DomainMonitors.ps1`
|
||||||
|
|||||||
@@ -155,6 +155,28 @@ Get-ScheduledTask -TaskName 'RDP-Login-Monitor','RDP-Login-Monitor-Watchdog' -Er
|
|||||||
Get-Content 'C:\ProgramData\RDP-login-monitor\Logs\deploy.log' -Tail 15
|
Get-Content 'C:\ProgramData\RDP-login-monitor\Logs\deploy.log' -Tail 15
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Graceful restart (без убийства PowerShell)
|
||||||
|
|
||||||
|
После правки **`login_monitor.settings.ps1`** (SAC, Telegram):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass `
|
||||||
|
-File "C:\ProgramData\RDP-login-monitor\Login_Monitor.ps1" -RequestRestart
|
||||||
|
```
|
||||||
|
|
||||||
|
Или скрипт из репозитория/шары: **`Restart-RdpLoginMonitor.ps1`**.
|
||||||
|
|
||||||
|
Чтобы подхватить **новый `Login_Monitor.ps1` с диска** (после Deploy), нужен **recycle** — новый скрытый процесс, старый завершается сам:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass `
|
||||||
|
-File "C:\ProgramData\RDP-login-monitor\Login_Monitor.ps1" -RequestRestart -Recycle
|
||||||
|
```
|
||||||
|
|
||||||
|
**`Deploy-LoginMonitor.ps1`** при обновлении вызывает `-RequestRestart -Recycle` и ждёт до 90 с; **`Stop-Process -Force`** только если таймаут.
|
||||||
|
|
||||||
|
Сигнал: файл **`C:\ProgramData\RDP-login-monitor\restart.request`** (создаётся автоматически, не редактировать вручную).
|
||||||
|
|
||||||
### D. Первичная установка (ещё нет ProgramData)
|
### D. Первичная установка (ещё нет ProgramData)
|
||||||
|
|
||||||
1. Deploy (как в C) — создаст каталог и при отсутствии settings скопирует **`login_monitor.settings.ps1`** из example.
|
1. Deploy (как в C) — создаст каталог и при отсутствии settings скопирует **`login_monitor.settings.ps1`** из example.
|
||||||
|
|||||||
+120
-21
@@ -36,7 +36,9 @@ param(
|
|||||||
[switch]$Watchdog,
|
[switch]$Watchdog,
|
||||||
[switch]$InstallTasks,
|
[switch]$InstallTasks,
|
||||||
[switch]$SkipScheduledTaskMaintenance,
|
[switch]$SkipScheduledTaskMaintenance,
|
||||||
[switch]$CheckSac
|
[switch]$CheckSac,
|
||||||
|
[switch]$RequestRestart,
|
||||||
|
[switch]$Recycle
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@@ -69,13 +71,16 @@ $script:ScheduledTaskNameMain = "RDP-Login-Monitor"
|
|||||||
$script:ScheduledTaskNameWatchdog = "RDP-Login-Monitor-Watchdog"
|
$script:ScheduledTaskNameWatchdog = "RDP-Login-Monitor-Watchdog"
|
||||||
# Один экземпляр: эксклюзивная блокировка файла в InstallRoot (SYSTEM и интерактивный админ — одинаково; Global mutex давал «Отказано в доступе» между контекстами).
|
# Один экземпляр: эксклюзивная блокировка файла в InstallRoot (SYSTEM и интерактивный админ — одинаково; Global mutex давал «Отказано в доступе» между контекстами).
|
||||||
$script:MonitorSingletonLockStream = $null
|
$script:MonitorSingletonLockStream = $null
|
||||||
|
$script:MonitorRestartRequestFile = Join-Path $script:InstallRoot 'restart.request'
|
||||||
|
$script:MonitorRecycleRequested = $false
|
||||||
|
$script:MonitorLoopInitialized = $false
|
||||||
|
|
||||||
# Версия: пишется в лог и в Telegram. При доменном развёртывании через шару см. DEPLOY.md —
|
# Версия: пишется в лог и в Telegram. При доменном развёртывании через шару см. DEPLOY.md —
|
||||||
# триггер обновления на клиентах даёт файл version.txt на шаре (его номер можно поднять и без смены
|
# триггер обновления на клиентах даёт файл version.txt на шаре (его номер можно поднять и без смены
|
||||||
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
||||||
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
||||||
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
||||||
$ScriptVersion = "1.2.0-SAC"
|
$ScriptVersion = "1.2.1-SAC"
|
||||||
|
|
||||||
# Логи (все под InstallRoot)
|
# Логи (все под InstallRoot)
|
||||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||||
@@ -385,6 +390,59 @@ function Get-RdpMonitorPowerShellExe {
|
|||||||
return "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
return "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Set-RdpMonitorRestartRequest {
|
||||||
|
param(
|
||||||
|
[ValidateSet('settings', 'recycle')]
|
||||||
|
[string]$Mode = 'settings',
|
||||||
|
[string]$Reason = 'manual'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $script:InstallRoot)) {
|
||||||
|
New-Item -ItemType Directory -Path $script:InstallRoot -Force | Out-Null
|
||||||
|
}
|
||||||
|
$lines = @(
|
||||||
|
"mode=$Mode"
|
||||||
|
"reason=$Reason"
|
||||||
|
"requested_at=$((Get-Date).ToString('o'))"
|
||||||
|
)
|
||||||
|
Write-TextFileUtf8Bom -Path $script:MonitorRestartRequestFile -Text (($lines -join "`r`n") + "`r`n")
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorRestartRequest {
|
||||||
|
if (-not (Test-Path -LiteralPath $script:MonitorRestartRequestFile)) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
$mode = 'settings'
|
||||||
|
$reason = ''
|
||||||
|
try {
|
||||||
|
foreach ($ln in (Get-Content -LiteralPath $script:MonitorRestartRequestFile -ErrorAction Stop)) {
|
||||||
|
if ($ln -match '^\s*mode\s*=\s*(.+)\s*$') { $mode = $Matches[1].Trim().ToLowerInvariant() }
|
||||||
|
if ($ln -match '^\s*reason\s*=\s*(.+)\s*$') { $reason = $Matches[1].Trim() }
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
try {
|
||||||
|
Remove-Item -LiteralPath $script:MonitorRestartRequestFile -Force -ErrorAction SilentlyContinue
|
||||||
|
} catch { }
|
||||||
|
if ($mode -ne 'recycle') { $mode = 'settings' }
|
||||||
|
return [pscustomobject]@{ Mode = $mode; Reason = $reason }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-RdpMonitorReloadSettings {
|
||||||
|
if (-not (Test-Path -LiteralPath $script:LoginMonitorSettingsFile)) {
|
||||||
|
Write-Log "Graceful restart: login_monitor.settings.ps1 не найден, настройки не перечитаны."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
. $script:LoginMonitorSettingsFile
|
||||||
|
$script:LoginMonitorSettingsLoaded = $true
|
||||||
|
Write-Log "Graceful restart: login_monitor.settings.ps1 перечитан (каналы: $(Get-NotifyChainHuman))."
|
||||||
|
return $true
|
||||||
|
} catch {
|
||||||
|
Write-Log "Graceful restart: ошибка чтения settings: $($_.Exception.Message)"
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Test-RdpMonitorScheduledTaskMatches {
|
function Test-RdpMonitorScheduledTaskMatches {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$TaskName,
|
[Parameter(Mandatory = $true)][string]$TaskName,
|
||||||
@@ -865,6 +923,13 @@ if ($CheckSac) {
|
|||||||
exit $code
|
exit $code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($RequestRestart) {
|
||||||
|
$restartMode = if ($Recycle) { 'recycle' } else { 'settings' }
|
||||||
|
Set-RdpMonitorRestartRequest -Mode $restartMode -Reason 'RequestRestart'
|
||||||
|
Write-Log "Запрошен graceful restart (mode=$restartMode, файл restart.request). Активный монитор обработает запрос без Stop-Process."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-RdpMonitorProcessMigrationAndRelaunch
|
Invoke-RdpMonitorProcessMigrationAndRelaunch
|
||||||
Lock-RdpMonitorSingleInstance
|
Lock-RdpMonitorSingleInstance
|
||||||
Ensure-RdpMonitorScheduledTasks
|
Ensure-RdpMonitorScheduledTasks
|
||||||
@@ -2487,28 +2552,47 @@ function Start-LoginMonitor {
|
|||||||
$script:MonitorStartedAt = Get-Date
|
$script:MonitorStartedAt = Get-Date
|
||||||
$script:HeartbeatStaleAlertActive = $false
|
$script:HeartbeatStaleAlertActive = $false
|
||||||
|
|
||||||
Cleanup-OldLogs
|
do {
|
||||||
Send-Heartbeat -IsStartup
|
$script:MonitorRecycleRequested = $false
|
||||||
Enable-SecurityAudit
|
|
||||||
|
|
||||||
$rdGatewayAvailable = $false
|
if (-not $script:MonitorLoopInitialized) {
|
||||||
if ($EnableRDGatewayMonitoring) { $rdGatewayAvailable = Test-RDGatewayLog }
|
Cleanup-OldLogs
|
||||||
|
Send-Heartbeat -IsStartup
|
||||||
|
Enable-SecurityAudit
|
||||||
|
$script:MonitorLoopInitialized = $true
|
||||||
|
}
|
||||||
|
|
||||||
$rcmMonitoringEnabled = ($osKind.IsWorkstation -and (Test-RcmLogAvailable))
|
$rdGatewayAvailable = $false
|
||||||
if ($osKind.IsWorkstation -and -not $rcmMonitoringEnabled) {
|
if ($EnableRDGatewayMonitoring) { $rdGatewayAvailable = Test-RDGatewayLog }
|
||||||
Write-Log "Рабочая станция: журнал Remote Connection Manager недоступен — уведомления только по Security 4624/4625 (LogonType 10). Проверьте, что включён удалённый рабочий стол."
|
|
||||||
}
|
|
||||||
|
|
||||||
$nextHeartbeatTime = (Get-Date).AddSeconds($HeartbeatInterval)
|
$rcmMonitoringEnabled = ($osKind.IsWorkstation -and (Test-RcmLogAvailable))
|
||||||
$nextRotationCheck = Check-AndRotateLog
|
if ($osKind.IsWorkstation -and -not $rcmMonitoringEnabled) {
|
||||||
$nextReportCheck = Check-AndSendDailyReport
|
Write-Log "Рабочая станция: журнал Remote Connection Manager недоступен — уведомления только по Security 4624/4625 (LogonType 10). Проверьте, что включён удалённый рабочий стол."
|
||||||
$lastCheckTime = (Get-Date).AddSeconds(-10)
|
}
|
||||||
$lastGatewayCheckTime = (Get-Date).AddSeconds(-10)
|
|
||||||
$lastRcmCheckTime = (Get-Date).AddSeconds(-10)
|
$nextHeartbeatTime = (Get-Date).AddSeconds($HeartbeatInterval)
|
||||||
$lastLockout4740CheckTime = (Get-Date).AddSeconds(-10)
|
$nextRotationCheck = Check-AndRotateLog
|
||||||
$monitorEvents = @(4624, 4625, 4648)
|
$nextReportCheck = Check-AndSendDailyReport
|
||||||
|
$lastCheckTime = (Get-Date).AddSeconds(-10)
|
||||||
|
$lastGatewayCheckTime = (Get-Date).AddSeconds(-10)
|
||||||
|
$lastRcmCheckTime = (Get-Date).AddSeconds(-10)
|
||||||
|
$lastLockout4740CheckTime = (Get-Date).AddSeconds(-10)
|
||||||
|
$monitorEvents = @(4624, 4625, 4648)
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
$restartReq = Get-RdpMonitorRestartRequest
|
||||||
|
if ($null -ne $restartReq) {
|
||||||
|
$script:StopNotificationSent = $true
|
||||||
|
if ($restartReq.Mode -eq 'recycle') {
|
||||||
|
Write-Log "Graceful recycle: запрос '$($restartReq.Reason)' — выход для запуска нового процесса (обновлённый скрипт с диска)."
|
||||||
|
$script:MonitorRecycleRequested = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Write-Log "Graceful restart (settings): запрос '$($restartReq.Reason)' — перечитываю настройки в этом же процессе PowerShell."
|
||||||
|
Invoke-RdpMonitorReloadSettings | Out-Null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
while ($true) {
|
|
||||||
try {
|
try {
|
||||||
# ignore.lst: сверка mtime и лог при изменении файла.
|
# ignore.lst: сверка mtime и лог при изменении файла.
|
||||||
[void](Get-RdpMonitorIgnoreListEntries)
|
[void](Get-RdpMonitorIgnoreListEntries)
|
||||||
@@ -2761,7 +2845,12 @@ function Start-LoginMonitor {
|
|||||||
Write-Log "Ошибка цикла мониторинга: $($_.Exception.Message)"
|
Write-Log "Ошибка цикла мониторинга: $($_.Exception.Message)"
|
||||||
}
|
}
|
||||||
Start-Sleep -Seconds $MonitorInterval
|
Start-Sleep -Seconds $MonitorInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($script:MonitorRecycleRequested) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} while ($true)
|
||||||
}
|
}
|
||||||
|
|
||||||
$script:StopNotificationSent = $false
|
$script:StopNotificationSent = $false
|
||||||
@@ -2792,6 +2881,16 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Start-LoginMonitor -MonitorInterval 5 -MonitorInteractiveOnly
|
Start-LoginMonitor -MonitorInterval 5 -MonitorInteractiveOnly
|
||||||
|
|
||||||
|
if ($script:MonitorRecycleRequested) {
|
||||||
|
$script:StopNotificationSent = $true
|
||||||
|
$canonicalScript = Join-Path $script:InstallRoot $script:CanonicalScriptName
|
||||||
|
Write-Log "Graceful recycle: запуск нового процесса монитора ($canonicalScript)."
|
||||||
|
Start-Process -FilePath (Get-RdpMonitorPowerShellExe) -ArgumentList @(
|
||||||
|
'-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $canonicalScript
|
||||||
|
) -WindowStyle Hidden | Out-Null
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
if ($_.Exception -is [System.Management.Automation.PipelineStoppedException]) {
|
if ($_.Exception -is [System.Management.Automation.PipelineStoppedException]) {
|
||||||
Write-Log "Выполнение прервано (Ctrl+C / Stop-Pipeline)."
|
Write-Log "Выполнение прервано (Ctrl+C / Stop-Pipeline)."
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Graceful restart RDP Login Monitor без Stop-Process.
|
||||||
|
.DESCRIPTION
|
||||||
|
settings — перечитать login_monitor.settings.ps1 в том же процессе PowerShell.
|
||||||
|
recycle — корректно завершить монитор и запустить новый процесс (после обновления Login_Monitor.ps1).
|
||||||
|
.EXAMPLE
|
||||||
|
powershell -ExecutionPolicy Bypass -File Restart-RdpLoginMonitor.ps1
|
||||||
|
powershell -ExecutionPolicy Bypass -File Restart-RdpLoginMonitor.ps1 -Recycle
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[switch]$Recycle
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$installRoot = [System.IO.Path]::GetFullPath("$env:ProgramData\RDP-login-monitor")
|
||||||
|
$monitorScript = Join-Path $installRoot 'Login_Monitor.ps1'
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $monitorScript)) {
|
||||||
|
Write-Error "Не найден: $monitorScript"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $monitorScript, '-RequestRestart')
|
||||||
|
if ($Recycle) { $args += '-Recycle' }
|
||||||
|
|
||||||
|
& "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" @args
|
||||||
|
exit $LASTEXITCODE
|
||||||
@@ -29,9 +29,9 @@ $NotifyOrder = 'tg'
|
|||||||
|
|
||||||
# --- Security Alert Center (SAC) ---
|
# --- Security Alert Center (SAC) ---
|
||||||
# off | exclusive | dual | fallback — см. security-alert-center/docs/agent-integration.md
|
# off | exclusive | dual | fallback — см. security-alert-center/docs/agent-integration.md
|
||||||
# $UseSAC = 'exclusive'
|
$UseSAC = 'dual'
|
||||||
# $SacUrl = 'https://sac.kalinamall.ru'
|
$SacUrl = 'https://sac.kalinamall.ru'
|
||||||
# $SacApiKey = 'sac_xxxxxxxx'
|
$SacApiKey = 'sac_UkOsAT3UWiQS54KK5OJPBDCSucysQDrKFju28wmYiz8'
|
||||||
# $SacSpoolDir = 'C:\ProgramData\RDP-login-monitor\sac-spool'
|
# $SacSpoolDir = 'C:\ProgramData\RDP-login-monitor\sac-spool'
|
||||||
# $SacTimeoutSec = 12
|
# $SacTimeoutSec = 12
|
||||||
# $SacTlsSkipVerify = $false
|
# $SacTlsSkipVerify = $false
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ $DistFiles = @(
|
|||||||
'Sac-Client.ps1',
|
'Sac-Client.ps1',
|
||||||
'version.txt',
|
'version.txt',
|
||||||
'Deploy-LoginMonitor.ps1',
|
'Deploy-LoginMonitor.ps1',
|
||||||
|
'Restart-RdpLoginMonitor.ps1',
|
||||||
'Exchange-MailSecurity.ps1',
|
'Exchange-MailSecurity.ps1',
|
||||||
'Notify-Common.ps1',
|
'Notify-Common.ps1',
|
||||||
'Install-DomainMonitors.ps1',
|
'Install-DomainMonitors.ps1',
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.2.0-SAC
|
1.2.1-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user