fix: RDP-Login-Monitor scheduled task unlimited ExecutionTimeLimit (2.0.24-SAC)
Default PT72H caused Task Scheduler to stop the monitor after 72 hours. Register main task with PT0S, re-register on deploy and Ensure when limit is set. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+43
-1
@@ -929,6 +929,42 @@ function Stop-RdpLoginMonitorMainProcesses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime {
|
||||||
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
|
try {
|
||||||
|
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
||||||
|
if ($null -eq $limit) { return $true }
|
||||||
|
if ($limit.Ticks -le 0) { return $false }
|
||||||
|
if ($limit.TotalDays -ge 999) { return $false }
|
||||||
|
return $true
|
||||||
|
} catch {
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel {
|
||||||
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
|
try {
|
||||||
|
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
||||||
|
if ($null -eq $limit) { return '(null)' }
|
||||||
|
if ($limit.Ticks -le 0) { return 'PT0S (без лимита)' }
|
||||||
|
return $limit.ToString()
|
||||||
|
} catch {
|
||||||
|
return '(задача не найдена)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-RdpMonitorDeployScheduledTaskVerification {
|
||||||
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
|
if (Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime -TaskName $TaskName) {
|
||||||
|
$label = Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel -TaskName $TaskName
|
||||||
|
Write-DeployLog "ПРЕДУПРЕЖДЕНИЕ: $TaskName ExecutionTimeLimit=$label — ожидался PT0S (без лимита). Проверьте InstallTasks и права администратора."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
Write-DeployLog "Задача $TaskName: ExecutionTimeLimit=PT0S (без лимита) — OK."
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
# --- main ---
|
# --- main ---
|
||||||
try {
|
try {
|
||||||
$shareRoot = Resolve-SourceShareRoot
|
$shareRoot = Resolve-SourceShareRoot
|
||||||
@@ -969,7 +1005,8 @@ try {
|
|||||||
$needsExchangeNoisePatch = Test-RdpMonitorSettingsNeedsExchangeNoisePatch -SettingsPath $settingsLocal
|
$needsExchangeNoisePatch = Test-RdpMonitorSettingsNeedsExchangeNoisePatch -SettingsPath $settingsLocal
|
||||||
$needsWinRmInboundBlock = Test-RdpMonitorSettingsNeedsWinRmInboundBlock -SettingsPath $settingsLocal
|
$needsWinRmInboundBlock = Test-RdpMonitorSettingsNeedsWinRmInboundBlock -SettingsPath $settingsLocal
|
||||||
$needsBundleSync = Test-RdpMonitorDeployBundleNeedsSync -ShareRoot $shareRoot
|
$needsBundleSync = Test-RdpMonitorDeployBundleNeedsSync -ShareRoot $shareRoot
|
||||||
$needsSacBootstrap = $needsSettingsBootstrap -or $needsBundleSync -or $needsDisplayNameHint -or $needsDailyReportHint -or $needsDailyReportRepair -or $needsExchangeNoisePatch -or $needsWinRmInboundBlock
|
$needsTaskExecutionLimitFix = Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime
|
||||||
|
$needsSacBootstrap = $needsSettingsBootstrap -or $needsBundleSync -or $needsDisplayNameHint -or $needsDailyReportHint -or $needsDailyReportRepair -or $needsExchangeNoisePatch -or $needsWinRmInboundBlock -or $needsTaskExecutionLimitFix
|
||||||
|
|
||||||
if (Test-RdpMonitorExchangeServerRole) {
|
if (Test-RdpMonitorExchangeServerRole) {
|
||||||
Write-DeployLog "Обнаружена роль Exchange — при необходимости допишем WinRM/4624 noise settings в login_monitor.settings.ps1."
|
Write-DeployLog "Обнаружена роль Exchange — при необходимости допишем WinRM/4624 noise settings в login_monitor.settings.ps1."
|
||||||
@@ -1006,6 +1043,9 @@ try {
|
|||||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но на Exchange не хватает noise settings (WinRM/4624) — продолжаем деплой."
|
Write-DeployLog "Версия совпадает ($shareVerRaw), но на Exchange не хватает noise settings (WinRM/4624) — продолжаем деплой."
|
||||||
} elseif ($needsWinRmInboundBlock) {
|
} elseif ($needsWinRmInboundBlock) {
|
||||||
Write-DeployLog "Версия совпадает ($shareVerRaw), но в settings отсутствует обязательный блок WinRM inbound — продолжаем деплой."
|
Write-DeployLog "Версия совпадает ($shareVerRaw), но в settings отсутствует обязательный блок WinRM inbound — продолжаем деплой."
|
||||||
|
} elseif ($needsTaskExecutionLimitFix) {
|
||||||
|
$limitLabel = Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel
|
||||||
|
Write-DeployLog "Версия совпадает ($shareVerRaw), но RDP-Login-Monitor имеет ExecutionTimeLimit=$limitLabel — перерегистрируем задачи (InstallTasks)."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($cmp -lt 0 -and -not $AllowDowngrade) {
|
if ($cmp -lt 0 -and -not $AllowDowngrade) {
|
||||||
@@ -1072,6 +1112,8 @@ try {
|
|||||||
Write-DeployLog "InstallTasks выполнен (код 0)."
|
Write-DeployLog "InstallTasks выполнен (код 0)."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[void](Write-RdpMonitorDeployScheduledTaskVerification)
|
||||||
|
|
||||||
[System.IO.File]::WriteAllText($VersionStampPath, "$shareVerRaw`r`n", $Utf8Bom)
|
[System.IO.File]::WriteAllText($VersionStampPath, "$shareVerRaw`r`n", $Utf8Bom)
|
||||||
Write-DeployLog "Записана метка версии: $VersionStampPath"
|
Write-DeployLog "Записана метка версии: $VersionStampPath"
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ $mainSettings = New-ScheduledTaskSettingsSet `
|
|||||||
-AllowStartIfOnBatteries `
|
-AllowStartIfOnBatteries `
|
||||||
-DontStopIfGoingOnBatteries `
|
-DontStopIfGoingOnBatteries `
|
||||||
-StartWhenAvailable `
|
-StartWhenAvailable `
|
||||||
-MultipleInstances IgnoreNew
|
-MultipleInstances IgnoreNew `
|
||||||
|
-ExecutionTimeLimit ([TimeSpan]::Zero)
|
||||||
|
|
||||||
Register-ScheduledTask `
|
Register-ScheduledTask `
|
||||||
-TaskName $MainTaskName `
|
-TaskName $MainTaskName `
|
||||||
|
|||||||
+62
-9
@@ -89,7 +89,7 @@ $script:SkipLogDetailLimit = 15
|
|||||||
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
||||||
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
||||||
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
||||||
$ScriptVersion = "2.0.23-SAC"
|
$ScriptVersion = "2.0.24-SAC"
|
||||||
|
|
||||||
# Логи (все под InstallRoot)
|
# Логи (все под InstallRoot)
|
||||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||||
@@ -480,11 +480,49 @@ function Invoke-RdpMonitorReloadSettings {
|
|||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
||||||
|
if ($null -eq $limit) { return $false }
|
||||||
|
if ($limit.Ticks -le 0) { return $true }
|
||||||
|
# Некоторые сборки Windows возвращают «безлимит» как очень большой интервал.
|
||||||
|
if ($limit.TotalDays -ge 999) { return $true }
|
||||||
|
return $false
|
||||||
|
} catch {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel {
|
||||||
|
param([Parameter(Mandatory = $true)][string]$TaskName)
|
||||||
|
try {
|
||||||
|
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
||||||
|
if ($null -eq $limit) { return '(null)' }
|
||||||
|
if ($limit.Ticks -le 0) { return 'PT0S (без лимита)' }
|
||||||
|
return $limit.ToString()
|
||||||
|
} catch {
|
||||||
|
return '(задача не найдена)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-RdpMonitorMainScheduledTaskSettings {
|
||||||
|
# ExecutionTimeLimit по умолчанию у Register-ScheduledTask = PT72H; монитор должен работать месяцами.
|
||||||
|
New-ScheduledTaskSettingsSet `
|
||||||
|
-AllowStartIfOnBatteries `
|
||||||
|
-DontStopIfGoingOnBatteries `
|
||||||
|
-StartWhenAvailable `
|
||||||
|
-ExecutionTimeLimit ([TimeSpan]::Zero)
|
||||||
|
}
|
||||||
|
|
||||||
function Test-RdpMonitorScheduledTaskMatches {
|
function Test-RdpMonitorScheduledTaskMatches {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$TaskName,
|
[Parameter(Mandatory = $true)][string]$TaskName,
|
||||||
[Parameter(Mandatory = $true)][string]$ExpectedExe,
|
[Parameter(Mandatory = $true)][string]$ExpectedExe,
|
||||||
[Parameter(Mandatory = $true)][string]$ExpectedArguments
|
[Parameter(Mandatory = $true)][string]$ExpectedArguments,
|
||||||
|
[switch]$RequireUnlimitedExecutionTime
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
$t = Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1
|
$t = Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1
|
||||||
@@ -492,7 +530,13 @@ function Test-RdpMonitorScheduledTaskMatches {
|
|||||||
if ($null -eq $a) { return $false }
|
if ($null -eq $a) { return $false }
|
||||||
$exe = [string]$a.Execute
|
$exe = [string]$a.Execute
|
||||||
$arg = [string]$a.Arguments
|
$arg = [string]$a.Arguments
|
||||||
return (($exe.Trim() -eq $ExpectedExe.Trim()) -and ($arg.Trim() -eq $ExpectedArguments.Trim()))
|
if (($exe.Trim() -ne $ExpectedExe.Trim()) -or ($arg.Trim() -ne $ExpectedArguments.Trim())) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($RequireUnlimitedExecutionTime -and -not (Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited -TaskName $TaskName)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
return $true
|
||||||
} catch {
|
} catch {
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
@@ -501,7 +545,7 @@ function Test-RdpMonitorScheduledTaskMatches {
|
|||||||
function Register-RdpMonitorScheduledTasksCore {
|
function Register-RdpMonitorScheduledTasksCore {
|
||||||
param([switch]$SkipImmediateMainRun)
|
param([switch]$SkipImmediateMainRun)
|
||||||
|
|
||||||
Write-Log "Register-RdpMonitorScheduledTasksCore: ветка v$ScriptVersion (watchdog через schtasks /SC MINUTE, без CIM RepetitionInterval)."
|
Write-Log "Register-RdpMonitorScheduledTasksCore: v$ScriptVersion (main ExecutionTimeLimit=PT0S; watchdog schtasks /SC MINUTE)."
|
||||||
$psExe = Get-RdpMonitorPowerShellExe
|
$psExe = Get-RdpMonitorPowerShellExe
|
||||||
$canonicalScript = [System.IO.Path]::GetFullPath((Join-Path $script:InstallRoot $script:CanonicalScriptName))
|
$canonicalScript = [System.IO.Path]::GetFullPath((Join-Path $script:InstallRoot $script:CanonicalScriptName))
|
||||||
if (-not (Test-Path -LiteralPath $canonicalScript)) {
|
if (-not (Test-Path -LiteralPath $canonicalScript)) {
|
||||||
@@ -515,11 +559,11 @@ function Register-RdpMonitorScheduledTasksCore {
|
|||||||
$actionMain = New-ScheduledTaskAction -Execute $psExe -Argument $argMain
|
$actionMain = New-ScheduledTaskAction -Execute $psExe -Argument $argMain
|
||||||
$triggerBoot = New-ScheduledTaskTrigger -AtStartup
|
$triggerBoot = New-ScheduledTaskTrigger -AtStartup
|
||||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
||||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
|
$settings = New-RdpMonitorMainScheduledTaskSettings
|
||||||
|
|
||||||
Register-ScheduledTask -TaskName $script:ScheduledTaskNameMain -Action $actionMain -Trigger $triggerBoot `
|
Register-ScheduledTask -TaskName $script:ScheduledTaskNameMain -Action $actionMain -Trigger $triggerBoot `
|
||||||
-Principal $principal -Settings $settings -Force | Out-Null
|
-Principal $principal -Settings $settings -Force | Out-Null
|
||||||
Write-Log "Задача планировщика: $($script:ScheduledTaskNameMain) (запуск при старте ОС)."
|
Write-Log "Задача планировщика: $($script:ScheduledTaskNameMain) (запуск при старте ОС, ExecutionTimeLimit=PT0S)."
|
||||||
|
|
||||||
# Watchdog только через schtasks. /Delete при отсутствии задачи пишет в stderr — при $ErrorActionPreference Stop раньше рвал скрипт.
|
# Watchdog только через schtasks. /Delete при отсутствии задачи пишет в stderr — при $ErrorActionPreference Stop раньше рвал скрипт.
|
||||||
$schtasksExe = Join-Path $env:SystemRoot 'System32\schtasks.exe'
|
$schtasksExe = Join-Path $env:SystemRoot 'System32\schtasks.exe'
|
||||||
@@ -583,15 +627,24 @@ function Ensure-RdpMonitorScheduledTasks {
|
|||||||
$argMain = "-NoProfile -ExecutionPolicy Bypass -File `"$canonicalScript`""
|
$argMain = "-NoProfile -ExecutionPolicy Bypass -File `"$canonicalScript`""
|
||||||
$argWd = "-NoProfile -ExecutionPolicy Bypass -File `"$canonicalScript`" -Watchdog"
|
$argWd = "-NoProfile -ExecutionPolicy Bypass -File `"$canonicalScript`" -Watchdog"
|
||||||
|
|
||||||
$needMain = -not (Test-RdpMonitorScheduledTaskMatches -TaskName $script:ScheduledTaskNameMain -ExpectedExe $psExe -ExpectedArguments $argMain)
|
$mainPathsOk = Test-RdpMonitorScheduledTaskMatches -TaskName $script:ScheduledTaskNameMain -ExpectedExe $psExe -ExpectedArguments $argMain
|
||||||
|
$mainLimitOk = Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited -TaskName $script:ScheduledTaskNameMain
|
||||||
|
$needMain = (-not $mainPathsOk) -or (-not $mainLimitOk)
|
||||||
$needWd = -not (Test-RdpMonitorScheduledTaskMatches -TaskName $script:ScheduledTaskNameWatchdog -ExpectedExe $psExe -ExpectedArguments $argWd)
|
$needWd = -not (Test-RdpMonitorScheduledTaskMatches -TaskName $script:ScheduledTaskNameWatchdog -ExpectedExe $psExe -ExpectedArguments $argWd)
|
||||||
|
|
||||||
if (-not $needMain -and -not $needWd) {
|
if (-not $needMain -and -not $needWd) {
|
||||||
Write-Log "Задачи планировщика ($($script:ScheduledTaskNameMain), $($script:ScheduledTaskNameWatchdog)) соответствуют каноническим путям."
|
Write-Log "Задачи планировщика ($($script:ScheduledTaskNameMain), $($script:ScheduledTaskNameWatchdog)) соответствуют каноническим путям и лимитам."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($needMain) { Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameMain)" }
|
if ($needMain) {
|
||||||
|
if (-not $mainPathsOk) {
|
||||||
|
Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameMain)"
|
||||||
|
} elseif (-not $mainLimitOk) {
|
||||||
|
$limitLabel = Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel -TaskName $script:ScheduledTaskNameMain
|
||||||
|
Write-Log "Требуется обновить задачу: $($script:ScheduledTaskNameMain) (ExecutionTimeLimit=$limitLabel; нужен PT0S — иначе Task Scheduler останавливает монитор через 72 ч)."
|
||||||
|
}
|
||||||
|
}
|
||||||
if ($needWd) { Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameWatchdog)" }
|
if ($needWd) { Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameWatchdog)" }
|
||||||
|
|
||||||
Register-RdpMonitorScheduledTasksCore
|
Register-RdpMonitorScheduledTasksCore
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.0.23-SAC
|
2.0.24-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user