Files
punktfunk/packaging/windows/reset-pf-vdisplay.ps1
T
enricobuehler c206e19ce5 feat(windows-packaging): dev-iteration scripts — reset + redeploy pf-vdisplay driver
Today's manual driver recovery (wedged under ADD/REMOVE churn → ERROR_NOT_FOUND) and the manual
host-stop/install/host-start dance around drivers/deploy-dev.ps1 are now two scripts:

  * reset-pf-vdisplay.ps1   — recover a wedged driver: stop host → pnputil /remove-device the ghost
                              "Generic Monitor (punktfunk)" nodes → Disable+Enable the adapter
                              (Restart-PnpDevice doesn't exist on the box PS) → start host. No reboot
                              (the box boots to Proxmox). -Verify probes to confirm ADD recovered.
  * redeploy-pf-vdisplay.ps1 — one-shot dev redeploy wrapping deploy-dev.ps1 with the host stop/start
                              (the running host holds the driver DLL) + a post-install adapter reload
                              (pnputil updates the store but the live device keeps the old binary).

Both standalone (don't touch deploy-dev.ps1). README gains a "Dev iteration on the test box" section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:45:14 +00:00

131 lines
5.9 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#requires -Version 5.1
<#
.SYNOPSIS
Recover the pf-vdisplay (punktfunk) virtual-display driver after it WEDGES under rapid ADD/REMOVE
churn — no reboot. The dev-iteration counterpart to redeploy-pf-vdisplay.ps1.
.DESCRIPTION
Sustained connect/disconnect churn (e.g. a client reconnect loop × the host's 8 pipeline-build
retries — ~100 ADD/REMOVE cycles) exhausts the driver's IddCx monitor slots: the per-monitor
target_ids climb, ghost "Generic Monitor (punktfunk)" device nodes pile up, and eventually
IOCTL_ADD returns 0x80070490 ERROR_NOT_FOUND ("Element nicht gefunden"). Every session then fails
to create a virtual output -> the client gets a hard blackscreen. A host-service restart's
IOCTL_CLEAR_ALL does NOT recover it; the driver instance itself must be reloaded.
Steps (run ELEVATED):
1. Stop the host service (it holds the driver's control device).
2. pnputil /remove-device the GHOST (Status != OK = not-present) punktfunk virtual-monitor nodes
that accumulated — the root of the slot exhaustion.
3. Disable + Enable the pf-vdisplay adapter (ROOT\DISPLAY\*, "punktfunk Virtual Display") to
reload the IddCx driver instance and reset its monitor list. (Restart-PnpDevice does NOT exist
on this box's PowerShell, so we disable+enable explicitly.)
4. Restart the host service.
Avoids a reboot on purpose (this box boots to Proxmox).
.PARAMETER Service Host service name. Default PunktfunkHost.
.PARAMETER AdapterName FriendlyName substring of the IddCx adapter to cycle. Default "punktfunk
Virtual Display" (NOT SudoVDA's "SudoMaker Virtual Display Adapter").
.PARAMETER GhostMatch FriendlyName substring of the virtual monitors to reap. Default "punktfunk".
.PARAMETER KeepGhosts Skip the ghost-node cleanup; only cycle the adapter.
.PARAMETER NoHost Don't stop/start the host service (just reset the driver) — used by
redeploy-pf-vdisplay.ps1, which manages the service itself.
.PARAMETER Verify After recovery, run a punktfunk-probe loopback and report whether ADD works
again (best-effort; needs punktfunk-probe.exe on PATH or via -Probe).
.PARAMETER Probe Path to punktfunk-probe.exe for -Verify.
.EXAMPLE
powershell -ExecutionPolicy Bypass -File reset-pf-vdisplay.ps1
.EXAMPLE
powershell -ExecutionPolicy Bypass -File reset-pf-vdisplay.ps1 -Verify -Probe C:\t-goal1\debug\punktfunk-probe.exe
#>
[CmdletBinding()]
param(
[string]$Service = 'PunktfunkHost',
[string]$AdapterName = 'punktfunk Virtual Display',
[string]$GhostMatch = 'punktfunk',
[switch]$KeepGhosts,
[switch]$NoHost,
[switch]$Verify,
[string]$Probe
)
$ErrorActionPreference = 'Continue'
function Get-PfAdapter {
Get-PnpDevice -Class Display -ErrorAction SilentlyContinue |
Where-Object { $_.FriendlyName -match $AdapterName } | Select-Object -First 1
}
# 1) Stop the host so it isn't mid-IOCTL during the reset (it holds the control device).
$svc = Get-Service $Service -ErrorAction SilentlyContinue
$hostWasRunning = $svc -and $svc.Status -eq 'Running'
if (-not $NoHost -and $hostWasRunning) {
Write-Host "==> stopping $Service"
Stop-Service $Service -Force
Start-Sleep -Seconds 2
}
# 2) Reap the ghost (not-present) punktfunk virtual-monitor device nodes.
if (-not $KeepGhosts) {
$ghosts = Get-PnpDevice -Class Monitor -ErrorAction SilentlyContinue |
Where-Object { $_.Status -ne 'OK' -and $_.FriendlyName -match $GhostMatch }
Write-Host "==> removing $($ghosts.Count) ghost virtual-monitor node(s)"
$removed = 0
foreach ($g in $ghosts) {
pnputil /remove-device $g.InstanceId *> $null
if ($LASTEXITCODE -eq 0) { $removed++ }
}
Write-Host " removed $removed"
}
# 3) Reload the IddCx adapter instance (disable + enable) to clear its monitor list.
$ad = Get-PfAdapter
if (-not $ad) {
Write-Warning "pf-vdisplay adapter '$AdapterName' not found (Class Display) — is the driver installed?"
}
else {
Write-Host "==> cycling adapter $($ad.InstanceId)"
Disable-PnpDevice -InstanceId $ad.InstanceId -Confirm:$false -ErrorAction Continue
Start-Sleep -Seconds 3
Enable-PnpDevice -InstanceId $ad.InstanceId -Confirm:$false -ErrorAction Continue
Start-Sleep -Seconds 3
$st = (Get-PnpDevice -InstanceId $ad.InstanceId -ErrorAction SilentlyContinue).Status
if ($st -ne 'OK') {
# One retry — a disabled root device occasionally needs a second enable to come back OK.
Enable-PnpDevice -InstanceId $ad.InstanceId -Confirm:$false -ErrorAction Continue
Start-Sleep -Seconds 2
$st = (Get-PnpDevice -InstanceId $ad.InstanceId -ErrorAction SilentlyContinue).Status
}
Write-Host " adapter status: $st"
}
# 4) Restart the host.
if (-not $NoHost -and $svc) {
Write-Host "==> starting $Service"
Start-Service $Service
Start-Sleep -Seconds 3
Write-Host " $Service status: $((Get-Service $Service -ErrorAction SilentlyContinue).Status)"
}
# 5) Optional: probe to confirm ADD recovers.
if ($Verify) {
if (-not $Probe) {
$Probe = (Get-Command punktfunk-probe.exe -ErrorAction SilentlyContinue).Source
}
if (-not $Probe -or -not (Test-Path $Probe)) {
Write-Warning "-Verify: punktfunk-probe.exe not found (pass -Probe <path>); skipping verification."
}
else {
$log = Join-Path $env:ProgramData 'punktfunk\logs\host.log'
Write-Host "==> verifying with $Probe"
& $Probe *> $null
Start-Sleep -Seconds 2
$last = Get-Content $log -Tail 80 -ErrorAction SilentlyContinue |
Select-String -Pattern 'pf-vdisplay created|Element nicht|0x80070490' | Select-Object -Last 1
if ($last -match 'created') { Write-Host " OK: ADD succeeded after reset." }
elseif ($last) { Write-Warning " ADD still failing after reset: $($last.Line.Trim())" }
else { Write-Warning " no ADD outcome found in the log; check $log." }
}
}
Write-Host "pf-vdisplay reset done."