0

I am comfortable with writing single queries. I am new to writing bash scripts trying to automate the daily stuff. I need help on creating a PowerShell or bash script where I can SSH to multiple Linux devices with same SSH key and then reboot the devices.

I access linux devices manually with the following command in PowerShell

ssh -i C:\<path-to-the-private-key\test.ppk test@XX.X.X.XXX (X - IP Address)

Then I enter the following command

sudo reboot

It asks me to type the password and then restarts the device.

I have 100+ devices that I need to restart.

I can get a list of all IP address in a text file. How can we search for all the IP address in a text file, authenticate with the SSH private key and run the sudo command to restart the device?

Would it also be possible to throw a message if it was not able to restart a device?

Any help would be appreciated.


This is the script that I have.

testreboot.sh

#!/bin/bash

pw="test123"  
hosts='IP.txt'


while read -r line;  do {
    /usr/bin/expect << EOF  do
    ssh test@"$hosts" 'sudo reboot' 
    expect "*?assword*"
    send "%pw\r" 
EOF 
} 
    done < $hosts

IP.txt

XXX.XX.XX.XX 
XXX.XX.XX.XX
XXX.XX.XX.XX 
XXX.XX.XX.XX

I have Ubuntu 20.04 installed from Windows App Store. I am trying to run the testreboot.sh from PowerShell using the following command and get the following error message.

 bash testreboot.sh
testreboot.sh: line 2: $'\r': command not found
testreboot.sh: line 3: $'\r': command not found
testreboot.sh: line 5: $'\r': command not found
testreboot.sh: line 16: syntax error near unexpected token `done'
testreboot.sh: line 16: `done < $hosts'

enter image description here

albbla91
  • 53
  • 2
  • 9
  • This is what `expect` was designed for. See https://stackoverflow.com/questions/41165719/embedding-an-expect-script-inside-a-bash-script – GoinOff May 12 '22 at 16:35
  • 1
    Create a file containing the list of servers to connect to. Then loop on this file (see https://mywiki.wooledge.org/BashFAQ/001). For each server call your `ssh`, with the reboot. For the `sudo` you can either configure it to accept reboot without a password, or use `expect`. – Nic3500 May 12 '22 at 17:12
  • 1
    I agree with @Nic3500. The logic to do any interactive stuff should be handled on each host. SSH can run a single command but cannot perform interactive logic over the SSH protocol. – Dean Householder May 12 '22 at 23:54
  • `expect` handles all interactive logic over SSH. I see no need to modify each server to perform interactive logic for you. In fact, that is a bad route to go requiring every new server to be modified to get things to work when `expect` can handle it all in your shell script using SSH. I use `expect` in my script to ssh to many machines and perform any operations like placing or retrieving files and such. – GoinOff May 13 '22 at 16:33
  • Thank you all for your answers. I am still new on writing bash scripts. I have tried this but it fails. Could you help? '#!/bin/bash pw="password123" hosts='c:\test\ListofIP.txt' while read -r line; do { /usr/bin/expect << EOF spawn sudo reboot user@$host expect "*?assword*" send "%pw\r" expect "*#*" EOF } done < $hosts' – albbla91 May 16 '22 at 10:40
  • Could you post the error where is breaks down and add your expect code to your post above so it's easy to follow. – GoinOff May 16 '22 at 13:34
  • @GoinOff Please see attached script and error message. Any help would be appreciated. Thank you – albbla91 May 16 '22 at 13:55
  • See my posted example below. You will need to modify it and make sure that any passwords that need escaping. See the way I passed the `password$` as `password\\\$` – GoinOff May 16 '22 at 15:43

2 Answers2

0

A better solution to this problem is to use something like Ansible, Chef, or Puppet to solve these multi-server coordination needs.

Dean Householder
  • 549
  • 1
  • 7
  • 13
0

Here is an example in a shell script using expect to ssh to another server and login:

NOTE: When you use expect in this manner, you need to escape " and $ and other items. If password has $, it must be escaped.

This is where after logging in and expect see a command prompt For example:

44 [localhost.localdomain]/home/map%

This is where you would need to add sudo reboot command

-re \"$reg_ex_prompt\" {
}

Test Script:

#!/bin/sh
#
debug=0
exit_val=0
spawn_item="ssh"
destination="user_name@<IP of server to shh>"
reg_ex_prompt='\[%|>|\$|#\] $'
#
# Change -D 0 to -D 1 to debug interactivly
#
expect -D $debug -c "
spawn $spawn_item $destination
set ret 1
set timeout 20
expect {
    timeout {
        send_user \"Timeout reached!\"
        exit \$ret
    }
    eof {
        puts \"End of test connection reached!\"
        if { \$ret == 0 } {
          puts \"Connection test Successful!\"
          puts \"Exiting $destination ...\"
        } else {
          puts \"Connection Failure!\"
        }
        exit \$ret
    }
    \"Connection refused\" {
        puts \"ERROR: Trouble connecting to $device_type_parm destination $destination\"
        puts \"Aborting...\"
        exit \$ret
    }
    \"Permission denied\" {
        puts \"ERROR: User name or password is incorrect for $destination\"
        puts \"Aborting...\"
        exit \$ret
    }
    \"Connection reset by peer\" {
        puts \"ERROR: Trouble connecting to $destination\"
        puts \"Aborting...\"
        exit \$ret
    }
    \"you sure you want to continue connecting\" {
        send \"yes\r\"
        exp_continue
    }
    \"assword:\" {
        puts \"\r\nSending password\"
        send \"password\\\$\r\"
        exp_continue
    }
    \"Choice? \" {
        send \"1\r\"
        exp_continue
     }
    \"Q. Quit\" {
        send \"q\r\"
        exp_continue
     }
    -re \"$reg_ex_prompt\" {
        send \"sudo reboot\r\"
        sleep 2
        set ret 0
        exit \$ret
     }
     interact
    } "

# get the exit value from expect statment above
exit_val=$?
GoinOff
  • 1,792
  • 1
  • 18
  • 37