Those of us who use linux with keyless logins and ssh , usually find the utility ssh-copy-id as a convenient way to copy the ssh ke into the authorized keys files of the destination server. This works great on Linux systems, but windows (and also Mac) don’t have a native version fo ssh-copy-id, of course you could find scripts online that do this.. but many are overkill basically re-creating the entire ssh client in code just for the purpose of copying over a single key. Also since this is a securtity realted operation , you want to be confident those scripts are only doing what they say they’re doing.
With that said I hope to address these issues in this post and show you a quick, short and most importantly easy to modify powershell script that you can use in any modern version of Windows.
Security and Concerns
Finally there’s security concerns about using these scripts, unless you go over everly line of of code you’re never really sure what they’re doing with your key. Because of this the code velow is short, in native powershell and very easy to use, you litterally can read the code in this post and res-assured it’s only doing what it’s supposed to.
SSH-COPY-ID in Powershell
Windows Powershell is the defacto Widnows command line programming language replacing the traditional DOS batch files, and has been in available since around Windows 7 (circa 2007) . You can find a useful Powershell cheat sheet here:
param ( [Parameter(Mandatory=$true)] [string]$connectionString, [Parameter(Mandatory=$true)] [string]$publicKeyFile ) $connectionParts = $connectionString.Split('@') if ($connectionParts.Length -ne 2) { throw "Invalid connection string format. Must be in the format 'user@hostname:port'" } $username = $connectionParts[0] $hostParts = $connectionParts[1].Split(':') $hostname = $hostParts[0] if ($hostParts.Length -gt 1) { $port = $hostParts[1] } else { $port = 22 } $sshDir = "$env:USERPROFILE\.ssh" if (!(Test-Path -Path $sshDir)) { New-Item -ItemType Directory -Path $sshDir | Out-Null } $sshPubKey = Get-Content $publicKeyFile $sshPubKeyFileName = Split-Path $publicKeyFile -Leaf $sshAuthorizedKeysFile = "$sshDir\authorized_keys" $sshConnection = New-SSHSession -ComputerName $hostname -Credential $username -Port $port $sshAuthorizedKeys = Invoke-SSHCommand -SessionId $sshConnection.SessionId -Command "cat $sshAuthorizedKeysFile" | Select-Object -ExpandProperty Output if ($sshAuthorizedKeys -notcontains $sshPubKey) { Invoke-SSHCommand -SessionId $sshConnection.SessionId -Command "echo `"$sshPubKey`" >> $sshAuthorizedKeysFile" } Write-Output "Public key added to $hostname authorized_keys file" ?
This script requires the New-SSHSession
and Invoke-SSHCommand
cmdlets, which are available in the PowershellSSH
module. You can install this module by running Install-Module -Name PowershellSSH
.
How it works
The script takes three parameters: the username on the remote host, the hostname or IP address of the remote host, and the path to the public key file. The script then creates the ~/.ssh
directory on the remote host if it doesn’t exist, reads the public key from the specified file, and adds it to the authorized_keys
file on the remote host if it’s not already there. Finally, the script outputs a message indicating that the public key was added to the authorized_keys
file.
To use this script, save it to a file with a .ps1
extension, and then run it with the required parameters. For example:
.\ssh-copy-id.ps1 user@remotehost:port -publicKeyFile C:\Users\myuser\.ssh\id_rsa.pub