How to check the SSH login status of routers in bash script with password prompts - bash

I am running a task where i need to check the SSH login status on 400 remote routers. I have made scripts using expect in bash which SSH the remote routers and run some commands over it. However, there are some routers that are not responding to SSH. I am using if statement to avoid those routers which are failing on SSH. Sample code to check the status on remote router works only if we have password less entry or the private key saved. Could you please help how can I check the SSH status on the remote routers?
If I get the password prompt while doing SSH to the router, I can say that the server is able to SSH the router. There is no need to supply password to it.
#!/bin/bash
ssh -q -o BatchMode=yes -o ConnectTimeout=7 username#IP exit
echo $?
if [ $? -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi

Well,
If you are using expect package then there is timeout option there as well.
Else your shell code above is correct way of doing it except just a few corrections:
#!/bin/bash
ssh -q -o BatchMode=yes -o ConnectTimeout=7 username#IP date
ret=$?
echo $ret
if [ $ret -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi
You can see, we are assigning $? immediately to a var. If you don't, then $? will contain the return value of echo $? command which will be always 0. Hence giving you true for all ssh.
Also I suggest to run some other command rather than exit with ssh.
Hope this helps
===Edited====>>>
well since you don't have passwordless ssh enabled. You can try to telnet to port 22, if 22 port is open then it will show connected and if its not open then it won't you can grep on it.
Here is the modified code: (Provided that ssh is running on 22 port otherwise change the port in code.)
#!/bin/bash
echo "" | telnet $IP 22 | grep "Connected"
ret=$?
echo $ret
if [ $ret -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi

Related

script to check if I can access multiple servers

I made this script to check if I can connect to a list of many servers:
for SERVER in $(cat servers.txt); do
ssh root#$SERVER && echo OK $SERVER || echo ERR $SERVER
done
The problem is that if is the first time I’m connecting to the server, the server asks the classic question “The authenticity of host ‘x.x.x.x’ can't be established... bla bla bla” Then I have to respond yes or not and it losses the purpose of making it a script, is there any way to bypass that so I can add it to the script?
Also, There are some servers in which I don't have my keys in them but they have the option to enter a password. In that case it will wait until I try a password to continue with the script execution, so I was wondering if there is a way to improve this script so if the server asks for a password then set it to ERR $SERVER and continue with the script?
Thank you for your help.
Do you actually need to establish an SSH connection?
Or is simply opening a socket connection to the host on the SSH port enough for you to determine that the server is online?
servers.txt
hostA.example.com
hostB.example.com
hostC.example.com
port-probe.sh
#!/bin/bash
PORT=22
TIMEOUT=3
for SERVER in $(cat servers.txt); do
# Open a socket and send a char
echo "-" | nc -w $TIMEOUT $SERVER $PORT &> /dev/null
# Check exit code of NC
if [ $? -eq 0 ]; then
echo "$SERVER is Available."
else
echo "$SERVER is Unavailable."
fi
done
You can use the -o flag to set options in SSH:
for SERVER in $(cat servers.txt); do
ssh -o StrictHostKeyChecking=no -o BatchMode=yes root#$SERVER exit && echo OK $SERVER || echo ERR $SERVER
done
Check out the manpage for ssh_config: man ssh_config for all of the options available with the -o flag.
If you have quite a few servers what you may want to do is connect to all of them simultaneously. This way it only waits maximum 2 minutes (default TCP connect timeout) if any of the servers is unresponsive.
Connect to each server without allocating a terminal and execute echo . command, redirect the output into a named file. Issue these commands in a loop asynchronously. Then wait till all commands complete, iterate over the log files and check which ones have dots in it. Then report the servers whose log files do not have a dot in it.
E.g.:
#/bin/bash
servers="$#"
for server in $servers; do
ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -Tn $server echo . >$server.log 2>$server.error.log &
done
wait # After 2 minutes all connection attempts timeout.
for server in $servers; do
[[ -s $server.log ]] || echo "Failed to connect to $server" >2
done

sshpass exit in automation

I have total of 6 IP addresses and out of the 6 only 2 IP addresses are valid. I wrote a shell script to use sshpass to test each IP.
The issue is when script reaches IP that is working it log's in the system (Cisco switch) and stays there and not continuing with the loop to test the remaining IPs. If i type "exit" on the system than it continues with the loop.
After a successful login how can script automatically get out, from logged system, and continue with testing remaining IP?
/usr/bin/sshpass -p $ADMINPASS ssh -oStrictHostKeyChecking=no -oCheckHostIP=no -t $ADMINLOGIN#$IP exit
i can use the exit status to figure out which IP worked and which on didn't work.
Test first if IP is alive, and then 'ssh' on it, could help you.I don't know if you are using a loop or not, but loop can be a good choice.Should look like : for f in ip-1 ip-2 ip-3 ip-4 ip-5 ip-6; do ping -c 1 -w 3 $f; if [ $? -eq 0 ]; then echo OK; ssh_pass $f your_command; else echo " IP is NOK"; fi; done
You can then also add 'exit' command, depending on what you test : 'exit 0' if it is OK, after you 'ssh' command, 'exit 1' if NOK.

how to check a ssh key is copied to remote server by script

I want use a script like below to check if ssh key in my host is copied to remote server:
#!/usr/bin/sh
ssh -q -o StrictHostKeyChecking=no user#server "ls >/dev/null </dev/null"
if [ $? -eq 0 ] ;then
echo "key copied to remote server"
else
echo "key not copied to remote server"
fi
but it always pending on password input in some case,
user#server's password:
if there any way to terminate this session and return error immediately?
add -o PubkeyAuthentication=yes and -o PasswordAuthentication=no to the ssh command in your script

Send close signal to SSH immediately on password prompt

I am currently running a server test with the following command:
echo ^C |ssh -q root#${server}
if [ 0 -ne $? ]; then
echo "==> Failed to connect..."; continue
fi
Unfortunately it does not look like my ^C is closing the connection immediately after a password prompt which is what I was expecting. Is there a better way to write this to test for an ssh connection without hanging on a prompt?
On unix systems, ^C kills a process because the TTY interface sends an interrupt signal to the process when the user types ^C. A literal ^C on standard input (read from a file or printed to a pipe from another process's output) is just a regular character.
You could suppress password authentication by running ssh like this:
ssh -o PasswordAuthentication=no -q root#${server}
ssh will exit with a failure code if it fails to authenticate using something other than a password. This failure code is indistinguishable from a failure to connect, so this may not be what you want.
If you're mainly interested in connectivity to the remote SSH server port, you don't have to use the actual ssh program to test. You could do this test with nc (netcat) for example:
$ nc -z localhost 22
$ echo $?
0
$ nc -z localhost 11122
$ echo $?
1
The -z flag tells netcat to test connectivity to the specified host and port without sending or receiving any data. You could structure your test like this:
if nc -z localhost 22
then
: success
else
echo Connection to ${server} failed
fi

Checking SSH failure in a script

Hi what is the best way to check to see if SSH fails for whatever reason?
Can I use a IF statement ( if it fails then do something)
I'm using the ssh command in a loop and passing my hosts names form a flat file.
so I do something like:
for i in `cat /tmp/hosts` ; do ssh $i 'hostname;sudo ethtool eth1'; done
I get sometime this error or I just cannot connect
ssh: host1 Temporary failure in name resolution
I want to skip the hosts that I cannot connect to is SSH fails. What is the best way to do this? Is there a runtime error I can trap to bypass the hosts that I cannot ssh into for whatever reason, perhaps ssh is not allowed or I do not have the right password ?
Thanking you in advance
Cheers
To check if there was a problem connecting and/or running the remote command:
if ! ssh host command
then
echo "SSH connection or remote command failed"
fi
To check if there was a problem connecting, regardless of success of the remote command (unless it happens to return status 255, which is rare):
if ssh host command; [ $? -eq 255 ]
then
echo "SSH connection failed"
fi
Applied to your example, this would be:
for i in `cat /tmp/hosts` ;
do
if ! ssh $i 'hostname;sudo ethtool eth1';
then
echo "Connection or remote command on $i failed";
fi
done
You can check the return value that ssh gives you as originally shown here:
How to create a bash script to check the SSH connection?
$ ssh -q user#downhost exit
$ echo $?
255
$ ssh -q user#uphost exit
$ echo $?
0
EDIT - I cheated and used nc
Something like this:
#!/bin/bash
ssh_port_is_open() { nc -z ${1:?hostname} 22 > /dev/null; }
for host in `cat /tmp/hosts` ; do
if ssh_port_is_open $host; then
ssh -o "BatchMode=yes" $i 'hostname; sudo ethtool eth1';
else
echo " $i Down"
fi
done

Resources