Skip to content

Instantly share code, notes, and snippets.

@NQevxvEtg
Last active July 30, 2025 17:04
Show Gist options
  • Select an option

  • Save NQevxvEtg/dc3f08c773c06d4d690c99b544f68bea to your computer and use it in GitHub Desktop.

Select an option

Save NQevxvEtg/dc3f08c773c06d4d690c99b544f68bea to your computer and use it in GitHub Desktop.
sshcopyid
#!/usr/bin/env expect -f
# Prompt for SSH password once
stty -echo
send_user "Enter SSH password: "
expect_user -re "(.*)\n"
stty echo
send_user "\n"
set ssh_password $expect_out(1,string)
set timeout 15
set hostfile [lindex $argv 0]
set username [lindex $argv 1]
set keyfile [file normalize "~/.ssh/id_rsa.pub"]
set key [exec cat $keyfile]
set key [string trim $key]
# Escape double quotes etc.
set key [string map {\a \\a \b \\b \\n \\\n \" \\\"} $key]
set ok 0
set bad 0
set total 0
# For summary
array set success {}
array set failure {}
set fh [open $hostfile r]
while {[gets $fh line] >= 0} {
set host [string trim $line]
if {$host eq ""} continue
incr total
set target [expr {[regexp {@} $host] ? $host : "$username@$host"}]
send_user "\n>>> Processing $target\n"
# Step 0: Check if key already exists
spawn ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new \
$target "grep -Fxq \"$key\" ~/.ssh/authorized_keys"
expect {
-re "assword:" {
send "$ssh_password\r"
exp_continue
}
timeout {
send_user "✗ $target timeout during key check\n"
incr bad
set failure($target) "timeout during key check"
continue
}
eof {
set exit_status [lindex [wait] 3]
if {$exit_status == 0} {
send_user "✓ $target already has key — skipping\n"
incr ok
set success($target) "already authorized"
continue
}
}
}
# Step 1: Ensure ~/.ssh exists
spawn ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=accept-new \
$target "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
expect {
-re "assword:" {
send "$ssh_password\r"
exp_continue
}
timeout {
send_user "✗ $target timeout during mkdir\n"
incr bad
set failure($target) "timeout during mkdir"
continue
}
eof {}
}
# Step 2: Copy key
spawn scp -o ConnectTimeout=8 ~/.ssh/id_rsa.pub $target:/tmp/mykey.pub
expect {
-re "assword:" {
send "$ssh_password\r"
exp_continue
}
timeout {
send_user "✗ $target timeout during SCP\n"
incr bad
set failure($target) "timeout during SCP"
continue
}
eof {}
}
# Step 3: Append key
spawn ssh -o ConnectTimeout=8 $target \
"cat /tmp/mykey.pub >> ~/.ssh/authorized_keys && \
chmod 600 ~/.ssh/authorized_keys && rm /tmp/mykey.pub"
expect {
-re "assword:" {
send "$ssh_password\r"
exp_continue
}
timeout {
send_user "✗ $target timeout during key install\n"
incr bad
set failure($target) "timeout during key install"
continue
}
eof {
send_user "✓ $target key installed\n"
incr ok
set success($target) "key installed"
}
}
}
close $fh
# Final Summary
send_user "\n========== SUMMARY ==========\n"
send_user "✅ Success : $ok\n"
foreach host [array names success] {
send_user " - $host : $success($host)\n"
}
send_user "\n❌ Failed : $bad\n"
foreach host [array names failure] {
send_user " - $host : $failure($host)\n"
}
send_user "\n📋 Total : $total\n"
send_user "=============================\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment