Created
September 14, 2026 13:09
-
-
Save cyrex562/87890710fa3fe95bfd5b5193c43b782f to your computer and use it in GitHub Desktop.
Powershell ssh-copy-id and ssh config tab complete add-ons to the `$PROFILE`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Linux-like SSH utilities and autocomplete configuration for Windows PowerShell. | |
| .DESCRIPTION | |
| Adds tab completion for 'ssh', 'scp', 'sftp', and 'ssh-copy-id' by reading your ~/.ssh/config. | |
| Also implements a native PowerShell wrapper function for 'ssh-copy-id'. | |
| .USAGE | |
| Paste this entire script block into your PowerShell profile. | |
| To open your profile, run: notepad $PROFILE | |
| #> | |
| using namespace System.Management.Automation | |
| # Helper function to parse Host entries from ssh config | |
| function Get-Hosts($configFile) { | |
| if (Test-Path $configFile) { | |
| Get-Content $configFile ` | |
| | Select-String -Pattern "^Host " ` | |
| | ForEach-Object { $_ -replace "(?i)^host\s+", "" } ` | |
| | ForEach-Object { $_ -split "\s+" } ` | |
| | Where-Object { $_ -notmatch '[*?]' } ` | |
| | Sort-Object -Unique | |
| } | |
| } | |
| # Native Windows port of the Linux ssh-copy-id script | |
| function ssh-copy-id { | |
| param( | |
| [Parameter(Mandatory=$true, Position=0)] | |
| [string]$UserAtMachine, | |
| [Parameter(Mandatory=$false)] | |
| [string]$KeyPath = "$env:USERPROFILE\.ssh\id_rsa.pub" | |
| ) | |
| # Fall back to ed25519 if default RSA doesn't exist | |
| if (-not (Test-Path $KeyPath)) { | |
| $KeyPath = "$env:USERPROFILE\.ssh\id_ed25519.pub" | |
| } | |
| if (-not (Test-Path $KeyPath)) { | |
| Write-Error "ERROR: Could not find a public key file at $env:USERPROFILE\.ssh\ (checked id_rsa.pub and id_ed25519.pub)" | |
| return | |
| } | |
| Write-Host "Copying key $KeyPath to $UserAtMachine..." -ForegroundColor Cyan | |
| # Securely append public key to remote host | |
| Get-Content $KeyPath -Raw | ssh $UserAtMachine "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" | |
| } | |
| # Register the interactive Tab-Completer for all SSH commands | |
| Register-ArgumentCompleter -CommandName ssh, scp, sftp, ssh-copy-id -Native -ScriptBlock { | |
| param($wordToComplete, $commandAst, $cursorPosition) | |
| $sshDir = "${Env:USERPROFILE}\.ssh" | |
| $hosts = @() | |
| # Parse master config | |
| if (Test-Path "$sshDir\config") { | |
| $hosts += Get-Hosts "$sshDir\config" | |
| # Traverse any external 'Include' directives | |
| Get-Content "$sshDir\config" ` | |
| | Select-String -Pattern "^Include " ` | |
| | ForEach-Object { $_ -replace "(?i)^include\s+", "" } ` | |
| | ForEach-Object { Get-Hosts "$sshDir/$_" } | |
| } | |
| $hosts = $hosts | Sort-Object -Unique | |
| $textToComplete = $wordToComplete | |
| $generateCompletionText = { param($x) $x } | |
| # Retain custom username prefix if typed (e.g., admin@ho[TAB]) | |
| if ($wordToComplete -match "^(?<user>[-\w/\\\\]+)@(?<host>[-.\w]*)$") { | |
| $textToComplete = $Matches["host"] | |
| $generateCompletionText = { param($hostname) $Matches["user"] + "@" + $hostname } | |
| } | |
| $hosts ` | |
| | Where-Object { $_ -like "${textToComplete}*" } ` | |
| | ForEach-Object { [CompletionResult]::new((&$generateCompletionText($_)), $_, [CompletionResultType]::ParameterValue, $_) } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment