From 0da1d0f2acad7ae80a3c418305dab91f56557f94 Mon Sep 17 00:00:00 2001 From: PTah Date: Thu, 11 Jun 2026 15:23:59 +1000 Subject: [PATCH 1/2] fix: deploy TaskQuery script scope (2.0.32-SAC) Publish TaskQuery helpers to script scope after import so ExecutionTimeLimit checks work from nested deploy callers; add RDP_DEPLOY_FUNCTIONS_ONLY early exit for isolated function loading. Co-authored-by: Cursor --- Deploy-LoginMonitor.ps1 | 40 ++++++++++++++++++++++++++++++++++++---- Login_Monitor.ps1 | 2 +- version.txt | 2 +- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Deploy-LoginMonitor.ps1 b/Deploy-LoginMonitor.ps1 index 09c68e5..f2d9486 100644 --- a/Deploy-LoginMonitor.ps1 +++ b/Deploy-LoginMonitor.ps1 @@ -997,6 +997,28 @@ function Test-RdpMonitorDeployTaskQueryReady { return [bool](Get-Command Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -ErrorAction SilentlyContinue) } +function Publish-RdpMonitorDeployTaskQueryFunctionsToScriptScope { + foreach ($name in @( + 'Get-RdpMonitorSchtasksExe', + 'Get-RdpMonitorScheduledTaskXmlDocument', + 'Test-RdpMonitorScheduledTaskExistsViaSchtasks', + 'Convert-RdpMonitorScheduledTaskExecutionTimeLimitText', + 'Get-RdpMonitorScheduledTaskExecutionTimeLimitFromDocument', + 'Get-RdpMonitorScheduledTaskActionFromDocument', + 'Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimitedValue', + 'Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved', + 'Test-RdpMonitorScheduledTaskExecutionTimeLimitUnlimited', + 'Test-RdpMonitorScheduledTaskNeedsUnlimitedExecutionTimeLimit', + 'Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel', + 'Test-RdpMonitorScheduledTaskActionMatchesViaSchtasks' + )) { + $cmd = Get-Command -Name $name -ErrorAction SilentlyContinue + if ($null -ne $cmd -and $cmd.CommandType -eq 'Function') { + Set-Item -Path "function:script:$name" -Value $cmd.ScriptBlock + } + } +} + function Import-RdpMonitorDeployTaskQueryModule { param([string]$ShareRoot = '') @@ -1020,6 +1042,7 @@ function Import-RdpMonitorDeployTaskQueryModule { continue } if (Test-RdpMonitorDeployTaskQueryReady) { + Publish-RdpMonitorDeployTaskQueryFunctionsToScriptScope return $true } Write-DeployLog "Предупреждение: $candidate загружен, но функции TaskQuery недоступны — пробуем следующий источник." @@ -1033,13 +1056,20 @@ function Initialize-RdpMonitorDeployTaskQuery { if (Test-RdpMonitorDeployTaskQueryReady) { return $true } + + $loaded = $false if (Import-RdpMonitorDeployTaskQueryModule -ShareRoot $ShareRoot) { - return $true + $loaded = $true + } else { + Write-DeployLog "RdpMonitor-TaskQuery.ps1 недоступен — deploy использует встроенную проверку schtasks /XML." + . $script:RdpMonitorDeployTaskQueryInlineScript + $loaded = (Test-RdpMonitorDeployTaskQueryReady) } - Write-DeployLog "RdpMonitor-TaskQuery.ps1 недоступен — deploy использует встроенную проверку schtasks /XML." - . $script:RdpMonitorDeployTaskQueryInlineScript - return (Test-RdpMonitorDeployTaskQueryReady) + if ($loaded) { + Publish-RdpMonitorDeployTaskQueryFunctionsToScriptScope + } + return $loaded } $script:RdpMonitorDeployTaskQueryInlineScript = { @@ -1212,6 +1242,8 @@ function Invoke-RdpMonitorDeploySacVersionNotice { } # --- main --- +if ($env:RDP_DEPLOY_FUNCTIONS_ONLY -eq '1') { return } + try { $shareRoot = Resolve-SourceShareRoot $sourceScript = Join-Path $shareRoot $ScriptName diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index aa5bbb6..6f1e9cf 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -90,7 +90,7 @@ $script:SkipLogDetailLimit = 15 # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "2.0.31-SAC" +$ScriptVersion = "2.0.32-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" diff --git a/version.txt b/version.txt index 0744909..684bc8e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.31-SAC +2.0.32-SAC From b6d293d21badd94d1b971da2d73ad1c957d795c3 Mon Sep 17 00:00:00 2001 From: PTah Date: Thu, 11 Jun 2026 15:27:47 +1000 Subject: [PATCH 2/2] fix: normalize ExecutionTimeLimit PT0S and load TaskQuery locally (2.0.33-SAC) Treat Get-ScheduledTask limit strings as unlimited, prefer ProgramData for TaskQuery import, and copy UNC modules to temp before dot-source. Co-authored-by: Cursor --- Deploy-LoginMonitor.ps1 | 103 +++++++++++++++++++++++++++++---------- Login_Monitor.ps1 | 2 +- RdpMonitor-TaskQuery.ps1 | 20 +++++--- version.txt | 2 +- 4 files changed, 94 insertions(+), 33 deletions(-) diff --git a/Deploy-LoginMonitor.ps1 b/Deploy-LoginMonitor.ps1 index f2d9486..ca31e7e 100644 --- a/Deploy-LoginMonitor.ps1 +++ b/Deploy-LoginMonitor.ps1 @@ -973,12 +973,35 @@ function Stop-RdpLoginMonitorMainProcesses { } } +function Convert-RdpMonitorDeployTaskExecutionTimeLimitValue { + param($Limit) + + if ($null -eq $Limit) { return $null } + if ($Limit -is [TimeSpan]) { return $Limit } + + $text = [string]$Limit + if ([string]::IsNullOrWhiteSpace($text)) { return $null } + $t = $text.Trim() + if ($t -eq 'PT0S') { return [TimeSpan]::Zero } + + try { + return [System.Xml.XmlConvert]::ToTimeSpan($t) + } catch { } + + try { + return [TimeSpan]::Parse($t) + } catch { } + + return $null +} + function Test-RdpMonitorDeployTaskExecutionLimitUnlimitedValue { param($Limit) - if ($null -eq $Limit -or $Limit -isnot [TimeSpan]) { return $false } - if ($Limit.Ticks -le 0) { return $true } - if ($Limit.TotalDays -ge 999) { return $true } + $normalized = Convert-RdpMonitorDeployTaskExecutionTimeLimitValue -Limit $Limit + if ($null -eq $normalized) { return $false } + if ($normalized.Ticks -le 0) { return $true } + if ($normalized.TotalDays -ge 999) { return $true } return $false } @@ -987,9 +1010,9 @@ function Get-RdpMonitorDeployTaskExecutionTimeLimitLabelFromResolved { if ($null -eq $Resolved) { return '(null)' } if ($Resolved.Source -eq 'missing') { return '(task missing)' } - $limit = $Resolved.Limit + $limit = Convert-RdpMonitorDeployTaskExecutionTimeLimitValue -Limit $Resolved.Limit if ($null -eq $limit) { return '(null)' } - if ($limit -is [TimeSpan] -and $limit.Ticks -le 0) { return 'PT0S' } + if ($limit.Ticks -le 0) { return 'PT0S' } return $limit.ToString() } @@ -1019,33 +1042,63 @@ function Publish-RdpMonitorDeployTaskQueryFunctionsToScriptScope { } } -function Import-RdpMonitorDeployTaskQueryModule { - param([string]$ShareRoot = '') +function Import-RdpMonitorDeployTaskQueryModuleAtPath { + param( + [Parameter(Mandatory = $true)][string]$Candidate + ) - $candidates = [System.Collections.Generic.List[string]]::new() - if (-not [string]::IsNullOrWhiteSpace($ShareRoot)) { - $candidates.Add((Join-Path $ShareRoot 'RdpMonitor-TaskQuery.ps1')) | Out-Null - } - $deployScriptPath = $PSCommandPath - if ([string]::IsNullOrWhiteSpace($deployScriptPath)) { $deployScriptPath = $MyInvocation.MyCommand.Path } - if (-not [string]::IsNullOrWhiteSpace($deployScriptPath)) { - $candidates.Add((Join-Path (Split-Path -Parent $deployScriptPath) 'RdpMonitor-TaskQuery.ps1')) | Out-Null - } - $candidates.Add((Join-Path $InstallRoot 'RdpMonitor-TaskQuery.ps1')) | Out-Null + if (-not (Test-Path -LiteralPath $Candidate)) { return $false } - foreach ($candidate in @($candidates)) { - if (-not (Test-Path -LiteralPath $candidate)) { continue } - try { - . $candidate - } catch { - Write-DeployLog "Предупреждение: не удалось загрузить $candidate — $($_.Exception.Message)" - continue + $loadPath = $Candidate + $tempCopy = $null + try { + if ($Candidate.StartsWith('\\')) { + $tempCopy = Join-Path $env:TEMP ("rdp-taskquery-{0}.ps1" -f [guid]::NewGuid().ToString('N')) + Copy-Item -LiteralPath $Candidate -Destination $tempCopy -Force + $loadPath = $tempCopy } + . $loadPath if (Test-RdpMonitorDeployTaskQueryReady) { Publish-RdpMonitorDeployTaskQueryFunctionsToScriptScope return $true } - Write-DeployLog "Предупреждение: $candidate загружен, но функции TaskQuery недоступны — пробуем следующий источник." + Write-DeployLog "Предупреждение: $Candidate загружен, но функции TaskQuery недоступны — пробуем следующий источник." + } catch { + Write-DeployLog "Предупреждение: не удалось загрузить $Candidate — $($_.Exception.Message)" + } finally { + if ($null -ne $tempCopy -and (Test-Path -LiteralPath $tempCopy)) { + Remove-Item -LiteralPath $tempCopy -Force -ErrorAction SilentlyContinue + } + } + return $false +} + +function Import-RdpMonitorDeployTaskQueryModule { + param([string]$ShareRoot = '') + + $candidates = [System.Collections.Generic.List[string]]::new() + $installCandidate = Join-Path $InstallRoot 'RdpMonitor-TaskQuery.ps1' + $candidates.Add($installCandidate) | Out-Null + + $deployScriptPath = $PSCommandPath + if ([string]::IsNullOrWhiteSpace($deployScriptPath)) { $deployScriptPath = $MyInvocation.MyCommand.Path } + if (-not [string]::IsNullOrWhiteSpace($deployScriptPath)) { + $deployCandidate = Join-Path (Split-Path -Parent $deployScriptPath) 'RdpMonitor-TaskQuery.ps1' + if ($deployCandidate -ne $installCandidate) { + $candidates.Add($deployCandidate) | Out-Null + } + } + if (-not [string]::IsNullOrWhiteSpace($ShareRoot)) { + $shareCandidate = Join-Path $ShareRoot 'RdpMonitor-TaskQuery.ps1' + if ($shareCandidate -ne $installCandidate -and -not ($candidates -contains $shareCandidate)) { + $candidates.Add($shareCandidate) | Out-Null + } + } + + foreach ($candidate in @($candidates)) { + if (Import-RdpMonitorDeployTaskQueryModuleAtPath -Candidate $candidate) { + return $true + } } return $false } diff --git a/Login_Monitor.ps1 b/Login_Monitor.ps1 index 6f1e9cf..f9fc967 100644 --- a/Login_Monitor.ps1 +++ b/Login_Monitor.ps1 @@ -90,7 +90,7 @@ $script:SkipLogDetailLimit = 15 # строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах). # Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только # исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1). -$ScriptVersion = "2.0.32-SAC" +$ScriptVersion = "2.0.33-SAC" # Логи (все под InstallRoot) $LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log" diff --git a/RdpMonitor-TaskQuery.ps1 b/RdpMonitor-TaskQuery.ps1 index bdb1904..5efd982 100644 --- a/RdpMonitor-TaskQuery.ps1 +++ b/RdpMonitor-TaskQuery.ps1 @@ -87,13 +87,21 @@ function Get-RdpMonitorScheduledTaskActionFromDocument { } } +function Convert-RdpMonitorScheduledTaskExecutionTimeLimitValue { + param($Limit) + + if ($null -eq $Limit) { return $null } + if ($Limit -is [TimeSpan]) { return $Limit } + return Convert-RdpMonitorScheduledTaskExecutionTimeLimitText -LimitText ([string]$Limit) +} + 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 } + $normalized = Convert-RdpMonitorScheduledTaskExecutionTimeLimitValue -Limit $Limit + if ($null -eq $normalized) { return $false } + if ($normalized.Ticks -le 0) { return $true } + if ($normalized.TotalDays -ge 999) { return $true } return $false } @@ -153,9 +161,9 @@ function Get-RdpMonitorScheduledTaskExecutionTimeLimitLabel { $resolved = Get-RdpMonitorScheduledTaskExecutionTimeLimitResolved -TaskName $TaskName if ($resolved.Source -eq 'missing') { return '(task missing)' } - $limit = $resolved.Limit + $limit = Convert-RdpMonitorScheduledTaskExecutionTimeLimitValue -Limit $resolved.Limit if ($null -eq $limit) { return '(null)' } - if ($limit -is [TimeSpan] -and $limit.Ticks -le 0) { return 'PT0S' } + if ($limit.Ticks -le 0) { return 'PT0S' } return $limit.ToString() } diff --git a/version.txt b/version.txt index 684bc8e..18bed85 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.32-SAC +2.0.33-SAC