Using PowerShell over SSH, Twenty Years Later

influx1 pts0 comments

PowerShell over SSH in 2026: OpenSSH on Windows, Key Auth, and PowerShell 7 Remoting | Matt Michie Twenty years ago this month I published instructions for wiring PowerShell to SSH with Cygwin. It involved a mirror hunt, an environment variable named ntsec, and a shell that gave you no prompt and no output when it started. The post ended with a plea to Microsoft: just use SSH. “Please don’t invent a proprietary Microsoft only tool to do this. Please please please please!”

They invented the proprietary tool anyway (WinRM), and for a while my Cygwin kludge was the #1 Google result for “PowerShell SSH”, which says more about the state of the ecosystem in 2008 than about the post. But the story has a good ending: Microsoft joined OpenSSH development, shipped it in Windows 10 in 2018, and as of Windows Server 2025 the SSH server is preinstalled on every box. The begging worked. It only took twelve years.

Here is the current state of PowerShell and SSH, as of mid-2026. This is the guide I wish had existed at any point in the last two decades.

What Ships Where

The OpenSSH client (ssh, scp, sftp, ssh-keygen, ssh-agent) has been in the box since Windows 10 build 1809 and Windows Server 2019. If you are on anything modern, typing ssh in a terminal just works. No PuTTY required (pour one out for a faithful friend).

The OpenSSH server is where the 2025 change landed: on Windows Server 2025, sshd is preinstalled. The service is present but stopped until you start it. On Windows 10, 11, Server 2019, and 2022 it remains an optional capability:

# Only needed before Server 2025<br>Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# Everywhere: start it and keep it started<br>Start-Service sshd<br>Set-Service -Name sshd -StartupType Automatic<br>The firewall rule for port 22 is created automatically when the capability is installed. The in-box build trails upstream OpenSSH; if you want current releases, the Win32-OpenSSH project ships standalone MSIs, including a 10.0 preview that picks up upstream’s post-quantum key exchange (mlkem768x25519-sha256). Yes: the operating system I once had to trick into running a remote shell now ships quantum-resistant key agreement. It is allowed to feel a little vertiginous.

Make SSH Drop You Into PowerShell

Out of the box, sshing into a Windows machine lands you in cmd.exe, which is a time machine with none of the charm. The default shell is a registry value:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" `<br>-Name DefaultShell `<br>-Value "C:\Program Files\PowerShell\7\pwsh.exe" `<br>-PropertyType String -Force<br>Point it at PowerShell 7 (pwsh.exe), not Windows PowerShell 5.1. PowerShell 7.6 is the current LTS release, it is a separate install from the OS, and everything below assumes it.

Keys, and the Gotcha That Bites Everyone

ssh-keygen on Windows defaults to Ed25519 now. Generate a key, then put the agent to work. The agent service exists on every modern Windows machine and is disabled by default, which is why nobody knows it exists:

# Run as administrator, once<br>Get-Service ssh-agent | Set-Service -StartupType Automatic<br>Start-Service ssh-agent

# As yourself<br>ssh-keygen -t ed25519<br>ssh-add $env:USERPROFILE\.ssh\id_ed25519<br>Deploying the public key to a Windows server is where confident assumptions go to die. For a standard user, the key goes where Unix habits expect: C:\Users\username\.ssh\authorized_keys. But if the account is a member of the Administrators group, sshd ignores that file entirely and reads C:\ProgramData\ssh\administrators_authorized_keys instead. And that file must have a locked-down ACL (SYSTEM and Administrators only), or key authentication silently fails and you fall back to password prompts with no explanation.

There is no ssh-copy-id on Windows. This pair of lines is the equivalent for an admin account, ACL fix included:

$authorizedKey = Get-Content -Path $env:USERPROFILE\.ssh\id_ed25519.pub

ssh username@hostname "powershell Add-Content -Force -Path $env:ProgramData\ssh\administrators_authorized_keys -Value '$authorizedKey'; icacls.exe ""$env:ProgramData\ssh\administrators_authorized_keys"" /inheritance:r /grant ""Administrators:F"" /grant ""SYSTEM:F"""<br>If key auth ever works from one account and not another on the same box, this split is almost always why. It cost me an afternoon before it became a reflex.

PowerShell Remoting over SSH

This is the part 2006 me was actually asking for. PowerShell 7’s Enter-PSSession, New-PSSession, and Invoke-Command all take SSH parameters, and they work across Windows, Linux, and macOS in any direction:

# Interactive session<br>Enter-PSSession -HostName server01 -UserName matt

# One-shot command with key auth<br>Invoke-Command -HostName server01 -UserName matt `<br>-KeyFilePath ~\.ssh\id_ed25519 `<br>-ScriptBlock { Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 }

# Persistent session<br>$s = New-PSSession -HostName server01 -UserName matt<br>Invoke-Command -Session $s -ScriptBlock { Get-Service sshd }<br>Unlike plain...

powershell windows server openssh service please

Related Articles