Skip to content

Instantly share code, notes, and snippets.

@CharlesGodwin
Last active May 1, 2024 09:12
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save CharlesGodwin/93f85838c8dbb2c4f931a3c52e598dfa to your computer and use it in GitHub Desktop.
Save CharlesGodwin/93f85838c8dbb2c4f931a3c52e598dfa to your computer and use it in GitHub Desktop.
Windows 10/11 scripts to support ssh-copy-id which is missing in Windows OpenSSH

The Windows version of OpenSSH client doesn't include a ssh-copy-id command. I don't know why. If it does one day, then this can be ignored.

NOTE If you have Windows Subsystem for Linux (WSL) installed, you can use the linux version of ssh-copy-id instead. Go to the description at the end of this document.

  • Download the file ssh-copy-id.cmd to your Windows PC, or copy and paste its contents.
  • Run the script passing your linux ssh information (for example ssh-copy-id.cmd pi@raspberrypi.local). This should work with any Linux platform. Alternatively, if you have experience, you can use the powershell version. ssh-copy-id.ps1. Run the script as powershell .\ssh-copy-id.ps1 pi@raspberrypi.local.
  • Run the command for each linux account you connect with. You will be prompted for your Linux host password. If you have more than 1 account on any machine, you must do this for each account.

The file name and location of the script is not important but the filename extension must be .cmd

If the public key is already known to the account, it will not be added again.

prerequisite

  • You have installed Microsoft's version of OpenSSH Client on your machine. Read this. You do NOT need to install SSH Server. Current versions of Windows 10 and Windows 11 have OpenSSH installed as part of the base Operating System and you do NOT need to install it.
  • You have generated a default authorize key. DO THIS ONLY ONCE. You can tell if this is done by looking in your .ssh folder. From command line type dir %userprofile%\.ssh\id_rsa.* If you find 2 files, id_rsa and id_rsa.pub, your default keys have been generated. Otherwise, run ssh-keygen Press enter for all prompts and the default keys will be generated in the correct place. ssh-keygen will warn you it is about to override exiting keys. If it does warn, answer no.

Using Windows Subsystem for Linux

If you have Windows Subsystem for Linux (WSL) installed you can use the linux version of ssh-copy-id. The command prompt version:

pushd %USERPROFILE%\.ssh & wsl ssh-copy-id -i id_rsa -F config <ssh info> & popd

The PowerShell version:

pushd $env:USERPROFILE\.ssh ; wsl ssh-copy-id -i id_rsa -F config <ssh info> ; popd

@ECHO off
@REM Provide login information
IF "%~1"=="" (
echo Missing login info as parameter
echo use %~nx0 user@hostname
exit /b 2
) else (
set SSH_TARGET=%1
)
if not exist "%userprofile%\.ssh\id_rsa" (
echo "Default authorized key does not exist. Use ssh-keygen"
exit /b 1
)
set /p PUBLIC_KEY=<"%USERPROFILE%\.ssh\id_rsa.pub"
echo umask 0077>ssh-copy-id.sh
echo mkdir -p ~/.ssh>>ssh-copy-id.sh
echo grep -q -F ^"%PUBLIC_KEY%^" ~/.ssh/authorized_keys 2^>/dev/null>>ssh-copy-id.sh
echo if [ $? -ne 0 ]>>ssh-copy-id.sh
echo then>>ssh-copy-id.sh
echo echo ^"%PUBLIC_KEY%^" ^>^> ~/.ssh/authorized_keys >>ssh-copy-id.sh
echo else>>ssh-copy-id.sh
echo echo Key already exists, no update performed.>>ssh-copy-id.sh
echo fi>>ssh-copy-id.sh
@REM The sed step is to convert crlf to lf for bash - it's fussy
TYPE ssh-copy-id.sh | ssh -o StrictHostKeyChecking=no %SSH_TARGET% "sed 's/\r//' | bash"
echo User %SSH_TARGET% Should be able to login without a password
<#
.SYNOPSIS
Copy ssh public key to remote account
.DESCRIPTION
Copies public key to target machine
Default is .ssh\id_rsa.pub
See copyright notice at end of script
If this script won't run, then run this command once
Set-ExecutionPolicy RemoteSigned CurrentUser
refer to https://go.microsoft.com/fwlink/?LinkID=135170
#>
[CmdletBinding()]
param(
[Parameter(Position = 0, Mandatory = $True)]
[string]$Target <# SSH compatible Name of Target machine #>,
[Parameter( Position = 1, Mandatory = $False)]
[string]$IdentityFile = "id_rsa" <#Identity File, must be in .ssh directory #>,
[switch]$Save = $False <# Save script used #>
)
$IdentityPath = Join-Path (Join-Path $env:USERPROFILE .ssh) $IdentityFile
if (-not (Test-Path -Path $IdentityPath -PathType Leaf)) {
Write-Host Key file $IdentityFile does not exist, use ssh-keygen
exit(1)
}
$PUBLIC_KEY = get-content "${IdentityPath}.pub"
$SCRIPT = @"
#!/bin/bash
#
PUBLIC_KEY="$PUBLIC_KEY"
umask 0077
[ -d ~/.ssh ]||mkdir -p ~/.ssh
[ -f ~/.ssh/authorized_keys ]|| touch ~/.ssh/authorized_keys
grep --quiet --fixed-strings "`$PUBLIC_KEY" ~/.ssh/authorized_keys
if [ `$? -ne 0 ]
then
echo "`$PUBLIC_KEY" >> ~/.ssh/authorized_keys
else
echo Key already exists, no update performed.
fi
"@
if ($Save) {
Set-Content .\ssh-copy-id.sh -Value $SCRIPT
}
# The sed step is to convert crlf to lf for bash - it's fussy
$SCRIPT | ssh $Target -o StrictHostKeyChecking=no "sed 's/\r//' | bash"
if ($?) {
Write-Output "You should be able to login to $Target without a password using $IdentityFile key"
}
else {
Write-Host "Could not connect to $Target - Terminating" -ForegroundColor Red
}
<#
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment