Expect script which can execute commands on multiple servers via SSH

Verze pro tiskPDF verze

This script will help Linux administrators in tasks where they need push commands on multiple servers in network. Script create SSH connection to every server located in hosts file, store fingerprint as trusted if needed, make "sudo su -" and push commands.
I am using it regularly when creating/deleting new users, patching applications or harvesting data.
There are some similar scripts on Internet but this one exceeds the functionality and usability of others.

First of all you must create file "hosts.list" (in same location as script) where you define servers which will use script for SSH connection. Each server on newline.

For example:

server1.domain.com
192.168.11.11
cyberdelia

Script expect that you will use standard user account and then switch under root via "sudo su -". You will be asked for username and password when you start script.
After that will be executed commands specified in "execute commands" section.

Here is mentioned script:

#!/usr/bin/expect
#
# info: Expect script which can execute commands on multiple servers via SSH
#
# author: Martin Cmelik (cm3l1k1) - www.security-portal.cz
#
# dependency: file "hosts.list" in same location (each server on newline)
#             /usr/bin/expect executable
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# license: This software is licensed under the Creative Commons
# Attribution-NonCommercial-ShareAlike 3.0 Unported License.
# To view this license visit http://creativecommons.org/licenses/by-nc-sa/3.0/
#

set timeout 60
set prompt "(%|#|\\$|%\]) $"
set fid [open ./hosts.list r]
set contents [read -nonewline $fid]
close $fid
stty echo
send_user "\nUsername for SSH connection: "
expect_user -re "(.*)\n" {set sshname $expect_out(1,string)}
send_user "\nPassword for SSH user: "
stty -echo
expect_user -re "(.*)\n" {set sshpassword $expect_out(1,string)}
stty echo
foreach host [split $contents "\n"] {
spawn ssh -o StrictHostKeyChecking=no $sshname@$host
expect {
  "assword:" { send -- "$sshpassword\r"
  }
  "you sure you want to continue connecting" {
  send -- "yes\r"
  expect "assword:"
  send -- "$sshpassword\r"
  }
}
expect -re "$prompt"
send -- "sudo su -\r"
expect {
  "assword:" { send -- "$sshpassword\r"
  expect -re "$prompt"
  }
  -re "$prompt"
}
# execute commands
send -- "sleep 5\r"
expect -re "$prompt"
send -- "echo All Done\r"
expect -re "$prompt"
send -- "exit\r"

}

I hope that script is clear. Every command must contain sign "\r" which means "Enter" and we are expecting $prompt which indicates the end of execution (timeout is 60 seconds).

Here is simple output:

cm3l1k1@deuterius bin $ ./expect.sh

Username for SSH connection: cm3l1k1

Password for SSH user: (not visible when you type)

spawn ssh -o StrictHostKeyChecking=no [email protected]

The authenticity of host 'server1.domain.com (192.168.11.22)' can't be established.
RSA key fingerprint is 44:a9:dc:b0:a4:53:f5:07:54:b0:c4:bc:0d:bb:99:32.
Are you sure you want to continue connecting (yes/no)? yes

This computer system, including all related equipment, networks, and network
devices (specifically including Internet access) are provided for authorized
corporate use only.

[email protected]'s password:

[cm3l1k1@server1 cm3l1k1]$ sudo su -

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.

Password:

[root@server1 root]# sleep 5

[root@server1 root]# echo All Done
All Done
[root@server1 root]# spawn ssh -o StrictHostKeyChecking=no [email protected]
...

Your input is only username and password.

I hope it will be useful!