Skip to content

v0.3.2 — first working release

Choose a tag to compare

@djdarcy djdarcy released this 08 Jul 05:53
v0.3.2
76c4306

wtf-rdp v0.3.2 — first working release

Rescue the RDP session Windows would make you destroy.

wtf-rdp is a Windows RDP session-rescue CLI (rdp) in the wtf-windows family, built on the DazzleCMD pattern. It detects and non-destructively recovers RDP/console sessions wedged or blocked by Local Session Manager (LSM) — the "You're unable to sign in because you're already signed in to another session that is blocked" failure that otherwise forces you to sign the session out and lose your work.

This is the first release that works from a plain pip install — 0.3.0/0.3.1 shipped the tool scripts but not their manifests, so the installed CLI found no tools (see the fix note below). If you tried an earlier version, upgrade: pip install --upgrade wtf-rdp.

The problem it solves

An ungraceful mstsc disconnect can leave your session flagged "blocked by Local Session Manager." From then on Windows refuses every sign-in (RDP and including the physical console) and the only button it offers is the one that signs the session out and throws away everything running in it. The block counter climbs and never expires, and on client Windows (a single interactive session) you can't even open a second session to fix it. Remote fixes (tscon, restarting TermService, rwinsta) are typically blocked by remote-UAC token filtering. The usual "recovery" destroys exactly the work you were trying to save.

How it works

  • The failure — a dirty RDP disconnect leaves the session in a corrupted "wedge"; LSM marks it blocked and refuses new sign-ins.
  • Detection — a wedge looks, to a naive check, like a healthy machine at its login screen, so wtf-rdp does not act on "a session is disconnected." It watches for the real signature: a console session stuck connecting, corroborated by the LSM transition-failure event a dirty disconnect emits, persisting past a short confirm window. Normal idle disconnects never trigger it.
  • Recovery — it reconnects the stranded session to the console with tscon and then locks it, so your running work survives and the box is never left with an open desktop.
  • Where it runs — a small PowerShell watchdog hosted by NSSM as a LocalSystem service. Because it runs as SYSTEM it inherently holds the SeTcbPrivilege that tscon needs, so recovery works with no change to the machine's admin/token model (no LocalAccountTokenFilterPolicy, no enabled built-in Administrator), and it can act autonomously with nobody logged in — which is the point, since the wedge is exactly what locks you out.

The sessfix kit — seven tools

Install/operate wtf-rdp on the RDP host (the machine that wedges — the one you connect into). The machine you connect from just uses mstsc as usual.

Tool What it does
rdp status Watchdog service state + recent rescues + live session table
rdp query Enumerate sessions; flag Stranded / WedgeSignal candidates (-Json)
rdp install Deploy + start the LocalSystem watchdog (downloads a checksum-verified NSSM)
rdp recover Manual one-shot reconnect + lock now; self-elevates to SYSTEM
rdp logs View the watchdog log (-Tail / -Follow / -Full)
rdp config Show / change poll interval, wedge-confirm window, target user
rdp uninstall Stop + remove the service (-Purge also deletes the install dir)

Every tool answers -h / -help / --help / /?.

Installation

pip install wtf-rdp

On externally-managed Python (PEP 668), use a venv or pipx install wtf-rdp. Requires Windows and Python 3.10+.

Getting started

In an elevated PowerShell on the RDP host:

# Deploy + start the watchdog, scoped to just your account so it only ever
# acts on your session. (Omit -TargetUser to rescue any stranded session.)
rdp install -TargetUser $env:USERNAME

# Confirm it's Running as SYSTEM and see the live session table
rdp status

That's the whole setup — it now runs across reboots and will reconnect + lock your session if it wedges. Day to day:

rdp query                      # flag stranded / wedge candidates
rdp logs -Follow               # watch the watchdog live
rdp recover                    # force a reconnect + lock right now
rdp config -PollIntervalSec 10 # tune how often it checks (restarts the service)

What's New / Fixed in v0.3.2

Fixed: the installed wheel now finds its tools (#1)

The per-tool manifests are named .wtf-rdp.json (leading dot), and setuptools' * glob skips dotfiles — so package-data's tools/**/* shipped every .ps1 but silently dropped every manifest that dispatches them. The result: pip install wtf-rdp"No tools found" and rdp install reported an invalid choice, even though the source/editable checkout worked. Fixed by packaging the dotfile manifests explicitly, with a regression test to guard it. Verified end to end: rebuilt the wheel, installed it into a clean venv, and rdp list reports all 7 tools.

Everything from 0.3.0 (the query/logs/config tools, universal -h, the rdp -h epilog, checksum-verified NSSM pinned by default) and 0.3.1 (manual workflow_dispatch on the release workflow) is included — this is the first build where it's actually usable after pip install.

Version History (0.3.x)

Version Key Change
v0.3.2 Current — first working wheel: package the .wtf-rdp.json tool manifests
v0.3.1 First public release + manual workflow_dispatch (wheel was missing tool manifests)
v0.3.0 sessfix query/logs/config, universal -h, verified NSSM pin (source-only)
v0.2.0 install / recover / uninstall + lock-after-rescue; shared session module
v0.1.0 Aggregator scaffold (rdp) + sessfix status; validated watchdog

Platform Support

Platform Status
Windows 11 Tested
Windows 10 Expected to work

The rdp CLI is Python and installs anywhere, but the sessfix tools are Windows-only (they no-op / warn off-Windows).

Requirements

  • Python 3.10+
  • Windows (for the sessfix session-rescue tools)
  • Administrator (elevated shell) for install / recover / uninstall / config writes