"""Back up and deploy the VDD login refresh script in VM100, without rebooting.""" import argparse import base64 from pathlib import Path import runpy import sys sys.stdout.reconfigure(encoding="utf-8", errors="replace") parser = argparse.ArgumentParser(description=__doc__) parser.parse_args() root = Path(__file__).resolve().parent term = runpy.run_path(str(root / "pve_term_exec.py")) vm = runpy.run_path(str(root / "pve_vm.py")) ticket, csrf = term["login"]() state = vm["api"]("/api2/json/nodes/starhe/qemu/100/status/current", ticket=ticket) if state.get("status") != "running": sys.exit("VM100 is not running; nothing changed") payload = base64.b64encode((root / "set-2k-display.ps1").read_bytes()).decode() command = r""" $ErrorActionPreference='Stop' $target='C:\ProgramData\VDI\set-2k-display.ps1' $task='VDISet2KDisplay' $entry=Get-ScheduledTask -TaskName $task if($entry.State -eq 'Running') { throw 'Display task is already running; inspect before deployment' } if(-not (Test-Path -LiteralPath $target)) { throw 'Original display script is missing' } if(($entry.Actions | Select-Object -First 1).Arguments -notlike '*set-2k-display.ps1*') { throw 'Unexpected display task action; do not change it' } $backup='C:\ProgramData\VDI\backups\display-refresh-'+(Get-Date -Format 'yyyyMMdd-HHmmss') New-Item -ItemType Directory -Path $backup | Out-Null Copy-Item -LiteralPath $target -Destination "$backup\set-2k-display.ps1" Export-ScheduledTask -TaskName $task | Set-Content -Encoding UTF8 "$backup\VDISet2KDisplay.xml" if(Test-Path 'C:\ProgramData\VDI\set-2k-result.txt') { Copy-Item 'C:\ProgramData\VDI\set-2k-result.txt' "$backup\previous-result.txt" } $temporary=$target+'.new' try { [IO.File]::WriteAllBytes($temporary,[Convert]::FromBase64String('__PAYLOAD__')) Move-Item -LiteralPath $temporary -Destination $target -Force # Prove freshness by a newly created result file; scheduler LastRunTime can # lag wall-clock time after VM clock correction and is not a reliable token. Remove-Item -LiteralPath 'C:\ProgramData\VDI\set-2k-result.txt' -ErrorAction SilentlyContinue Start-ScheduledTask -TaskName $task Start-Sleep -Seconds 2 for($i=0;$i -lt 20;$i++) { if((Get-ScheduledTask -TaskName $task).State -ne 'Running') { break } Start-Sleep -Seconds 1 } $info=Get-ScheduledTaskInfo -TaskName $task if((Get-ScheduledTask -TaskName $task).State -eq 'Running' -or $info.LastTaskResult -ne 0) { throw 'New display task did not complete successfully' } $log=Get-Content 'C:\ProgramData\VDI\set-2k-result.txt' -Raw if($log -notmatch 'result=0 mode=2560x1440@60') { throw '60Hz read-back missing in display task log' } @{backup=$backup; task_result=$info.LastTaskResult; result=$log.Trim()} | ConvertTo-Json -Compress } catch { if(Test-Path 'C:\ProgramData\VDI\set-2k-result.txt') { Copy-Item 'C:\ProgramData\VDI\set-2k-result.txt' "$backup\failed-result.txt" Get-Content "$backup\failed-result.txt" } if($info) { $info | Select-Object LastTaskResult,LastRunTime | ConvertTo-Json -Compress } Stop-ScheduledTask -TaskName $task -ErrorAction SilentlyContinue Copy-Item -LiteralPath "$backup\set-2k-display.ps1" -Destination $target -Force Start-ScheduledTask -TaskName $task throw } finally { Remove-Item -LiteralPath $temporary -ErrorAction SilentlyContinue } """.replace("__PAYLOAD__", payload) out, error = vm["agent"](ticket, csrf, ["powershell.exe", "-NoProfile", "-Command", command]) print(out) if error or '"task_result":0' not in out: print(error, file=sys.stderr) sys.exit(1)