Expect/Send Issue - linux

Currently, I am working on a script to automatize a process, in this point my script is short and simple but I have had some Issues with expect/send.
code:
#!/usr/bin/expect -f
#!/bin/bash
set ip ***
set ip2 ***
set user ***
set usr2 ***
set OTP [lindex $argv 0]
spawn ssh "usr#$ip";
expect "OTP Password:"
send -- "$OTP"
interact
expect "prompt >"
send -- "ssh usr2#$ip2"
interact
For this point script works until the first ssh but... for the second ssh (expect "prompt >" / send -- "ssh $ip2") It doesn't work... I don't get the idea why. I have tried with some commands like expect eof, wait, timeout and nothing as well I checked to expect version is on latest (5.45).
Do you have any idea? thanks!

Your spawn looks fine to me, but in the send, you forgot to send the carriage return, which actually terminates the command:
send -- "$OTP\r"

Related

Expect script to verify login working

My company uses powerbroker identity service to bridge authentication between AD and Linux systems.
I am trying to write an expect script that I can use to verify that the authentication is working .. .and write the output to a file. Can anyone help?.. this is going to be used on a huge list of servers.. I don't really know expect so here is what I got so far but not sure how to get it to log.. or to create a case statement where it says if server is good or not...
#!/usr/bin/expect -f
set timeout -1
set ip [lindex $argv 0]
set user XXXXXX
set password XXXXXXX
spawn ssh "$user\#$ip"
expect -exact ":"
send "$password\r";
expect "$"
send -- "\r"
send -- "hostname ; date\r"
expect "$"
send -- "exit\r"

What's the best way to mix remote expect scripts and local bash commands?

I'm automating tasks on a local and remote machine (behind a firewall). Once I'm done with tasks on the remote machine, I'd like the script to return to executing commands on the local machine.
#!/usr/bin/expect -f
set timeout -1
spawn ssh username#host
expect "Password: "
send "mypassword\r"
expect "username#host:~$"
...do some stuff...
send "exit\r"
expect eof
[then, once on the local machine, change directories and do other things]
What's the best way to append bash commands? I suppose I could start with bash, call expect within it, then simply return to bash once expect is done.
Expect is based on Tcl, so it can run the same commands. But if your goal is to run bash commands, the best bet is to run them from bash as a separate script, exactly as you propose in your last sentence.
It really depends on what your idea of ...do some stuff... is. Here's an example of something I recently did from my OSX w/s to an AWS instance
export all_status
init_scripts=($(ssh -q me#somehost 'ls /etc/init.d'))
for this_init in ${init_scripts[#]};do
all_status="${all_status}"$'\n\n'"${this_init}"$'\n'"$(ssh -q somehost \'sudo /etc/init.d/${this_init} status\')"
done
echo "$all_status" > ~/somehost_StatusReport.txt
unset all_status
Passing a command at the end of the ssh command will cause the command to be run on the remote host. Or you can scp a script to the remote host and run it with
ssh somehost '/home/me/myscript'
I met this situation recently too. I make a shell supexpect.sh which could login and execute command automatically. It will return to your local shell at the end.
#!/usr/bin/expect
#Usage:supexpect <host ip> <ssh username> <ssh password> <commands>
set timeout 60
spawn ssh [lindex $argv 1]#[lindex $argv 0] [lindex $argv 3]
expect "yes/no" {
send "yes\r"
expect "*?assword" { send "[lindex $argv 2]\r" }
} "*?assword" { send "[lindex $argv 2]\r" }
send "exit\r"
expect eof
To execute:
./supexpect.sh 10.89.114.132 username password "ls -a;pwd;your_stuff_on_remote_host"
Note:
The prompt might need to adapt to your own system, and of course you need to pass execute permission to it.

Expect script for ssh login

I has a simple expect script for sshing into a remote machine adapted from here https://serverfault.com/questions/79645/ssh-run-a-command-on-login-and-then-stay-logged-in:
#!/usr/bin/expect -f
set host [lrange $argv 0 0]
spawn ssh $host
expect "root"
interact
The only problem is that when I exit from the remote host by typing "exit", there's a 3 second hang and then I get the prompt back. I don't know much about the internals of expect, so I was wondering if somebody knows about the reason and how to avoid it.

How to automate telnet session using Expect?

I'm trying to write an expect script to automate telnet. This is what I have so far.
#!/usr/bin/expect
# Test expect script to telnet.
spawn telnet 10.62.136.252
expect "foobox login:"
send "foo1\r"
expect "Password:"
send "foo2\r"
send "echo HELLO WORLD\r"
# end of expect script.
Basically, what I want to do is telnet to the following IP address and then echo HELLO WORLD. However, it seems that the script fails after attempting to telnet...I'm not sure if it's able to accept login and password input, but it is not echoing HELLO WORLD. Instead, I just get this output:
cheungj#sfgpws30:~/justin> ./hpuxrama
spawn telnet 10.62.136.252
Trying 10.62.136.252...
Connected to 10.62.136.252.
Escape character is '^]'.
Welcome to openSUSE 11.1 - Kernel 2.6.27.7-9-pae (7).
foobox login: foo1
Password: foo2~/justin>
It's hard to tell, but from the output you're pasting it looks like:
Your script isn't waiting for login to complete before sending the next command.
Your script is exiting and closing the process before you can see any output.
There are no guarantees in life, but I'd try this as a first step:
#!/usr/bin/expect -f
spawn telnet 10.62.136.252
expect "foobox login:"
send "foo1\r"
expect "Password:"
send "foo2\r"
# Wait for a prompt. Adjust as needed to match the expected prompt.
expect "justin>"
send "echo HELLO WORLD\r"
# Wait 5 seconds before exiting script and closing all processes.
sleep 5
Alternatives
If you can't get your script to work by manually programming it, try the autoexpect script that comes with Expect. You can perform your commands manually, and autoexpect will generate an Expect typescript based on those commands, which you can then edit as needed.
It's a good way to find out what Expect actually sees, especially in cases where the problem is hard to pin down. It's saves me a lot of debugging time over the years, and is definitely worth a try if the solution above doesn't work for you.
You're sending the echo command without first expecting the prompt. Try:
# after sending the password
expect -re "> ?$"
send "echo HELLO WORLD\r"
expect eof
Have you seen this StackOverflow Question?
He seems to have got things working by using curly braces.
Here is a simplified version
#!/usr/bin/expect
# just do a chmod 755 one the script
# ./YOUR_SCRIPT_NAME.sh $YOUHOST $PORT
# if you get "Escape character is '^]'" as the output it means got connected otherwise it has failed
set ip [lindex $argv 0]
set port [lindex $argv 1]
set timeout 5
spawn telnet $ip $port
expect "'^]'."

Automating telnet session using Bash scripts

I am working on automating some telnet related tasks, using Bash scripts.
Once automated, there will be no interaction of the user with telnet (that is, the script will be totally automated).
The scripts looks something like this:
# execute some commands on the local system
# access a remote system with an IP address: 10.1.1.1 (for example)
telnet 10.1.1.1
# execute some commands on the remote system
# log all the activity (in a file) on the local system
# exit telnet
# continue with executing the rest of the script
There are two problems I am facing here:
How to execute the commands on the remote system from the script (without human interaction)?
From my experience with some test code, I was able to deduce that when telnet 10.1.1.1 is executed, telnet goes into an interactive session and the subsequent lines of code in the script are executed on the local system. How can I run the lines of code on the remote system rather than on the local one?
I am unable to get a log file for the activity in the telnet session on the local system. The stdout redirect I used makes a copy on the remote system (I do not want to perform a copy operation to copy the log to the local system). How can I achieve this functionality?
While I'd suggest using expect, too, for non-interactive use the normal shell commands might suffice. telnet accepts its command on stdin, so you just need to pipe or write the commands into it through heredoc:
telnet 10.1.1.1 <<EOF
remotecommand 1
remotecommand 2
EOF
(Edit: Judging from the comments, the remote command needs some time to process the inputs or the early SIGHUP is not taken gracefully by telnet. In these cases, you might try a short sleep on the input:)
{ echo "remotecommand 1"; echo "remotecommand 2"; sleep 1; } | telnet 10.1.1.1
In any case, if it's getting interactive or anything, use expect.
Write an expect script.
Here is an example:
#!/usr/bin/expect
#If it all goes pear shaped the script will timeout after 20 seconds.
set timeout 20
#First argument is assigned to the variable name
set name [lindex $argv 0]
#Second argument is assigned to the variable user
set user [lindex $argv 1]
#Third argument is assigned to the variable password
set password [lindex $argv 2]
#This spawns the telnet program and connects it to the variable name
spawn telnet $name
#The script expects login
expect "login:"
#The script sends the user variable
send "$user "
#The script expects Password
expect "Password:"
#The script sends the password variable
send "$password "
#This hands control of the keyboard over to you (Nice expect feature!)
interact
To run:
./myscript.expect name user password
Telnet is often used when you learn the HTTP protocol. I used to use that script as a part of my web scraper:
echo "open www.example.com 80"
sleep 2
echo "GET /index.html HTTP/1.1"
echo "Host: www.example.com"
echo
echo
sleep 2
Let's say the name of the script is get-page.sh, then this will give you an HTML document:
get-page.sh | telnet
I hope this will be helpful to someone ;)
This worked for me..
I was trying to automate multiple telnet logins which require a username and password. The telnet session needs to run in the background indefinitely since I am saving logs from different servers to my machine.
telnet.sh automates telnet login using the 'expect' command. More info can be found here: http://osix.net/modules/article/?id=30
telnet.sh
#!/usr/bin/expect
set timeout 20
set hostName [lindex $argv 0]
set userName [lindex $argv 1]
set password [lindex $argv 2]
spawn telnet $hostName
expect "User Access Verification"
expect "Username:"
send "$userName\r"
expect "Password:"
send "$password\r";
interact
sample_script.sh is used to create a background process for each of the telnet sessions by running telnet.sh. More information can be found in the comments section of the code.
sample_script.sh
#!/bin/bash
#start screen in detached mode with session-name 'default_session'
screen -dmS default_session -t screen_name
#save the generated logs in a log file 'abc.log'
screen -S default_session -p screen_name -X stuff "script -f /tmp/abc.log $(printf \\r)"
#start the telnet session and generate logs
screen -S default_session -p screen_name -X stuff "expect telnet.sh hostname username password $(printf \\r)"
Make sure there is no screen running in the backgroud by using the
command 'screen -ls'.
Read
http://www.gnu.org/software/screen/manual/screen.html#Stuff to read
more about screen and its options.
'-p' option in sample_script.sh
preselects and reattaches to a specific window to send a command via
the ‘-X’ option otherwise you get a 'No screen session found' error.
You can use expect scripts instaed of bash.
Below example show how to telnex into an embedded board having no password
#!/usr/bin/expect
set ip "<ip>"
spawn "/bin/bash"
send "telnet $ip\r"
expect "'^]'."
send "\r"
expect "#"
sleep 2
send "ls\r"
expect "#"
sleep 2
send -- "^]\r"
expect "telnet>"
send "quit\r"
expect eof
The answer by #thiton was helpful but I wanted to avoid the sleep command. Also telnet didn't exit the interactive mode, so my script got stuck.
I solved that by sending telnet command with curl (which seems to wait for the response) and by explicitly telling telnet to quit like this:
curl telnet://10.1.1.1:23 <<EOF
remotecommand 1
remotecommand 2
quit
EOF
Following is working for me...
put all of your IPs you want to telnet in IP_sheet.txt
while true
read a
do
{
sleep 3
echo df -kh
sleep 3
echo exit
} | telnet $a
done<IP_sheet.txt
#!/bin/bash
ping_count="4"
avg_max_limit="1500"
router="sagemcom-fast-2804-v2"
adress="192.168.1.1"
user="admin"
pass="admin"
VAR=$(
expect -c "
set timeout 3
spawn telnet "$adress"
expect \"Login:\"
send \"$user\n\"
expect \"Password:\"
send \"$pass\n\"
expect \"commands.\"
send \"ping ya.ru -c $ping_count\n\"
set timeout 9
expect \"transmitted\"
send \"exit\"
")
count_ping=$(echo "$VAR" | grep packets | cut -c 1)
avg_ms=$(echo "$VAR" | grep round-trip | cut -d '/' -f 4 | cut -d '.' -f 1)
echo "1_____ping___$count_ping|||____$avg_ms"
echo "$VAR"
Use ssh for that purpose. Generate keys without using a password and place it to .authorized_keys at the remote machine. Create the script to be run remotely, copy it to the other machine and then just run it remotely using ssh.
I used this approach many times with a big success. Also note that it is much more secure than telnet.
Here is how to use telnet in bash shell/expect
#!/usr/bin/expect
# just do a chmod 755 one the script
# ./YOUR_SCRIPT_NAME.sh $YOUHOST $PORT
# if you get "Escape character is '^]'" as the output it means got connected otherwise it has failed
set ip [lindex $argv 0]
set port [lindex $argv 1]
set timeout 5
spawn telnet $ip $port
expect "'^]'."
Script for obtain version of CISCO-servers:
#!/bin/sh
servers='
192.168.34.1
192.168.34.3
192.168.34.2
192.168.34.3
'
user='cisco_login'
pass='cisco_password'
show_version() {
host=$1
expect << EOF
set timeout 20
set host $host
set user $user
set pass $pass
spawn telnet $host
expect "Username:"
send "$user\r"
expect "Password:"
send "$pass\r"
expect -re ".*#"
send "show version\r"
expect -re ".*-More-.*"
send " "
expect -re ".*#"
send "exit\r"
EOF
}
for ip in $servers; do
echo '---------------------------------------------'
echo "$ip"
show_version $ip | grep -A3 'SW Version'
done
Here is a solution that will work with a list of extenders. This only requires bash - some of the answers above require expect and you may not be able to count on expect being installed.
#!/bin/bash
declare -a Extenders=("192.168.1.48" "192.168.1.50" "192.168.1.51")
# "192.168.1.52" "192.168.1.56" "192.168.1.58" "192.168.1.59" "192.168.1.143")
sleep 5
# Iterate the string array using for loop
for val in ${Extenders[#]}; do
{ sleep 0.2; echo "root"; sleep 0.2; echo "ls"; sleep 0.2; } | telnet $val
done
Play with tcpdump or wireshark and see what commands are sent to the server itself
Try this
printf (printf "$username\r\n$password\r\nwhoami\r\nexit\r\n") | ncat $target 23
Some servers require a delay with the password as it does not hold lines on the stack
printf (printf "$username\r\n";sleep 1;printf "$password\r\nwhoami\r\nexit\r\n") | ncat $target 23**

Resources