bash expect stops after *** - bash

I have a very simple expect script to connect to a Cisco Wireless Lan Controller via Cisco router.
My problem is that after some commands expect stops suddenly without finish all sentences and without any error.
I think that the problem is with * from password but I'm not sure.
That's my script
#!/usr/bin/expect
set timeout 10
spawn telnet X.Y.Z.W
expect "User Access Verification"
expect "Username:"
send "admin\r"
expect "Password:"
send "PASSWORD\r"
expect "Router#"
send "telnet WLC_IP\r"
expect "(Cisco Controller)"
expect "User:"
send "admin\r"
expect "Password:"
send "PASSWORD\r"
expect "Cisco Controller"
send " config paging disable\r"
expect "Cisco Controller"
send " show ap auto-rf 802.11b AP-NAME\r"
expect "Cisco Controller"
send "logout\r";
And this is the output after running,
spawn telnet X.Y.Z.W
Trying X.Y.Z.W...
Connected to X.Y.Z.W.
Escape character is '^]'.
User Access Verification
Username: admin
Password:
Router#telnet WLC_IP
Trying WLC_IP ... Open
(Cisco Controller)
User: admin
Password:**********
(Cisco Controller) >?
clear Clear selected configuration elements.
config Configure switch options and settings.
cping Send capwap echo packets to a specified mobility peer IP address.
debug Manages system debug options.
eping Send Ethernet-over-IP echo packets to a specified mobility peer IP address.
grep Print lines matching a pattern.
help Help
license Manage Software License
linktest Perform a link test to a specified MAC address.
logout Exit this session. Any unsaved changes are lost.
mping Send Mobility echo packets to a specified mobility peer IP address.
ping Send ICMP echo packets to a specified IP address.
reset Reset options.
save Save switch configurations.
show Display switch options and settings.
test Test trigger commands
transfer Transfer a file to or from the switch.
(Cisco Controller) >config paging disable
(Cisco Controller) >[root#mailman scripts]#
Also, there are an "?" after password that I don't know why is it.
Any ideas?
Thanks in advance!

after setting expect eof at the end of my script it works well! I'm not sure if it's mandatory but works for me.
Thank you!

Related

Shell script calling passing input to command which expects input from terminal

I am trying to write a script which calls the following command
[root#xxxxx imtadmin]# admin tower
-------------------------------------------------------------------
GMS: address=xxxxx-42450, cluster=CLRTY-SA, physical address=xxxxx:45155
-------------------------------------------------------------------
NSA Tower Shell
Usage:
history Show admin shell command history.
!<command prefix> Execute a command maching the given prefix from the command history.
refresh Wake up monitor thread, to update clients.
autodiscovery <on|off> Turn autodiscovery on or off.
add <host(s)> Add given host(s) by address.
remove <host(s)> Remove given host(s) by address.
list clients Print listing of clients.
list services Print listing of client services.
select <address|index> Select a specific client host by address.
connect <address> [port] Connect to a given Select a specific
client host by address.
trace Send trace message on multicast channel.
trace <on|off> Turn trace listening on or off.
password <password> Change password for this session only.
reset password Reset password to local machine value.
group <group> Change channel group for this session only.
(such as CLRTY for listening to PPM
broadcasts.)
reset group Reset group to local machine value.
list group List group members.
exit|quit Exit the tower.
? Print this message.
> list clients **TERMINAL INPUT***
Discovered Clients:
--------------------------
1) xxxxx.ec2.internal:9091 [xxxxx-20212]
--------------------------
> refresh **TERMINAL INPUT***
> list clients **TERMINAL INPUT***
Discovered Clients:
--------------------------
1) xxxxxx.ec2.internal:9091 [xxxxx-59053]
2) yyyyy.ec2.internal:9091 [yyyyy-20212]
3) zzzzzz.ec2.internal:9091 [zzzzz]
--------------------------
>
My Script:
#!/usr/bin/expect
spawn /opt/clarity/bin/admin tower
set timeout -1
expect -re "^>{1}"
send "list clients"
My script does call the command admin tower and stops at the prompt > but it doesn't accept input provided by script or input I provide from the terminal (my goal is to provide input from the script).
This should work :
send "list clients\n"
expect eof
Following worked. Thanks, #Philippe for hinting I need to add expect after providing input.
#!/usr/bin/expect
spawn /opt/clarity/bin/admin tower
expect -re "^>"
send "list clients\r"
expect -re "^>{1}"
send "refresh\r"
expect -re "^>{1}"
send "list clients\r"
expect -re "^>{1}"
send "exit\r"

Bash scripting with expect. Set parameters to multiple test boards

I'm working on a small project for school. I'm using 15 or so tuners to emulate a Cell network. I'm by no means well versed in scripting yet. I'm an EE who usually googles until I have some frankencode capable of my purposes.
The goal is the set up all the modules quickly so I thought to automate the process with a script. This requires ssh, and so far I have to manually type in the password each time. This morning I set up a basic test with both Expect and sshpass. In either case I can correctly log in, but not give instructions to the remote machine.
I was reading that sshpass has difficulty with sending remote instruction, correct me if I'm wrong.
/usr/bin/expect << EOF
spawn ssh root#<IP>
expect "(yes/no)?" #Are you sure you want to connect nonsense
send "yes\r"
expect "password"
send "$pass\r"
I tried a few things here to get the device to receive instruction
interact
cat /pathto/config.txt
#or
send "cat /pathto/config.txt
#the real goal is to send this instruction
sqlite3 /database.db "update table set param=X"
EOF
You might as well make it an expect script, not a shell script
#!/usr/bin/expect -f
and then pass the IP address to the script as a command line argument
expect myloginscript.exp 128.0.0.1 the_password
In the expect script, you'll grab that IP address from the arguments list
set ip [lindex $argv 0]
set pass [lindex $argv 1]
(Putting the password on the command line is not good security practice. You can research better methods of passing the password to your expect script.)
To use ssh, you'll be asked "are you sure" only the first time to connect, so let's make that conditional. That is done by letting the expect command wait for several patterns:
spawn ssh root#$ip
expect {
"(yes/no)?" {
send "yes\r"
# continue to wait for the password prompt
exp_continue
}
"password" {
send "$pass\r"
}
}
Once that is sent, you should expect to see your shell prompt. The pattern for this is up to your own configuration but it typically ends with a hash and a space.
expect -re {# $}
Now you can automate the rest of the commands:
send "cat /pathto/config.txt\r"
expect -re {# $}
# note the quoting
send "sqlite3 /database.db \"update table set param='X'\"\r"
expect -re {# $}
At this point, you'll want to log off:
send "exit\r"
expect eof
On the other hand, if you set up ssh private key authentication (see ssh-keygen and ssh-copy-id), you can just do this:
ssh root#IP sqlite3 /database.db "update table set param='$X'"
and not have to get into expect at all.

expect telnet to multiple cisco devices and execute show run

I have the following scripts which is supposed to pull the IP address from a file device-list.txt and then telnet to the device, login and execute a show run. The script logs in to the device successfully, but gives me an error after that. Any ideas where im going wrong?
for device in `cat device-list.txt`; do ./test4 $device;done
cat test4
#!/usr/bin/expect -f
set hostname [lindex $argv 0]
set user myusername
set pass mypassword
set timeout 10
log_file -a ~/results.log
send_user "\n"
send_user ">>>>> Working on $hostname # [exec date] <<<<<\n"
send_user "\n"
spawn telnet $hostname
expect "Username:"
send "$user\n"
expect "Password:"
send "$pass\n"
expect "#"
send “term len 0\n”
send “show running-config\n”
expect “end\r”
send “\n”
send “exit\n”
User Access Verification
Username: myusername
Password:
ROUTER#usage: send [args] string
while executing
"send “term len 0\n”"
(file "./test4" line 26)
Your problem is due to incorrect double quotes. You have to use double quotes ", not smart quotes “
send “term len 0\n” ; # Wrong
send "term len 0\r"; # Correct
Note :
Basically, Expect will work with two feasible commands such as send and expect. If send is used, then it is mandatory to have expect (in most of the cases) afterwards. (while the vice-versa is not required to be mandatory)
This is because without that we will be missing out what is happening in the spawned process as Expect will assume that you simply need to send one string value and not expecting anything else from the session.
So, we recommend to use expect after each send, to make sure our commands actually sent to the spawned process. (You have not used expect after sending some commands such as term len 0\r). Also, use \r instead of \n.

How to get telnet execution result code from shell script?

Using the following shell code for remote telnet request:
{
sleep 5
echo admin
sleep 3
echo pass
sleep 3
echo ls
sleep 5
echo exit
} | telnet 172.16.1.1
I want to check if telnet connection was successful or not. Trying to use $?:
echo $?
But it always returns "1", even if telnet connection was OK.
Telnet is exceptionally difficult to script in this way, there is a high degree of asynchronicity with the time it takes to establish a connection and for your intended actions to complete. expect was created for exactly this kind of purpose. You launch a program, like telnet, then declare a series of expectations - eg, when 'username: ' is emitted from the program, and an action to trigger (eg: typing in the username).
There are also libraries or wrappers for expect in many languages:
python expect
ruby expect
perl expect
Here is an example that drives telnet to make an HTTP HEAD request:
set timeout 20
spawn telnet localhost 80
expect "Connected to "
send "HEAD / HTTP/1.0\r\n\r\n"
expect "HTTP 200 OK"
Given all of this, I feel I must point out that telnet is considered insecure. Ssh is a much better choice and supports better choices for authentication (eg: public/private key auth), restrictions for commands that can be run (via .ssh/authorized_keys). With ssh, and ssh-keys set up, your script reduces to a single shell command:
ssh user#hostname ls
ssh has great support for safe, secure remote command execution.
If I'm remembering correctly, this expect script does what you're doing above.
#!/usr/bin/expect
spawn telnet 172.16.1.1
expect username:
send admin
expect password:
send pass
expect "\$ "
send ls
expect "\$ "
send exit
Here's a useful link for getting started: http://oreilly.com/catalog/expect/chapter/ch03.html

Facing difficulty to transfer a file from one server to another using TCL

I am trying to transfer a file from one server to a remote server with the help of a TCL script.
But my script stops after the message "200 Port set okay" and continues to rum from the below telnet session.
I have checked the destination location, my file is not transferred.
Please suggest what can I do or where I am wrong
#!/usr/bin/tclsh
#!/usr/bin/expect
package require Expect
set p "mm155_005.006.010.200_bt.fw"
#**************************************************************\
FILE TRANSFER TO REMOTE SERVER \
***************************************************************
spawn ftp 10.87.121.26
expect "User (10.87.121.26:(none)):"
send "user\r"
expect "Password:"
send "pswd\r"
expect "ftp>"
send "cd FW\r"
expect "ftp>"
send "ha\r"
expect "ftp>"
send "bi\r"
expect "ftp>"
send "mput \"$p\"\r"
expect "mput $p? "
send "yes\r"
expect "ftp>"
send "ls\r"
#**************************************************************\
RUNNING THE TRANSFERED FILE \
***************************************************************
spawn telnet 10.87.121.26
expect "Login: "
send "user\r"
expect "password: "
send "pswd\r"
expect "*? > "
send "cd FW\r"
expect "*? > "
send "burnboot 30 5.6(10.200)\r"
Output
spawn ftp 10.87.121.26
Connected to 10.87.121.26.
220 VxWorks FTP server (VxWorks VxWorks5.4.2) ready.
Name (10.87.121.26:vkumar): user
331 Password required
Password:
230 User logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd FW
250 Changed directory to "C:/FW"
ftp> ha
Hash mark printing on (1024 bytes/hash mark).
ftp> bi
200 Type set to I, binary mode
ftp> mput "mm155_005.006.010.200_bt.fw"
mput mm155_005.006.010.200_bt.fw? yes
200 Port set okay \ I am unable to see hash progress bar after this line
spawn telnet 10.87.121.26
Trying 10.87.121.26...
Connected to 10.87.121.26.
Escape character is '^]'.
Login: user
password:
node84.7.PXM.a > cd FW
node84.7.PXM.a > bash-2.05b$
Instead of rolling your own solution in Expect (I also did this about 9 years ago), use the FTP module from tcllib -- it's already battle-hardened.
http://tcllib.sourceforge.net/doc/ftp.html
The script as reported is unlikely to produce exactly that output; there is nothing from the ls done after the mput. However, if the mput is hanging the most likely problem is that there is a firewall issue; FTP uses multiple sockets to do file transfers (which is why FTP is such a pain when it comes to overall firewall management). In particular, it has a command channel (the socket which you communicate with the FTP server over) and a separate data channel per file (and also with the output of some remote commands, such as ls); that's what that Port set okay is about. This is not firewall-friendly, and it's easy to misconfigure firewalls in this area (especially when there is NAT also in place).
You might (i.e., try this first) want to use passive mode instead, as that reduces the complexity at the firewall level. Try issuing a passive before the mput (just as you currently issue a binary).
Here's a bash script I wrote with a similar function;
You should be able to adapt it to your needs.
Adding a few lines to SSH in and run the script should be quite trivial.
As a side note; why are you using TCL for this?
#!/bin/bash
fileName=`ls /home/user/downloads -t1 | head -n1`
latestFile="/home/user/downloads/$fileName"
echo $latestFile
hostname="HOSTNAME"
username="USER"
password="PASS"
ftp -inv $hostname << EOF
quote USER $username
quote PASS $password
cd transfer/jirabackup
binary
put $latestFile $fileName
quit

Resources