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

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

Related

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

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

How to check connection to a list of servers in bash?

Im trying to check connections for a list of servers. I want to loop through the list, check if a connection works and if yes, do some stuff, if not, echo out a problem message.
My problem is:
the script stops at the first node without echoing the $?.
So, whats wrong with my for-loop?
These vars are included from a config file:
$nodes is a list of server IPs like 1.1.1.1,2.2.2.2,10.10.10.10
$user is one string
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -o ConnectTimeout=3 $user#$node echo ok
echo $?
if [[ $? != 0 ]]
then
echo "Problem in logging into $node"
else
# do some stuff here
fi
done
EDIT #1:
for node in $(echo $nodes | sed "s/,/ /g")
do
echo "Checking Node: $node"
ssh -q -t -o ConnectTimeout=3 $user#$node "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
then
echo "Problem in logging into $node"
else
echo "OK"
fi
done
It is because ssh first asks you to validate The authority of the host and If you accept the authority it will ask for password. That is why your command does not return to shell and waits for input.
If your intention is just validating ssh connection, then you may consider to use
telnet <your_host> <port> < /dev/null
But if your intend is to run some commands you need a trust relationship between hosts. In that case you can use:
Execute this commands:
ssh-keygen -t rsa
then
ssh-copy-id -i root#ip_address
Now you can connect with
ssh <user>#<host>
Furher information
You can add -tto make virtual terminal and add quotes on command:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
Also use -ne instead of != which is for compare strings
if [[ "$?" -ne 0 ]]
Also echo $? mess the return code. You should use something like:
ssh -q -t -o ConnectTimeout=3 ${user}#${node} "echo ok"
retcode=$?
echo $retcode
if [[ "$retcode" -ne 0 ]]
You can rewrite ssh command like this to avoid problems with ssh host keys
ssh -q -t -o StrictHostKeyChecking=no -o ConnectTimeout=3 ${user}#${node} "echo ok"

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

How to report unsuccessful commands on remote machines?

For instance, I wrote a simple script to delete all the jar files on remote machines.
## distribute commands to machines
for machine in $machines
do
echo $machine
ssh -o "StrictHostKeyChecking no" $machine "rm /home/ubuntu/test.jar" &
done
I want to know whether all these commands were successful. Is there any convenient way?
Thanks!
Get rid of the & backgrounding the sshes and then you can check their exit status with if or ||.
for machine in $machines; do
echo $machine
if ! ssh -o StrictHostKeyChecking=no $machine rm /home/ubuntu/test.jar; then
echo "didn't work" >&2
fi
done
or
succeeded=true
for machine in $machines; do
echo $machine
ssh -o StrictHostKeyChecking=no $machine rm /home/ubuntu/test.jar || succeeded=false
done
if ! $succeeded; then
echo "one or more removals failed" >&2
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