fix: deploy task verify via schtasks XML and notify SAC on update (2.0.28-SAC)
Stop false redeploy loops when Get-ScheduledTask fails, push agent version to SAC immediately after deploy, and skip redundant schtasks /Run during task maintenance.
This commit is contained in:
+83
-18
@@ -58,7 +58,7 @@ $DeployLogPath = Join-Path $InstallRoot "Logs\deploy.log"
|
|||||||
$ScriptName = "Login_Monitor.ps1"
|
$ScriptName = "Login_Monitor.ps1"
|
||||||
$SacClientName = "Sac-Client.ps1"
|
$SacClientName = "Sac-Client.ps1"
|
||||||
$VersionFileName = "version.txt"
|
$VersionFileName = "version.txt"
|
||||||
$DeployBundleFiles = @($ScriptName, $SacClientName, 'Diagnose-RdpLoginMonitor.ps1')
|
$DeployBundleFiles = @($ScriptName, $SacClientName, 'Diagnose-RdpLoginMonitor.ps1', 'RdpMonitor-TaskQuery.ps1')
|
||||||
$PsExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
$PsExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||||
|
|
||||||
$Utf8Bom = New-Object System.Text.UTF8Encoding $true
|
$Utf8Bom = New-Object System.Text.UTF8Encoding $true
|
||||||
@@ -971,35 +971,60 @@ function Stop-RdpLoginMonitorMainProcesses {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime {
|
function Import-RdpMonitorDeployTaskQueryModule {
|
||||||
param([string]$TaskName = 'RDP-Login-Monitor')
|
param([string]$ShareRoot = '')
|
||||||
|
|
||||||
|
$candidates = [System.Collections.Generic.List[string]]::new()
|
||||||
|
$candidates.Add((Join-Path $InstallRoot 'RdpMonitor-TaskQuery.ps1')) | Out-Null
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($ShareRoot)) {
|
||||||
|
$candidates.Add((Join-Path $ShareRoot 'RdpMonitor-TaskQuery.ps1')) | Out-Null
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
$candidates.Add((Join-Path (Resolve-SourceShareRoot) 'RdpMonitor-TaskQuery.ps1')) | Out-Null
|
||||||
if ($null -eq $limit) { return $true }
|
} catch { }
|
||||||
if ($limit.Ticks -le 0) { return $false }
|
}
|
||||||
if ($limit.TotalDays -ge 999) { return $false }
|
|
||||||
return $true
|
foreach ($candidate in @($candidates)) {
|
||||||
} catch {
|
if (Test-Path -LiteralPath $candidate) {
|
||||||
|
. $candidate
|
||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime {
|
||||||
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
|
if (-not (Get-Command Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit -ErrorAction SilentlyContinue)) {
|
||||||
|
if (-not (Import-RdpMonitorDeployTaskQueryModule)) { return $true }
|
||||||
|
}
|
||||||
|
return (Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit -TaskName $TaskName)
|
||||||
|
}
|
||||||
|
|
||||||
function Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel {
|
function Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel {
|
||||||
param([string]$TaskName = 'RDP-Login-Monitor')
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
try {
|
if (-not (Get-Command Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel -ErrorAction SilentlyContinue)) {
|
||||||
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
if (-not (Import-RdpMonitorDeployTaskQueryModule)) { return '(модуль TaskQuery недоступен)' }
|
||||||
if ($null -eq $limit) { return '(null)' }
|
|
||||||
if ($limit.Ticks -le 0) { return 'PT0S (без лимита)' }
|
|
||||||
return $limit.ToString()
|
|
||||||
} catch {
|
|
||||||
return '(задача не найдена)'
|
|
||||||
}
|
}
|
||||||
|
return (Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel -TaskName $TaskName)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Write-RdpMonitorDeployScheduledTaskVerification {
|
function Write-RdpMonitorDeployScheduledTaskVerification {
|
||||||
param([string]$TaskName = 'RDP-Login-Monitor')
|
param([string]$TaskName = 'RDP-Login-Monitor')
|
||||||
if (Test-RdpMonitorDeployMainTaskNeedsUnlimitedExecutionTime -TaskName $TaskName) {
|
if (-not (Get-Command Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit -ErrorAction SilentlyContinue)) {
|
||||||
$label = Get-RdpMonitorDeployMainTaskExecutionTimeLimitLabel -TaskName $TaskName
|
if (-not (Import-RdpMonitorDeployTaskQueryModule)) {
|
||||||
|
Write-DeployLog "ПРЕДУПРЕЖДЕНИЕ: RdpMonitor-TaskQuery.ps1 не найден — проверка ExecutionTimeLimit пропущена."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolved = Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -TaskName $TaskName
|
||||||
|
if ($resolved.Source -eq 'schtasks-xml') {
|
||||||
|
Write-DeployLog "Задача ${TaskName}: ExecutionTimeLimit проверен через schtasks /XML (Get-ScheduledTask недоступен)."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit -TaskName $TaskName) {
|
||||||
|
$label = Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel -TaskName $TaskName
|
||||||
Write-DeployLog "ПРЕДУПРЕЖДЕНИЕ: $TaskName ExecutionTimeLimit=$label — ожидался PT0S (без лимита). Проверьте InstallTasks и права администратора."
|
Write-DeployLog "ПРЕДУПРЕЖДЕНИЕ: $TaskName ExecutionTimeLimit=$label — ожидался PT0S (без лимита). Проверьте InstallTasks и права администратора."
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
@@ -1007,6 +1032,42 @@ function Write-RdpMonitorDeployScheduledTaskVerification {
|
|||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Invoke-RdpMonitorDeploySacVersionNotice {
|
||||||
|
if (-not (Test-Path -LiteralPath $LocalScript)) {
|
||||||
|
Write-DeployLog "SAC deploy notice: Login_Monitor.ps1 не найден — пропуск."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$settingsLocal = Join-Path $InstallRoot 'login_monitor.settings.ps1'
|
||||||
|
if (-not (Test-Path -LiteralPath $settingsLocal)) {
|
||||||
|
Write-DeployLog "SAC deploy notice: login_monitor.settings.ps1 отсутствует — пропуск."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$outLog = Join-Path $InstallRoot 'Logs\deploy_sac_notice_stdout.log'
|
||||||
|
$errLog = Join-Path $InstallRoot 'Logs\deploy_sac_notice_stderr.log'
|
||||||
|
$noticeArgs = @(
|
||||||
|
'-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $LocalScript, '-SendDeploySacNotice'
|
||||||
|
)
|
||||||
|
$p = Start-Process -FilePath $PsExe -ArgumentList $noticeArgs -Wait -PassThru -WindowStyle Hidden `
|
||||||
|
-RedirectStandardOutput $outLog -RedirectStandardError $errLog
|
||||||
|
if ($p.ExitCode -eq 0) {
|
||||||
|
Write-DeployLog "SAC: версия агента передана сразу после деплоя (SendDeploySacNotice)."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-DeployLog "Предупреждение: SendDeploySacNotice завершился с кодом $($p.ExitCode) — SAC обновится при старте монитора (agent.lifecycle)."
|
||||||
|
foreach ($pair in @(@($outLog, 'stdout'), @($errLog, 'stderr'))) {
|
||||||
|
$lp = $pair[0]
|
||||||
|
$lbl = $pair[1]
|
||||||
|
if (Test-Path -LiteralPath $lp) {
|
||||||
|
$tail = Get-Content -LiteralPath $lp -Tail 20 -ErrorAction SilentlyContinue
|
||||||
|
if ($tail) {
|
||||||
|
Write-DeployLog "SendDeploySacNotice $lbl (хвост): $($tail -join ' | ')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# --- main ---
|
# --- main ---
|
||||||
try {
|
try {
|
||||||
$shareRoot = Resolve-SourceShareRoot
|
$shareRoot = Resolve-SourceShareRoot
|
||||||
@@ -1040,6 +1101,8 @@ try {
|
|||||||
Write-DeployLog "ОШИБКА: на шаре отсутствует $SacClientName — выполните update-rdp-monitor.ps1 на сервере публикации."
|
Write-DeployLog "ОШИБКА: на шаре отсутствует $SacClientName — выполните update-rdp-monitor.ps1 на сервере публикации."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[void](Import-RdpMonitorDeployTaskQueryModule -ShareRoot $shareRoot)
|
||||||
|
|
||||||
$needsSettingsBootstrap = Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $settingsLocal
|
$needsSettingsBootstrap = Test-RdpMonitorSettingsNeedsSacBootstrap -SettingsPath $settingsLocal
|
||||||
$needsDisplayNameHint = Test-RdpMonitorSettingsNeedsServerDisplayNameHint -SettingsPath $settingsLocal
|
$needsDisplayNameHint = Test-RdpMonitorSettingsNeedsServerDisplayNameHint -SettingsPath $settingsLocal
|
||||||
$needsDailyReportHint = Test-RdpMonitorSettingsNeedsDailyReportHint -SettingsPath $settingsLocal
|
$needsDailyReportHint = Test-RdpMonitorSettingsNeedsDailyReportHint -SettingsPath $settingsLocal
|
||||||
@@ -1171,6 +1234,8 @@ try {
|
|||||||
[System.IO.File]::WriteAllText($DeployUpdateMarkerPath, "$updMarker`r`n", $Utf8Bom)
|
[System.IO.File]::WriteAllText($DeployUpdateMarkerPath, "$updMarker`r`n", $Utf8Bom)
|
||||||
Write-DeployLog "Записана метка обновления: $DeployUpdateMarkerPath (Version=$shareVerRaw; UpdatedAt=$updStamp)."
|
Write-DeployLog "Записана метка обновления: $DeployUpdateMarkerPath (Version=$shareVerRaw; UpdatedAt=$updStamp)."
|
||||||
|
|
||||||
|
Invoke-RdpMonitorDeploySacVersionNotice
|
||||||
|
|
||||||
if (-not $SkipStartMonitorAfterUpdate) {
|
if (-not $SkipStartMonitorAfterUpdate) {
|
||||||
$canonical = [System.IO.Path]::GetFullPath($LocalScript)
|
$canonical = [System.IO.Path]::GetFullPath($LocalScript)
|
||||||
if (Test-RdpMonitorMainProcessRunning -CanonicalScript $canonical) {
|
if (Test-RdpMonitorMainProcessRunning -CanonicalScript $canonical) {
|
||||||
|
|||||||
+75
-28
@@ -38,6 +38,7 @@ param(
|
|||||||
[switch]$SkipImmediateMainRun,
|
[switch]$SkipImmediateMainRun,
|
||||||
[switch]$SkipScheduledTaskMaintenance,
|
[switch]$SkipScheduledTaskMaintenance,
|
||||||
[switch]$CheckSac,
|
[switch]$CheckSac,
|
||||||
|
[switch]$SendDeploySacNotice,
|
||||||
[switch]$RequestRestart,
|
[switch]$RequestRestart,
|
||||||
[switch]$Recycle
|
[switch]$Recycle
|
||||||
)
|
)
|
||||||
@@ -89,7 +90,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.27-SAC"
|
$ScriptVersion = "2.0.28-SAC"
|
||||||
|
|
||||||
# Логи (все под InstallRoot)
|
# Логи (все под InstallRoot)
|
||||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||||
@@ -480,31 +481,13 @@ function Invoke-RdpMonitorReloadSettings {
|
|||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
|
|
||||||
function Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited {
|
foreach ($taskQueryPath in @(
|
||||||
param(
|
(Join-Path $PSScriptRoot 'RdpMonitor-TaskQuery.ps1'),
|
||||||
[Parameter(Mandatory = $true)][string]$TaskName
|
(Join-Path $script:InstallRoot 'RdpMonitor-TaskQuery.ps1')
|
||||||
)
|
)) {
|
||||||
try {
|
if (Test-Path -LiteralPath $taskQueryPath) {
|
||||||
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
. $taskQueryPath
|
||||||
if ($null -eq $limit) { return $false }
|
break
|
||||||
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 '(задача не найдена)'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,9 +520,18 @@ function Test-RdpMonitorScheduledTaskMatches {
|
|||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
return $true
|
return $true
|
||||||
} catch {
|
} catch { }
|
||||||
|
|
||||||
|
if (-not (Get-Command Test-RdpMonitorScheduledTaskActionMatchesViaSchtasks -ErrorAction SilentlyContinue)) {
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
|
if (-not (Test-RdpMonitorScheduledTaskActionMatchesViaSchtasks -TaskName $TaskName -ExpectedExe $ExpectedExe -ExpectedArguments $ExpectedArguments)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($RequireUnlimitedExecutionTime -and -not (Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited -TaskName $TaskName)) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
function Register-RdpMonitorScheduledTasksCore {
|
function Register-RdpMonitorScheduledTasksCore {
|
||||||
@@ -647,7 +639,7 @@ function Ensure-RdpMonitorScheduledTasks {
|
|||||||
}
|
}
|
||||||
if ($needWd) { Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameWatchdog)" }
|
if ($needWd) { Write-Log "Требуется обновить или создать задачу: $($script:ScheduledTaskNameWatchdog)" }
|
||||||
|
|
||||||
Register-RdpMonitorScheduledTasksCore
|
Register-RdpMonitorScheduledTasksCore -SkipImmediateMainRun
|
||||||
}
|
}
|
||||||
|
|
||||||
function Start-RdpMonitorWatchdogMain {
|
function Start-RdpMonitorWatchdogMain {
|
||||||
@@ -1143,6 +1135,61 @@ if ($CheckSac) {
|
|||||||
exit $code
|
exit $code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($SendDeploySacNotice) {
|
||||||
|
if (-not $script:SacClientLoaded) {
|
||||||
|
Write-Log "SendDeploySacNotice: Sac-Client.ps1 не найден."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if ((Get-SacNormalizedMode) -eq 'off') {
|
||||||
|
Write-Log "SendDeploySacNotice: UseSAC=off — уведомление SAC пропущено."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
if (-not (Test-SacConfigured)) {
|
||||||
|
Write-Log "SendDeploySacNotice: SAC не настроен (SacUrl / SacApiKey)."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
[System.Net.ServicePointManager]::SecurityProtocol =
|
||||||
|
[System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
$hostLabel = $env:COMPUTERNAME
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($ServerDisplayName)) {
|
||||||
|
$hostLabel = [string]$ServerDisplayName
|
||||||
|
}
|
||||||
|
$updatedAt = $null
|
||||||
|
if (Test-Path -LiteralPath $DeployUpdateMarkerFile) {
|
||||||
|
try {
|
||||||
|
foreach ($ln in (Get-Content -LiteralPath $DeployUpdateMarkerFile -ErrorAction Stop)) {
|
||||||
|
if ($ln -match '^\s*UpdatedAt\s*=\s*(.+)\s*$') {
|
||||||
|
$updatedAt = $Matches[1].Trim()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
$summary = "RDP login monitor deployed, version $ScriptVersion on $hostLabel"
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($updatedAt)) {
|
||||||
|
$summary += " ($updatedAt)"
|
||||||
|
}
|
||||||
|
$details = @{
|
||||||
|
lifecycle = 'updated'
|
||||||
|
trigger = 'deploy'
|
||||||
|
version = [string]$ScriptVersion
|
||||||
|
}
|
||||||
|
$ok = Send-SacEvent -EventType 'agent.lifecycle' -Severity 'info' `
|
||||||
|
-Title "RDP agent updated to $ScriptVersion" `
|
||||||
|
-Summary $summary `
|
||||||
|
-Details $details
|
||||||
|
if ($ok) {
|
||||||
|
Write-Log "SendDeploySacNotice: SAC agent.lifecycle отправлен (version=$ScriptVersion)."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
Write-Log "SendDeploySacNotice: не удалось отправить в SAC (см. sac_client.log / spool)."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-RdpMonitorProcessMigrationAndRelaunch
|
Invoke-RdpMonitorProcessMigrationAndRelaunch
|
||||||
Lock-RdpMonitorSingleInstance
|
Lock-RdpMonitorSingleInstance
|
||||||
Ensure-RdpMonitorScheduledTasks
|
Ensure-RdpMonitorScheduledTasks
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Запрос задач планировщика RDP-login-monitor через schtasks /Query /XML (fallback для Get-ScheduledTask).
|
||||||
|
#>
|
||||||
|
|
||||||
|
function Get-RdpMonitorSchtasksExe {
|
||||||
|
return Join-Path $env:SystemRoot 'System32\schtasks.exe'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskXmlDocument {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
|
||||||
|
$exe = Get-RdpMonitorSchtasksExe
|
||||||
|
$prevEa = $ErrorActionPreference
|
||||||
|
try {
|
||||||
|
$ErrorActionPreference = 'SilentlyContinue'
|
||||||
|
$raw = & $exe /Query /TN $TaskName /XML 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0) { return $null }
|
||||||
|
$text = ($raw | Out-String).Trim()
|
||||||
|
if ([string]::IsNullOrWhiteSpace($text)) { return $null }
|
||||||
|
if ($text -notmatch '(?s)<Task\b') { return $null }
|
||||||
|
return [xml]$text
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $prevEa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskExistsViaSchtasks {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
return ($null -ne (Get-RdpMonitorScheduledTaskXmlDocument -TaskName $TaskName))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Convert-RdpMonitorScheduledTaskExecutionTimeLimitText {
|
||||||
|
param([string]$LimitText)
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($LimitText)) { return $null }
|
||||||
|
$t = $LimitText.Trim()
|
||||||
|
if ($t -eq 'PT0S') { return [TimeSpan]::Zero }
|
||||||
|
try {
|
||||||
|
return [System.Xml.XmlConvert]::ToTimeSpan($t)
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskExecutionTimeLimitFromDocument {
|
||||||
|
param([xml]$Doc)
|
||||||
|
|
||||||
|
if ($null -eq $Doc) { return $null }
|
||||||
|
|
||||||
|
$ns = New-Object System.Xml.XmlNamespaceManager($Doc.NameTable)
|
||||||
|
$ns.AddNamespace('t', 'http://schemas.microsoft.com/windows/2004/02/mit/task')
|
||||||
|
$node = $Doc.SelectSingleNode('//t:Settings/t:ExecutionTimeLimit', $ns)
|
||||||
|
if ($null -eq $node) {
|
||||||
|
$node = $Doc.SelectSingleNode('//*[local-name()="Settings"]/*[local-name()="ExecutionTimeLimit"]')
|
||||||
|
}
|
||||||
|
if ($null -eq $node -or [string]::IsNullOrWhiteSpace($node.InnerText)) { return $null }
|
||||||
|
return Convert-RdpMonitorScheduledTaskExecutionTimeLimitText -LimitText $node.InnerText.Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskActionFromDocument {
|
||||||
|
param([xml]$Doc)
|
||||||
|
|
||||||
|
if ($null -eq $Doc) { return $null }
|
||||||
|
|
||||||
|
$ns = New-Object System.Xml.XmlNamespaceManager($Doc.NameTable)
|
||||||
|
$ns.AddNamespace('t', 'http://schemas.microsoft.com/windows/2004/02/mit/task')
|
||||||
|
$cmdNode = $Doc.SelectSingleNode('//t:Actions/t:Exec/t:Command', $ns)
|
||||||
|
$argNode = $Doc.SelectSingleNode('//t:Actions/t:Exec/t:Arguments', $ns)
|
||||||
|
if ($null -eq $cmdNode) {
|
||||||
|
$cmdNode = $Doc.SelectSingleNode('//*[local-name()="Actions"]/*[local-name()="Exec"]/*[local-name()="Command"]')
|
||||||
|
}
|
||||||
|
if ($null -eq $argNode) {
|
||||||
|
$argNode = $Doc.SelectSingleNode('//*[local-name()="Actions"]/*[local-name()="Exec"]/*[local-name()="Arguments"]')
|
||||||
|
}
|
||||||
|
if ($null -eq $cmdNode) { return $null }
|
||||||
|
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Execute = [string]$cmdNode.InnerText
|
||||||
|
Arguments = if ($null -ne $argNode) { [string]$argNode.InnerText } else { '' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimitedValue {
|
||||||
|
param($Limit)
|
||||||
|
|
||||||
|
if ($null -eq $Limit) { return $false }
|
||||||
|
if ($Limit -isnot [TimeSpan]) { return $false }
|
||||||
|
if ($Limit.Ticks -le 0) { return $true }
|
||||||
|
if ($Limit.TotalDays -ge 999) { return $true }
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$limit = (Get-ScheduledTask -TaskName $TaskName -ErrorAction Stop | Select-Object -First 1).Settings.ExecutionTimeLimit
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Limit = $limit
|
||||||
|
Source = 'Get-ScheduledTask'
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
$doc = Get-RdpMonitorScheduledTaskXmlDocument -TaskName $TaskName
|
||||||
|
if ($null -eq $doc) {
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Limit = $null
|
||||||
|
Source = 'missing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$limit = Get-RdpMonitorScheduledTaskExecutionTimeLimitFromDocument -Doc $doc
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Limit = $limit
|
||||||
|
Source = 'schtasks-xml'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
|
||||||
|
$resolved = Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -TaskName $TaskName
|
||||||
|
if ($resolved.Source -eq 'missing') { return $false }
|
||||||
|
return (Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimitedValue -Limit $resolved.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
|
||||||
|
$resolved = Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -TaskName $TaskName
|
||||||
|
if ($resolved.Source -eq 'missing') { return $true }
|
||||||
|
return (-not (Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimitedValue -Limit $resolved.Limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName
|
||||||
|
)
|
||||||
|
|
||||||
|
$resolved = Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -TaskName $TaskName
|
||||||
|
if ($resolved.Source -eq 'missing') { return '(task missing)' }
|
||||||
|
|
||||||
|
$limit = $resolved.Limit
|
||||||
|
if ($null -eq $limit) { return '(null)' }
|
||||||
|
if ($limit -is [TimeSpan] -and $limit.Ticks -le 0) { return 'PT0S' }
|
||||||
|
return $limit.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RdpMonitorScheduledTaskActionMatchesViaSchtasks {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$TaskName,
|
||||||
|
[Parameter(Mandatory = $true)][string]$ExpectedExe,
|
||||||
|
[Parameter(Mandatory = $true)][string]$ExpectedArguments
|
||||||
|
)
|
||||||
|
|
||||||
|
$doc = Get-RdpMonitorScheduledTaskXmlDocument -TaskName $TaskName
|
||||||
|
if ($null -eq $doc) { return $false }
|
||||||
|
|
||||||
|
$action = Get-RdpMonitorScheduledTaskActionFromDocument -Doc $doc
|
||||||
|
if ($null -eq $action) { return $false }
|
||||||
|
if ($action.Execute.Trim() -ne $ExpectedExe.Trim()) { return $false }
|
||||||
|
return ($action.Arguments.Trim() -eq $ExpectedArguments.Trim())
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
$DistFiles = @(
|
$DistFiles = @(
|
||||||
'Login_Monitor.ps1',
|
'Login_Monitor.ps1',
|
||||||
'Sac-Client.ps1',
|
'Sac-Client.ps1',
|
||||||
|
'RdpMonitor-TaskQuery.ps1',
|
||||||
'version.txt',
|
'version.txt',
|
||||||
'Deploy-LoginMonitor.ps1',
|
'Deploy-LoginMonitor.ps1',
|
||||||
'Restart-RdpLoginMonitor.ps1',
|
'Restart-RdpLoginMonitor.ps1',
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.0.27-SAC
|
2.0.28-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user