"""Re-register scheduled task with clean argument escaping. Uses an external file for the PowerShell registration script rather than inline base64 (which was mangling backslashes). """ import base64, paramiko, subprocess, time, yaml pwd_raw = yaml.safe_load(subprocess.run(['sops','-d','D:/vault/clients/dataforth/ad2.sops.yaml'], capture_output=True, text=True, timeout=30, check=True).stdout)['credentials']['password'] PWD = pwd_raw.replace('\\', '') REG_SCRIPT = r'''# register-task.ps1 — re-register DataforthTestDatasheetUploader cleanly $taskName = 'DataforthTestDatasheetUploader' $scriptPath = 'C:\ProgramData\dataforth-uploader\run-pipeline.ps1' Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue | Out-Null # Argument uses single quotes inside to avoid double-quote escaping issues $argStr = '-NoProfile -ExecutionPolicy Bypass -File ' + '"' + $scriptPath + '"' $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $argStr -WorkingDirectory 'C:\ProgramData\dataforth-uploader' $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).Date.AddHours(1) -RepetitionInterval (New-TimeSpan -Hours 1) $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Minutes 30) Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description 'Dataforth Test Datasheet Uploader (DFWDS port + Hoffman API)' | Out-Null Write-Host '=== registered task definition ===' (Get-ScheduledTask -TaskName $taskName).Actions | Format-List Write-Host '=== run it now ===' Start-ScheduledTask -TaskName $taskName Start-Sleep -Seconds 20 Get-ScheduledTaskInfo -TaskName $taskName | Select LastRunTime,LastTaskResult,NextRunTime | Format-List ''' c = paramiko.SSHClient(); c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect('192.168.0.6', username='sysadmin', password=PWD, timeout=30, banner_timeout=45, look_for_keys=False, allow_agent=False) print('[1] SFTP register-task.ps1 to AD2') remote_reg = 'C:/ProgramData/dataforth-uploader/register-task.ps1' sftp = c.open_sftp() with sftp.open(remote_reg, 'w') as fh: fh.write(REG_SCRIPT) sftp.close() print('\n[2] run register-task.ps1 (elevated)') # Use cmd to launch powershell so we avoid the quote-escape chain _, o, e = c.exec_command( r'powershell -NoProfile -ExecutionPolicy Bypass -File "C:\ProgramData\dataforth-uploader\register-task.ps1"', timeout=120 ) print(o.read().decode('utf-8','replace')) err = e.read().decode('utf-8','replace') if err.strip() and 'CLIXML' not in err: print('[stderr]', err[:500]) print('\n[3] tail latest pipeline log (post-SYSTEM-run)') def psb64(cmd, to=60): enc = base64.b64encode(cmd.encode('utf-16-le')).decode() _, o, _ = c.exec_command(f'powershell -NoProfile -EncodedCommand {enc}', timeout=to) return o.read().decode('utf-8','replace') out = psb64( r'$latest = Get-ChildItem "C:\ProgramData\dataforth-uploader\logs" -Filter "pipeline-*.log" | ' r'Sort-Object LastWriteTime -Descending | Select -First 1; ' r'"Log: $($latest.FullName)"; "---"; Get-Content $latest.FullName -Tail 20' ) print(out) c.close()