A tiny Windows GUI for %USERPROFILE%\.ssh\config.
Make a host, generate a key, pick a jump host, press Connect. That is the whole program.
- Your config file is the database. SSHDesk edits
~/.ssh/configand nothing else. Everything it writes, plainsshreads — and so does VS Code, WinSCP, git, rsync, and anything else on the machine. Delete SSHDesk and you lose nothing. - It keeps what you wrote. Comments,
Include,Match, and any directive it does not know are preserved exactly. Editing one host does not rewrite the rest. - No install. Two files, ~450 lines of PowerShell. No .NET SDK, no Python, no Node, no service, no telemetry. Windows 10/11 already has everything it needs.
The window opens with the order of operations across the top — 1. name and address → 2. make a key → 3. register it on the server → 4. connect — and every field explains itself in one line as you touch it: what an address is, that the login name belongs to the server rather than to your PC, that the port is usually 22, that a key file is the thing that replaces your password.
Nothing is jargon-first: the labels say Name, Address, Login name,
Key file, and Connect through rather than ProxyJump. The config it writes is
still exactly what ssh expects.
Download SSHDesk.ps1 and SSHDesk.cmd into the same folder, then run
SSHDesk.cmd.
That is it. (Or clone the repo and run the same file.)
| Hosts | alias, HostName, User, Port, IdentityFile, IdentitiesOnly, ServerAliveInterval, plus a free-text box for anything else — ForwardAgent, SetEnv, RemoteForward and friends keep their own lines there |
| Jump hosts | Connect through — pick one of your other hosts as the stepping stone. The full route is drawn underneath (this PC → edge → web → db), walked through the config, so a stone standing behind another stone is visible rather than implied. Loops are cut off instead of hung on |
| Keys | generate ed25519 key pairs, copy the public key, and fix the Windows ACL (icacls) so OpenSSH stops refusing the key. A key that already exists is never overwritten — you are asked whether to reuse it or make one under a new name |
| Register on server | puts your public key into ~/.ssh/authorized_keys on the server, over ssh — the ssh-copy-id that Windows OpenSSH does not ship. You choose add (keeps the keys already there) or replace (this key becomes the only one, with a second warning, because it locks every other machine out). Not the same as Copy public key, which only fills your clipboard |
| Test | BatchMode probe that tells you which thing is wrong: name resolution, refused port, timeout, or key rejected |
| Connect | opens Windows Terminal (or PowerShell) with ssh <alias> |
- Every save copies the previous file to
config.bak-YYYYMMDD-HHmmssfirst. - Emptying a field removes the directive; it never leaves a dangling key.
- Private keys are never overwritten: an existing one is reused or a new name is taken.
- Duplicate host aliases are flagged —
sshsilently uses the first match, so the second one would never apply. - Generated private keys get
icacls /inheritance:r /grant:r <you>:F. This is the Windows equivalent ofchmod 600, and without it OpenSSH refuses to use the key.
19 out of the box: English, 日本語, 简体中文, 繁體中文, 한국어, Español, Português (Brasil), Français, Deutsch, Italiano, Nederlands, Polski, Русский, Türkçe, Bahasa Indonesia, Tiếng Việt, ไทย, العربية, हिन्दी.
The interface follows your Windows display language on first run (pt-BR and
zh-TW resolve correctly), and there is a picker in the top right if you want a
different one — the choice is remembered in %APPDATA%\SSHDesk\settings.json.
Right-to-left languages get a mirrored layout.
Each language is one file in lang\. Copy lang\en.json, translate the values,
keep the {0} placeholders, then:
powershell -NoProfile -ExecutionPolicy Bypass -File tools\build-lang.ps1That embeds the files back into SSHDesk.ps1 so the single-file download still
speaks every language. A missing key falls back to English, one string at a time.
⚠ SSHDesk.ps1 must stay UTF-8 with BOM — Windows PowerShell 5.1 reads a
.ps1 as ANSI without it, and every non-Latin string turns to mojibake. The
build tool checks this.
Windows 10 or 11 with the built-in OpenSSH client (ssh.exe, ssh-keygen.exe).
Windows PowerShell 5.1 — already there. Windows Terminal is used when present.
powershell -NoProfile -ExecutionPolicy Bypass -File tests\roundtrip.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File tests\i18n.ps1The first round-trips a config through the parser and writer and asserts that
comments, global options, and unknown directives all survive. The second checks
that every language carries every key, that {0} placeholders survived
translation, and that a missing string falls back to English.
$env:SSHDESK_SMOKE = '1'; .\SSHDesk.ps1Builds every control, clicks through every host and every stepping stone, then exits — useful in CI, where there is no desktop. (It earns its keep: it has caught a crash on first run, a host that could be its own jump host, and a route drawn backwards.)
The screenshots above are generated the same way, from a sample config, so no real host names or user names end up in them:
$env:SSHDESK_SHOT = "$PWD\docs\screenshot.png"; .\SSHDesk.ps1A signed installer would be friendlier, but an unsigned one triggers SmartScreen, and this program handles your private keys. A single readable script you can skim in five minutes seemed like the better trade.
MIT.

