ssh-copy-id on Windows: the PowerShell command that works

Windows has no ssh-copy-id. In PowerShell, run Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo >> ~/.ssh/authorized_keys && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys", typing your password when asked. This works for a Linux or Mac server. A Windows server needs a different command.

Updated . The one-liner ran in PowerShell 7.4 on Linux against an Ubuntu 24.04 server, and the file edge cases (line endings, UTF-16, missing newline) were tested against that server.

Copy a key to a Linux or Mac server

Run this in PowerShell on your Windows machine:

Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo >> ~/.ssh/authorized_keys && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

You type the account password once. For another port, add -p 2222 after ssh. The same command works in Command Prompt if you replace the first part with type %USERPROFILE%\.ssh\id_ed25519.pub.

Then test it. This refuses to fall back to a password, so it only succeeds if the key works:

ssh -o PasswordAuthentication=no user@server

No key yet? Create one first, as shown in how to generate an SSH key on Windows.

Why this version

Most copies of this command online skip the echo >> part. It adds an empty line first, because an existing authorized_keys may not end in a newline. Without it your key is glued to the end of the last line, and that key and yours both stop working. In our test the login was refused in that case and worked with the empty line, which the server ignores.

Three other things we checked:

  • Windows line endings. A key followed by CRLF still worked, with or without a comment, on OpenSSH 9.6.
  • UTF-16. A file in UTF-16 does not work: the login was refused. In Windows PowerShell 5.1, > and >> write UTF-16, so never create authorized_keys with them. Add-Content and the pipe above do not have this problem for a plain key.
  • Repeating. Running the command twice adds the key twice. That is harmless, but ssh-copy-id would have skipped it.

If you have Git Bash or WSL

Those are Unix environments with their own tools. Check whether the real command is there:

command -v ssh-copy-id
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

Remember that WSL has its own home folder, so its ~/.ssh is not your Windows .ssh.

Copy a key to a Windows server

The one-liner fails here, since the default shell is cmd.exe and the file location is different. The simplest way is to work on the server itself and paste the key, as shown in the OpenSSH Server guide.

To do it remotely, Microsoft documents this for a standard user:

$authorizedKey = Get-Content -Path $env:USERPROFILE\.ssh\id_ed25519.pub
$remotePowershell = "powershell New-Item -Force -ItemType Directory -Path $env:USERPROFILE\.ssh; Add-Content -Force -Path $env:USERPROFILE\.ssh\authorized_keys -Value '$authorizedKey'"
ssh user@server $remotePowershell

Note that $env:USERPROFILE inside the double quotes is filled in on your machine, before it is sent. It only lands in the right place if the profile path is the same on both, so check the result.

For a member of Administrators, the key goes in a different file with strict permissions:

$authorizedKey = Get-Content -Path $env:USERPROFILE\.ssh\id_ed25519.pub
$remotePowershell = "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"""
ssh user@server $remotePowershell

If the login still asks for a password

On Linux, look at the server's log while you try: permissions on the home folder, ~/.ssh and authorized_keys are the usual cause. See Permission denied (publickey). On a Windows server, first check whether the account is an administrator and whether you used the matching file.

Questions

Is there an ssh-copy-id for Windows?

Not in the OpenSSH client that comes with Windows. Git Bash or WSL may have the real command, which you can check with command -v ssh-copy-id. In PowerShell, pipe the public key into ssh instead.

Why does the server still ask for a password after I copied the key?

Usually the permissions on the server: the home folder, ~/.ssh and authorized_keys must not be writable by others. A key saved in UTF-16 or glued to the previous line also fails. Watch the server log while you try.

Where does the public key go on a Windows server?

For a standard user, in .ssh\authorized_keys in the user's profile. For a member of Administrators, in C:\ProgramData\ssh\administrators_authorized_keys, readable only by Administrators and SYSTEM.

Sources

More in SSH on each system

All guides