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 [email protected] (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

8
  • This is what expect was designed for. See stackoverflow.com/questions/41165719/… Commented May 12, 2022 at 16:35
  • 1
    Create a file containing the list of servers to connect to. Then loop on this file (see 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. Commented May 12, 2022 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. Commented May 12, 2022 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. Commented May 13, 2022 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' Commented May 16, 2022 at 10:40

2 Answers 2

0

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

Sign up to request clarification or add additional context in comments.

Comments

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=$?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.