Configure SSH Key Authentication for an Administrator on Windows Server with PowerShell
Windows OpenSSH ignores an administrator’s authorized_keys. Put the key in administrators_authorized_keys with the right ACL, scripted for a fresh server.

On this page
TL;DR
For any account in the local Administrators group, the public key goes in one
shared file, and that file must be accessible only by Administrators and SYSTEM.
In an elevated PowerShell session on the server, with your public key in
$publicKey:
$authorizedKeys = "$env:ProgramData\ssh\administrators_authorized_keys"
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
icacls.exe $authorizedKeys /inheritance:r /grant 'Administrators:F' /grant 'SYSTEM:F'Then from the client:
$ ssh -i ~/.ssh/id_ed25519 Administrator@server-addressNo password prompt means it worked. A non-administrator account uses
~\.ssh\authorized_keys as on any other OpenSSH server and needs none of this.
The OpenSSH port for Windows makes one deliberate departure from the
sshd_config defaults you know. Its stock configuration ends with:
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keysSo for an administrator, the per-user authorized_keys is never consulted, and
ssh-copy-id — which doesn’t exist on Windows anyway — would put the key in
a file sshd never reads. The key goes in the shared file, and sshd ignores that
file without saying why if an ordinary user can write to it.
Generate a key pair on the client
If you do not already have one:
$ ssh-keygen -t ed25519Take the defaults. Key formats, ssh-keygen and the rest of the client side
are unmodified OpenSSH, so a key you already use elsewhere works here too. The
public half is ~/.ssh/id_ed25519.pub, one line beginning ssh-ed25519.
That line is what the server needs; the private half never leaves the client.
Get the public key onto the server
Pick whichever route reaches the server. In a password-authenticated SSH session, or an RDP session, paste the one line into a variable on the server:
# Paste the whole public key line between the quotes.
$publicKey = 'ssh-ed25519 AAAA... you@laptop'Or, from the client, copy the line in one step, which avoids pasting a long line through a terminal:
$ scp ~/.ssh/id_ed25519.pub Administrator@server-address:id_ed25519.puband on the server:
$publicKey = Get-Content "$env:USERPROFILE\id_ed25519.pub"Write the key and fix the permissions
$sshDir = "$env:ProgramData\ssh"
$authorizedKeys = "$sshDir\administrators_authorized_keys"
if (-not (Test-Path $sshDir)) {
New-Item -ItemType Directory -Path $sshDir | Out-Null
}
Add-Content -Path $authorizedKeys -Value $publicKey -Encoding ascii
icacls.exe $authorizedKeys /inheritance:r /grant 'Administrators:F' /grant 'SYSTEM:F'Add-Content creates the file if it is missing and appends if it is not, so
the same lines add a second administrator’s key later. -Encoding ascii is
not decoration: see the first common failure.
/inheritance:r strips the inherited entries. The two /grant entries put
back the only two principals Microsoft’s documentation allows on this file.
sshd’s own permission check is looser, and rejects the file only when another
account has write access. Confirm:
icacls.exe $authorizedKeysThe output should list exactly BUILTIN\Administrators:(F) and
NT AUTHORITY\SYSTEM:(F).
Test from the client
sshd reads the keys file at every sign-in, so no restart is needed. From the client:
$ ssh -i ~/.ssh/id_ed25519 Administrator@server-addressExpected result
You’re signed in without a password prompt. Once that holds for every account
that needs access, turn password authentication off in
C:\ProgramData\ssh\sshd_config:
PasswordAuthentication noand restart the service, which reads sshd_config only when it starts. Leave
password authentication on until the key login is confirmed, or you’ll lock
yourself out of the server you’re configuring.
Common failures
Login still asks for a password
The key is in the file and the ACL is right, but the file isn’t plain ASCII.
In Windows PowerShell 5.1, > and Out-File write UTF-16 with a byte-order
mark, and sshd can’t parse a key that starts with one. Delete the file and
write it again with Add-Content -Encoding ascii or Set-Content -Encoding ascii. Inspect a suspect file: a good file starts 73 73 68 (ssh), a bad
one starts FF FE.
Format-Hex -Path $authorizedKeys | Select-Object -First 1ACL shows extra principals after icacls
Inheritance wasn’t removed before granting. Run the /inheritance:r form
earlier, which does both steps in one call, and check again.
icacls reports no mapping for an account name
Error
No mapping between account names and security IDs was done.The Windows installation isn’t in English, and the Administrators group has a
localized name. Grant it by SID instead, with /grant '*S-1-5-32-544:F' in
place of /grant 'Administrators:F'.
Works for one account and not another
The second account isn’t an administrator. For it, the key belongs in that
user’s own C:\Users\<name>\.ssh\authorized_keys, and the shared file is
irrelevant.
Client output doesn’t explain the refusal
Ask the server. When the ACL is the cause, Server 2025 logs it under
Applications and Services Logs > OpenSSH > Operational, naming the file and
the account that can write to it. Server 2022’s OpenSSH 8.1 logs only
“Authentication refused” there; the line naming the file goes to the
OpenSSH > Debug channel, which is off by default. An encoding fault logs nothing there, so check the bytes
as described earlier. ssh -v on the client shows only that the key was
offered and declined.
Tested with
- OS
- Windows Server 2025 Datacenter (26100.33438) and Windows Server 2022 Datacenter (20348.5622)
- OpenSSH
- 9.5p2 on 2025, 8.1p1 on 2022
- Client
- OpenSSH on macOS 27
- Date
- October 2026