Loosely Decoupled
GuideSSHPowerShell

How to Enable SSH on Windows 11 Pro with PowerShell

Sign in to a Windows 11 Pro machine over SSH with a password, then a key, using PowerShell alone.

A pigeon in a hard hat with a clipboard eyes a latched garden gate standing in front of a newly fitted hatch in a tall cabinet, whose lock holds a cyan key.
On this page

TL;DR

In an elevated PowerShell session on the Windows 11 machine, install the OpenSSH server, start it, and check which network category the machine is on:

PowerShell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd
Get-NetConnectionProfile | Format-Table InterfaceAlias, NetworkCategory

The firewall rule the install creates covers Private networks only, so on a network marked Public, SSH times out. Only if the last command shows Public, widen the rule. This opens port 22 on every Public and Private network the machine joins:

PowerShell
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Profile Public, Private

Windows 11 doesn’t ship the server, and the install took about half an hour on the test machines. For an administrator account, put the public key in C:\ProgramData\ssh\administrators_authorized_keys; a key in the user’s own authorized_keys is refused. With no AllowGroups line, any local account can sign in with its password, not only Administrators and OpenSSH Users as on Server 2025.

The Server 2025 article starts from a machine that already has the OpenSSH server on the image. Windows 11 doesn’t, and a few other defaults differ too. I ran the same setup on Windows 11 26H2 Pro to find out where.

Install the OpenSSH server capability

Windows 11 includes the OpenSSH client and leaves the server out. Check what is present:

PowerShell
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' |
    Format-Table Name, State

OpenSSH.Client reads Installed and OpenSSH.Server reads NotPresent. Install the server:

PowerShell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

The command downloads the capability and returns when it finishes. It took about half an hour on the test machines, with no restart needed. Only the total was measured, and a Feature on Demand is downloaded during the install, so yours will differ.

When it returns, OpenSSH.Server reads Installed, and C:\Windows\System32\OpenSSH\sshd.exe exists. On Arm64 the server and client binaries are native Arm64, and every step here behaved the same.

Note

On this build, Get-ComputerInfo and the registry report the product as Windows 10 Pro. That registry value was never updated for Windows 11. A CurrentBuild of 26300 is Windows 11.

Start sshd and set it to start automatically

After the install the sshd service is stopped, and its start type is manual. Set the start type so the service survives a reboot, then start it:

PowerShell
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd
Get-Service -Name sshd | Format-Table Name, Status, StartType

The first start writes sshd_config and the host keys to C:\ProgramData\ssh\. The directory is empty until then, and the host keys are generated on this machine.

Confirm that the service is listening:

PowerShell
Get-NetTCPConnection -LocalPort 22 -State Listen

Get-Service reads Running and Automatic, and port 22 is listening on 0.0.0.0 and ::.

Allow the firewall rule on public networks

The install creates the rule OpenSSH-Server-In-TCP, enabled, for the Private profile only. Check which profile the network is on:

PowerShell
Get-NetConnectionProfile | Format-Table InterfaceAlias, NetworkCategory

The test machines read Public, which the stock rule doesn’t cover. The firewall drops the packets, so a client waits and times out rather than being refused. The next command changes the rule to apply on Public and Private networks. -Profile replaces the rule’s list, so name both:

PowerShell
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Profile Public, Private
Get-NetFirewallRule -Name OpenSSH-Server-In-TCP | Format-Table Name, Enabled, Profile

Profile reads Private, Public.

I didn’t test a domain-joined machine. Its network profile is DomainAuthenticated, which the rule as changed here doesn’t list.

Caution

The rule now accepts connections to port 22 on any Public or Private network the machine joins. On a machine with a public address, restrict inbound port 22 with a network firewall in front of it.

Sign in with a password

On the other machine, connect with the name and password of a local account on the Windows 11 machine:

Command
$ ssh <user>@<address> 'ver & whoami'

Output


Microsoft Windows [Version 10.0.26300.9711]
<computer>\<user>

Accept the host key when asked, then enter the account’s password. Without the trailing command, ssh opens an interactive session in cmd.exe, which is the default shell for Windows OpenSSH, as on Server.

Put an administrator’s key in administrators_authorized_keys

For a member of the Administrators group, sshd reads only C:\ProgramData\ssh\administrators_authorized_keys, and the install doesn’t create it. A key in C:\Users\<user>\.ssh\authorized_keys is refused. The Match Group administrators block in the generated sshd_config sets this.

That one file serves every administrator on the machine, so a key in it signs in as any of them, not only the account you meant. If several people administer the machine and need separate keys, this setup doesn’t give them that.

On the other machine, create the key pair and print the public key:

Command
$ ssh-keygen -t ed25519 -f ~/.ssh/<key-name>
$ cat ~/.ssh/<key-name>.pub

In an elevated PowerShell session on the Windows 11 machine, set $publicKey = '<paste the line>', then run this block. It replaces any content in the file and removes inherited permissions so that only Administrators and SYSTEM can access it:

PowerShell
$authorizedKeys = 'C:\ProgramData\ssh\administrators_authorized_keys'

Set-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
icacls.exe $authorizedKeys /inheritance:r /grant '*S-1-5-32-544:F' /grant 'SYSTEM:F'
icacls.exe $authorizedKeys

The second icacls.exe lists NT AUTHORITY\SYSTEM:(F) and BUILTIN\Administrators:(F) and nothing else. *S-1-5-32-544 names the built-in Administrators group by its SID, so the grant works on a Windows installation where the group’s name is translated.

Test it from the other machine with password and keyboard-interactive sign-in switched off for this attempt, so only the key can succeed:

Command
$ ssh -i ~/.ssh/<key-name> -o IdentitiesOnly=yes -o PasswordAuthentication=no \
>   -o KbdInteractiveAuthentication=no <user>@<address> whoami

Output

<computer>\<user>

Who can sign in without an AllowGroups line

On Server 2025 the sshd_config that ships on the image limits SSH to the Administrators group and the OpenSSH Users group. On Windows 11 it has no AllowGroups line. The OpenSSH Users group exists and has no members, and it restricts nothing.

A standard user outside both groups signed in with a password, because there’s no AllowGroups line. Putting accounts in OpenSSH Users restricts nothing until sshd_config has an AllowGroups line. This matches Server 2022 rather than Server 2025; the Server 2025 article covers the setting there.

Common failures

Connection times out

Error

ssh: connect to host <ip> port 22: Operation timed out

Check the category with Get-NetConnectionProfile. On Public, widen the rule:

PowerShell
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Profile Public, Private

If the rule already covers the category, look for a firewall between the two machines.

Permission denied with a key

Error

<user>@<ip>: Permission denied (publickey,password,keyboard-interactive).

For an administrator, the key sits in the user’s own authorized_keys instead of administrators_authorized_keys, or the file doesn’t exist. Append the key (set $publicKey as in “Put an administrator’s key in administrators_authorized_keys”); this keeps any keys already in the file:

PowerShell
$authorizedKeys = 'C:\ProgramData\ssh\administrators_authorized_keys'
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
icacls.exe $authorizedKeys /inheritance:r /grant '*S-1-5-32-544:F' /grant 'SYSTEM:F'

Tested with

OS
Windows 11 26H2 Pro, build 26300.9711, x64 and Arm64, on cloud VMs
OpenSSH
OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2
Client
OpenSSH_10.3p1 on macOS 27.0.1
Commands
Run as SYSTEM through a cloud run-command
Accounts
Local accounts only
Not tested
Windows 11 Home, the Settings app's Optional features, a Microsoft account, a physical Arm device
Date
October 2026

New articles, by email.

A short note when something new is published.