Have you ever spent a good portion of your day repeatedly logging into all of the network devices in your data center to add the IP address of a new syslog server? Or perhaps removing the local user account of a former peer who jumped ship to greener pastures?
As a Network Engineer there have undoubtedly been times when you have had to make the same configuration change to a large group of devices. Unless you spent a few years honing your scripting skills as a Systems Administrator in the past, chances are that your idea of “automating” the process involved manually logging into devices and pasting the same configuration from a text file over and over.
You know that scripting could help, but who has time to learn to write code when you’re busy researching connectivity issues? After all you’re a Network Engineer and not a Developer, right?
Why Use Expect?
1. It’s Easy!
Expect is a scripting program written in Tcl that was built to automate tasks for other interactive programs, such as Cisco’s IOS and NX-OS command line interfaces. It’s rather intuitive to understand at the basic level.
Once you have a working baseline script, such as the one I am providing below, it’s fast and easy to modify it for use in any situation where you need to make the same configuration change on multiple devices.
2. It’s Already Installed
If you’re primary workstation is a Mac then there is no installation necessary! Expect is already installed in /usr/bin/expect.
3. Excellent Online Resources Available
The more you use Expect, the more you’re going to want to do with it. Luckily you don’t need to take an online course or buy the O’Reilly Media book like you would with Python and Perl. You can Google search your way to just about anything.
Simple Expect Script For Cisco Network Devices
I’m sharing a basic Expect script which you can use to make configuration changes to Cisco IOS and NX-OS devices from a Mac. If you want to run it from a Linux server, just update the path from /usr/bin/expect to wherever the program is located locally.
The script simply establishes an SSH session, enters enable mode (if you’re not already dropped in it), enters configure mode, sends whatever commands you specify, then does a write to memory before exiting and moving onto the next device. You need three files to accomplish this:
device-list.txt
This is simply a text file with IP addresses and/or hostnames of the devices with which you want the script to connect to:
core1.mydomain.com nexus1a nexus1b 10.0.0.1
configure-cisco.sh
This is a bash shell script which you will run to start the entire process. It will prompt for your ssh password and an enable password, and then feed it to the Expect script along with the contents of device_list.txt. I found this more secure then reading the passwords from a file and easier to do in bash than in expect.
#!/bin/bash # Collect the current user's ssh and enable passwords echo -n "Enter the SSH password for $(whoami) " read -s -e password echo -ne '\n' echo -n "Enter the Enable password for $(whoami) " read -s -e enable echo -ne '\n' # Feed the expect script a device list & the collected passwords for device in `cat device-list.txt`; do ./configure-cisco.exp $device $password $enable ; done
configure-cisco.exp
This is the expect script that I explained earlier. It has some intelligence built in to gracefully handle ssh connectivity issues and will send results both to the screen and to a file called results.log in your home directory:
#!/usr/bin/expect -f # Set variables set hostname [lindex $argv 0] set username $env(USER) set password [lindex $argv 1] set enablepassword [lindex $argv 2] # Log results log_file -a ~/results.log # Announce which device we are working on and at what time send_user "\n" send_user ">>>>> Working on $hostname @ [exec date] <<<<<\n" send_user "\n" # Don't check keys spawn ssh -o StrictHostKeyChecking=no $username\@$hostname # Allow this script to handle ssh connection issues expect { timeout { send_user "\nTimeout Exceeded - Check Host\n"; exit 1 } eof { send_user "\nSSH Connection To $hostname Failed\n"; exit 1 } "*#" {} "*assword:" { send "$password\n" } } # If we're not already in enable mode, get us there expect { default { send_user "\nEnable Mode Failed - Check Password\n"; exit 1 } "*#" {} "*>" { send "enable\n" expect "*assword" send "$enablepassword\n" expect "*#" } } # Let's go to configure mode send "conf t\n" expect "(config)#" # Enter your commands here. Examples listed below #send "tacacs-server host 10.0.0.5\n" #expect "(config)#" #send "tacacs-server directed-request\n" #expect "(config)#" #send "tacacs-server key 7 0000000000000\n" #expect "(config)#" #send "ntp server 10.0.0.9\n" #expect "(config)#" #send "ip domain-name yourdomain.com\n" #expect "(config)#" send "end\n" expect "#" send "write mem\n" expect "#" send "exit\n" expect ":~\$" exit
To run the script, create all three files in your Mac home directory, chmod+x the scripts, then run configure-cisco.sh.
[12/07/2012 1:45pm @paul-mac-air:~]% ./configure-cisco.sh Enter the SSH password for paul Enter the Enable password for paul > Working on core1.mydomain.com @ Fri Dec 7 13:45:22 PST 2012 < spawn ssh -o StrictHostKeyChecking=no paul@core1.mydomain.com ...
Examples of Simple Enhancements
The scripts I included above have been stripped down to the bare essentials so that there are fewer lines of code to get started with. It gets the job done, but the more you use the scripts the more you may want to enhance it.
I am by no means an expert in Expect or Bash, but I’ve spent a little time playing with both to help tailor my scripts to do the things I want. The more you use Expect, the more you may want to tailor it as well. Below are a few very basic examples.
1. Add terminal vt100 to for connecting to Nexus devices
I simply got tired of seeing this line every time I connected to a Nexus device:
Nexus 5000 Switch
Password:
Bad terminal type: “xterm-256color”. Will assume vt100.
You can specify a terminal type of vt100 by adding this line to the configure-cisco.sh script (assuming you don’t want to do it in your terminal settings):
# Set terminal to vt100 so Nexus devices don't complain export TERM=vt100
2. Save and rotate logs
I like to log all of the input from my script to a single file called “results.log” which I can then parse later and/or save for reference. To make sure I don’t overwrite a previous log file, I added a few lines of code to configure-cisco.sh to copy and rename “results.log” to “results.log.timestamp”
timestamp=`date +%m%d%H%M` logdir=~/logs/expect # This will rotate and append date stamp... logfile=$logdir/results.log newlogfile=$logfile.$timestamp cp $logfile $newlogfile
Summary
Expect is the perfect tool for easily automating redundant tasks and configuration changes on network equipment. It’s preloaded on Mac OS X and simple to install on server running the Linux flavor of your choice. You don’t need to fully dive in to the language in order to take advantage of it’s time saving capabilities.
//
// ]]>
do you have any book recommendations for expect?
Yes, “Exploring Expect” by O’Reilly Media: http://shop.oreilly.com/product/9781565920903.do
I am new to scripting so pardon the redundant ???, but how would you make it read the hostname, and put actual hostname for file not the IP?
I love your blog, keep doing what u r doing.
Thank you, I appreciate the positive feedback!
Thank you for this! Any idea why I get the following output when trying to run the script?
./configure-cisco.sh: line 1: {rtf1ansiansicpg1252cocoartf1187cocoasubrtf370: command not found
./configure-cisco.sh: line 2: syntax error near unexpected token `}’
./configure-cisco.sh: line 2: `{\fonttbl\f0\fnil\fcharset0 Consolas;\f1\fnil\fcharset0 Consolas-Bold;}’
It looks like Rich Text formatting is in the script you are trying to run, so I am assuming you created it with some sort of text editor. Try saving the file as plain text or using the vi editor from within a terminal window to create it.
You were right. I switched to TextWrangler and all is good now. Thanks so much!
Happy to help!
Don’t you think Perl would be easier than Expect ?
No. Expect is designed for interacting with CLI’s and works extremely well for these type of network administration tasks. Perl is more difficult to learn for people who don’t have a programming background.
with Expect you need to learn Bash scripting too.. I will consider both and your advice as I am trying to come up with scripts for Cisco devices . Thanks
You might also want to check out Python. Cisco has embraced it to the point where the Nexus line has a Python API. That’s on my agenda for Q3.
This is an incredible example that pretty much shows me everything I need to know to automate some simple tasks. Thank you!
This has solved my problem, namely a script to ssh onto a switch which displays a message before asking for the password. I couldn’t find a perl example that could deal with that.
Thanks for this post!
Question – At my work I ssh into the ASR device then from the ASR I telnet to each switch…. ACL only allows ASR device to telnet to each switch I can’t ssh/telnet to the switches directly… How would I go about scripting that??? thanks!
Hi Bob,
This can be done with a for loop within the configure-cisco.exp script.
Create a file with the names/IP’s of the devcies you want to connect to from the ASR:
pporter@ops002:~$ cat my_devices
sw-001
sw-099
Then modify a script like this to suit your needs (please note that WordPress might be converting the greater-than symbot to ASCII below)
#!/usr/bin/expect -f
# Set variables - some of which were sent from the calling bash script
set hostname [lindex $argv 0]
set username $env(USER)
set password [lindex $argv 1]
set enablepassword [lindex $argv 2]
set timeout 5
spawn ssh -o StrictHostKeyChecking=no $username\@$hostname
expect "*assword: "
send "$password\r"
# SSH to each IP/Hostname in local file named "my_devices", do a "show clock", then exit
set devicelist [open my_devices]
while {[gets $devicelist line] != -1} {
expect "*>"
send "ssh $line \n"
expect "Password:"
send "$password\r"
expect "*>"
send "show clock\n"
expect "*>"
send "exit\n"
expect "*>"
}
close $devicelist
send "exit\n"
expect ":~\$"
exit
thx Paul!
Hi nice script. I have an off question about your blog. How are you displaying the code in the language colours?
WordPress code tag:
http://en.support.wordpress.com/code/posting-source-code/
I have another question. What if you want to put this in just one file? Cant you put the expect part in a function and call it from the bash script so I just deal with one file? How will I achieve that easily?
My goal was to make this easy for Network Engineers who don’t have a strong scripting background to follow. Keeping the Bash separate from the Expect seemed to be the best way to do that.
If you combine the two into a simple, single script then please post it as a comment so others can check it out.
Thanks for the reply, If I figure it out I ll let you know.
Oh how can I use this:
/usr/bin/expect<<EOF
expect eof
EOF
I know you can put the expect script in that but how do I incorporate it in your script?
I’m really interested in this script and I tried to do a test run but no luck. I created all 3 files in vim editor. I copied everything in the .exp file except:
# Enter your commands here. Examples listed below
#send “tacacs-server host 10.0.0.5\n”
#expect “(config)#”
#send “tacacs-server directed-request\n”
#expect “(config)#”
#send “tacacs-server key 7 0000000000000\n”
#expect “(config)#”
#send “ntp server 10.0.0.9\n”
#expect “(config)#”
#send “ip domain-name yourdomain.com\n”
#expect “(config)#”
ran configure-cisco.sh from /Users/username/ but I get configure-cisco.sh: command not found
even when I do sudo
What does “echo $PATH” give you? What about an “ls -la” of the directory where you put the files? It sounds like the file is not in the directory where you think it is or you made a typo when creating the file name.
Paul
The results of what you were asking:
$PATH
/sw/bin:/sw/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11R6/bin
ls -la:
-rw-r–r– configure-cisco.exp
-rw-r–r– configure-cisco.sh
-rw-r–r– device-list.txt
pwd:
/Users/myusername
Thanks
Mike
Hey Mike,
You missed the part that made these executables. Please do a “chmod +x” for the shell script and expect script.
Because that command “configure-cisco.sh” off course does not exist.
Run “bash configure-cisco.sh” or “./ configure-cisco.sh” with out the quotes of course. the file needs to be executable try the second option but the first should work regardless
That seems to work but I get the following results:
Enter the SSH password for myusername
Enter the Enable password for myusername
configure-cisco.sh: line 11: ./configure-cisco.exp: Permission denied
myusername-MacBook-Pro:~ myusername$
I guess I’m looking for a good reference to be able to interpret the syntax. My interpretation is
1)device-list.txt – everything in here will be included in the batch process
2)configure-cisco.sh – apply password for devices in device-list.txt and configure-cisco.exp.
3)configure-cisco.exp – Finally apply the syntax to do ios upgrades, tacacs information etc.
Thanks,
Mike
You got the permission denied because the expect script isn’t executable (see my other comment).
Yes, that is basically what is going on. To be more specific, the bash script is also running a loop and applying the settings specified in the expect portion for every host name it sees in the device list.
Keep working on it and feel free to post more questions if you have them. Once you get this working you’ll be thankful you stuck with it. My infrastructure is over 200 devices and it’s a breeze to push out any sort of config change.
If you’re referring to the chmod command I did a chmod 755 on all 3 files. I’m primarily a PC guy but about 5 years ago I started experimenting with FreeBSD and because of that I was able to get around in the command line on my Macbook. I did notice the for, in and do which I suspected was applying a loop.
Results I’m getting when I run bash configure-cisco.sh are:
Myusername-MacBook-Pro:~ Myusername$ bash configure-cisco.sh
Enter the SSH password for Myusername
Enter the Enable password for Myusername
./configure-cisco.exp: line 1: et: command not found
./configure-cisco.exp: line 3: syntax error near unexpected token `(‘
./configure-cisco.exp: line 3: ` set username $env(USER)’
each script has -rwxr-xr-x and I’m the owner so this should be correct?
Hey Mike, thanks for emailing me the files you were using. Make the corrections I suggested and you should be good to go. Enjoy!
Hey, Paul:
Thanks for posting the expect script. I’ve been developing a bash script for 6 years to automate a configuration inventory of hundreds of network devices (different makers). It works well, but it was completely automatic only with telnet connections. Nowadays we are using ssh v2 connections, so automation of this inventory script was not complete and I needed to add password from the keyboard at connection time.
Thanks again for sharing your knowledge. I will try your suggestions.
Javier
You’re welcome and I hope it can be of help! Thanks for taking the time to leave a comment
Cheers,
– Paul
Hi Paul,
I’m quite blind in scripting thingy, would you mind to share the command if using the telnet?
==================================================
“configure-cisco.sh
This is a bash shell script which you will run to start the entire process. It will prompt for your ssh password and an enable password, and then feed it to the Expect script along with the contents of device_list.txt. I found this more secure then reading the passwords from a file and easier to do in bash than in expect.
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Collect the current user’s ssh and enable passwords
echo -n “Enter the SSH password for $(whoami) ”
read -s -e password
echo -ne ‘\n’
echo -n “Enter the Enable password for $(whoami) ”
read -s -e enable
echo -ne ‘\n’
# Feed the expect script a device list & the collected passwords
for device in `cat device-list.txt`; do
./configure-cisco.exp $device $password $enable ;
done
”
===================================================
Hi Rohayu,
In the configure-cisco.exp script, replace this:
# Don’t check keys
spawn ssh -o StrictHostKeyChecking=no $username\@$hostname
With this:
# Telnet
spawn telnet $hostname
expect “Username: ”
send “$username\r”
expect “*assword: ”
send “$password\r”
Let me know if that doesn’t work for you.
Thanks,
– Paul
Found the telnet option already. Anyway, how if we’re using list of devices that running with the different list of passwords on each devices. Any idea?
Yes it can definitely be done, but you would have to sacrifice security by putting all of those passwords in the device-list.txt file (putting passwords in text files is a very bad idea!) and modify the bash script to use something like awk to parse it and send a hostname and password to the expect script. You’re probably better off modifying the expect script so that it waits for you to manually enter the password for each device.
How do you modify the script to manually prompt for password?
Hello Paul,
I’m facing the same issue that Rohayu has. is it possible to provide an example of how to use awk to accomplish this?
I’m having a hard issue. I have your script in linux and yum installed expect. I only have root user in the linux machine. I’m trying to get ur script to work.
In configure-cisco.sh: I change the $(whoami) to a real user in TACACS server for accessing all cisco devices.
#!/bin/bash
# Collect the current user’s ssh and enable passwords
echo -n “Enter the SSH password for $(mike10) ”
read -s -e password
echo -ne ‘\n’
echo -n “Enter the Enable password for $(mike10) ”
read -s -e enable
echo -ne ‘\n’
# Feed the expect script a device list & the collected passwords
for device in `cat device-list.txt`; do
./configure-cisco.exp $device $password $enable ;
done
I get this error:
[root@localhost script]# ./configure-cisco.sh
./configure-cisco.sh: line 3: mike10: command not found
Enter the SSH password for
./configure-cisco.sh: line 6: mike10: command not found
Enter the Enable password for
I’m trying to do TELNET as the switches don’t do SSH.:
I deleted these two lines and add the #Telnet.
deleted:
# Don’t check keys
spawn ssh -o StrictHostKeyChecking=no $username\@$hostname
added:
# Telnet
spawn telnet $hostname
expect “Username: ”
send “$username\r”
expect “*assword: ”
send “$password\r”
The telnet doesn’t work either. Any suggestions would be great.
Your echo lines should read like this:
echo -n “Enter the SSH password for mike10 ”
In the expect script make the following change:
#set username $env(USER)
set username mike10
Things should flow from there.
Hi Paul,
Thanks for the reply. 🙂
hi paul, i have this kind of environment, i need to ssh to the server A, then from this server, i have to telnet several switches and routers and collecting some logs.
let say,
server A, 10.0.0.1 password: abc123
switch B, 10.0.0.2, telnet password: def456, enable password: ghj123
switch C, 10.0.0.3, telnet password: def123, enable password: ghj456
.
.
.
router Z, 10.0.0.2, telnet password: def789, enable password: ghj789.
if you don’t mind, would you share an example of the script to make this work.
Thanks a lot 🙂
Hi Clara,
If you don’t have the ability to run the script from the jump-host you are SSH’ing to then you could try changing the bash script so that it first calls a different expect script that logs you into the jump host. Once connected, the next expect script could take over and run the commands.
If you have different usernames and passwords for each network device then your best bet would be to configure your iOS devices to use RSA Auth (keys) rather than passwords. You could then write a script that parses a file of usernames mapped to devices without the need to also include the password.
Thanks,
– Paul
Hi Paul,
I have a requirement to test reboot cases. So, i have to spawn a telnet session to console, issue reboot and expect the prompt back, check the time taken to reboot.
Any graceful way to automate this in expect.
In the current script I have (simple spawn, reboot, expect prompt), sometimes hit the ‘eof’ before reboot and the process terminates.
/usr/bin is the typical location for expect in most linux distros incliuding fedora, redhat enterprise linux, and centos
Hi
Can you recommend any good book for python like “Exploring Expect” for automating tasks?
Paul,
What if your Cisco username is not the whoami on Linux?
# Collect the current user’s ssh and enable passwords
echo -n “Enter the SSH password for $(whoami) ”
read -s -e password
echo -ne ‘\n’
echo -n “Enter the Enable password for $(whoami) ”
read -s -e enable
echo -ne ‘\n’
Can it be replaced with another Username/Password?
Thanks Paul for your fantastic blog, but i have a question
i am running your script on a linux redhate machine, but the script is unable to locate the device-list.txt file, where should i place this file ??
Thanks so much for this!
It works in my environment except for the logging…
Please provide any addition insight if you can.
Here’s the error(s) I’m getting.
./configure-cisco.sh: command substitution: line 10: syntax error near unexpected token `newline’
./configure-cisco.sh: command substitution: line 10: `cat device-list.txt’
Paul, this script is awesome! I just used it deploy a change to all 50 switches on my campus. Thank you!
Hi paul,
Thanks for really helpful and qualitative lesson on expect script.
I am new to the same field and also trying to write an script.
This is what i am trying to do we have a tool network automation to execute the scripts successfully on HP switches.
I am trying to update the ACL on all HP switches. by entering the given set of commands.
first will login to the switch.
I understand from above this can be achieved through
# Allow this script to handle ssh connection issues
expect {
timeout { send_user “\nTimeout Exceeded – Check Host\n”; exit 1 }
eof { send_user “\nSSH Connection To $hostname Failed\n”; exit 1 }
“*#” {}
“*assword:” {
send “$password\n”
}
}
given set of command
remove old ACL’
then readd acl
then add back to vlan 1
then wr mem
to remove acl
conf t
no access-list “grp name”
conf t
vlan 1′
no ip access-group “group name” in
exit’
no access-list “acl name”
(config)# INSERT NEW ACL HERE
(config-ext-nacl)exit
(config)# vlan 1
(vlan-1)# ip access-group “group name” in
(vlan-1)# exit
(config)# exit
Hi Paul,
I stumbled upon your blog when searching for expect ssh login script for Cisco IOS devices.
With your research we were able to adjust the scripts to our needs and automate and capture information from a lot of devices.
Thanks for your effort!!
Paul, thank you for this fantastic blog.
Your example was perfect to my needs and I could automate a very boring job a have, involving 34 routers in my company’s network.
Now, typing my user and password one time, I get the job done in all routers at once, in 4 minutes only.
It’s a shame, I was expending 40 ~ 50 minutes to do it manually before find your site.
My task envolves collect CRC on all routers once a week and clear counters after that.
Now it’s easy..
Thks a lot and congratulations.
Hi Paul, very nicely put together !
is it possible to omit the output to the tty and write the output of i.e. “show tech” directly into a file ? How could this be done ?
I would like to keep the shell windows free for status messages and it would potentially be more performant, as displaying this much text also takes some time to display.
Many thanks !
Andreas
Andreas
I found that the output can be recorded into a file by altering the expect script feed part of the shell script to:
for device in `cat device-list.txt`; do
./configure-cisco.exp >> output.txt $device $password $enable ;
done
This will append the STDOUT to output.txt in the local directory. If you wanted to watch the output at the same time, send the script in to the back ground by running it, enter your username & password press ctrl-z which will pause the process. Now type the bg command to un-pause it and set it running in the background.
To watch the file you can run: tail -f ./output.txt
I have just run a batch of over 1100 devices to run a show inventory and update the access lists.
kudos to Paul for a great time saving piece of scripting. 🙂
I get the following error with a script that’s worked great before:
spawn ssh -o StrictHostKeyChecking=no example@*.*.*.*
Protocol major versions differ: 2 vs. 1
I’m just looking for the simplest way to resolve this without reinventing the wheel.
#!/usr/bin/expect -f
# Set variables
set hostname [lindex $argv 0]
set username example
set password [lindex $argv 1]
set enablepassword [lindex $argv 2]
set timeout 100
# Log results
log_file -a ~/results.log
# Announce which device we are working on and at what time
send_user “\n”
send_user “>>>>> Working on $hostname @ [exec date] <<<<” {
send “enable\n”
expect “*assword”
send “$enablepassword\n”
expect “*#”
}
}
# Let’s go to configure mode
send “conf t\n”
expect “(config)#”
# Enter your commands here. Examples listed below
send “hostname test\n”
expect “(config)#”
send “end\n”
expect “#”
send “write mem\n”
expect “#”
send “exit\n”
expect “:~\$”
exit
I get the following error for an expect script that was working perfectly find before and I’m very confused by this error:
spawn ssh -o StrictHostKeyChecking=no example@10.2.3.118
Protocol major versions differ: 2 vs. 1
I’m just trying to figure out the easiest way to resolve this without reinventing the wheel:)
#!/usr/bin/expect -f
# Set variables
set hostname [lindex $argv 0]
set username example
set password [lindex $argv 1]
set enablepassword [lindex $argv 2]
set timeout 100
# Log results
log_file -a ~/results.log
# Announce which device we are working on and at what time
send_user “\n”
send_user “>>>>> Working on $hostname @ [exec date] <<<<” {
send “enable\n”
expect “*assword”
send “$enablepassword\n”
expect “*#”
}
}
# Let’s go to configure mode
send “conf t\n”
expect “(config)#”
# Enter your commands here. Examples listed below
send “hostname test\n”
expect “(config)#”
send “end\n”
expect “#”
send “write mem\n”
expect “#”
send “exit\n”
expect “:~\$”
exit
Try forcing SSH on your local host to use version 2:
spawn ssh -2 -o StrictHostKeyChecking=no example@10.2.3.118
Hi Paul,
I tried this recommendation and it didn’t work. I even tried
spawn ssh -2 -o StrictHostKeyChecking=no $username\@$hostname
This syntax is preferable b/c I’m using TACACS AAA with an ACS. This was a working config but I get the following
Password:
Sorry, try again.
Password:
Thanks for your help
Mike
hi,
if i use expect on windows platform, can i use this script? and which kind of modification do i made to perform it operational on windows platform…
modify /usr/bin ?
thanks
hi,
i’ve installed expect on windows platform, does the script is operational on it?
And which kind of modification do i made to perform it operational on windows platform…
modify the path /usr/bin with c:\… ?
thanks
Sorry, I know Expect for Windows exists but I have never used it nor tried doing any scripting on a Windows platform before.
Hey there~
Great post you have there! Just what I needed. However, do you know of any way to extract the configuration changes from a config/text file instead of hard-coding them into the ‘send’ commands? The script could be much more useful and flexible if we could do this, instead of having to mod the script everytime it’s something different.
Btw we have a large amount of devices which depend on radius, and my current solution of them is to use the ‘interact’ function to pause so that I can key in my token key. I can’t think of any better method, but do you have any other suggestions on that as well?
Thank you, I am glad you found this post helpful.
I’m sure there is a way to rewrite this so that you can feed it a file and not have to deal with the “send” and “expect” commands, but personally I would use python and do a total rewrite.
When it comes to two-factor auth you’ll have to break the automation one way or another. Here’s a method I have used in the past:
spawn ssh -o StrictHostKeyChecking=no your-username\@$hostname
expect “ "
stty -echo
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set passcode $expect_out(1,string)
send "$passcode\r"
expect "#"
I doubt it’s any better than the interact method you are using. This is a situation where using a tool like HP Network Automation and SNMP to push configuration changes would be a real time saver.
Thanks for your swift reply~ Well I’m actually quite new to scripting too so I’ll probably stick to bash and expect first till I get better since I have no experience with python at all.
Your method for the two factor authentication works as well, but I’ll probably stick to the interact since it’s just 1 line of code.
And as a good news, not sure whether it’s of benefit to you, but maybe to the rest who reads the comments, I managed to successfulload the configuration from a file!
The slight change in the script is as below:
—————————-
set configfile [lindex $argv X]
.
. output ommited
.
expect “*(config)#$”
set filereader [open $configfile r]
while {[gets $filereader read_line] != -1} {
# send_user “Acquired line: $read_line\n”
send “$read_line\n”
expect “*(config*)#$”
}
close $filereader
——————————
I was using the ‘send_user’ line just to verify that the file was being read correctly and the lines were acquired properly, it’s not really needed in the actual function thats why it’s commented out.
And the (config*)# match is because I had a problem when the config mode entered line or interface configuration where it would display (config-if) or something else instead.
Right now it doesn’t have any ‘error detection’ mechanism but you guys could probably add in your own.
Cheers~
Why I am getting this message? The device-list.txt file is created.
yc@ubuntu:~$ #!/bin/bash
yc@ubuntu:~$ # Collect the current user’s ssh and enable passwords
yc@ubuntu:~$ echo -n “Enter the SSH password for $(whoami) ”
Enter the SSH password for yc yc@ubuntu:~$ read -s -e password
yc@ubuntu:~$ echo -n “Enter the Enable password for $(whoami) ”
Enter the Enable password for yc yc@ubuntu:~$ read -s -e enable
yc@ubuntu:~$ # Feed the expect script a device list & the collected passwords
yc@ubuntu:~$ for device in `cat device-list.txt`; do
> ./configure-cisco.exp $device $password $enable ;
> done
cat: device-list.txt: No such file or directory
yc@ubuntu:~$
It looks like you have just pasted the shell script in to the shell. Paste it in to a new file then change the permissions so it’s executable (chmod +x filename)
Check the permissions of the device-list.txt, ensure it is readable and that it is in the same directory as the script you have just created.
If the device list is in a different directory you will need to amend the script accordingly.
-rwxrwxr-x 1 adam adam 1.3K Jan 7 19:22 configure-cisco.exp
-rwxrwxr-x 1 adam adam 410 Jan 7 19:22 configure-cisco.sh
-rw-r–r– 1 adam adam 124 Jan 7 19:22 device-list.txt
Hello Paul,
Great article! I’m trying to automate the process of adding a couple of ACL’s to about 400 3750V2 switches. However, when I execute the script, and I reach a “send” command which includes an IP-address it all goes wrong. It seems to me te dot in the IP address is trying to bind a variable or something.
So when I execute:
send “access-list 10 permit 10.0.0.1”
expect “(config)”
The output is all messed up, something along the lines of: “$permit 10.0.0.exit”
Do you have any clue on what is going wrong? I’m using active TCL on Windows. It looks to me I need to escape the ‘dots’ in the IP address somehow? Thanks!
Are you including the /n at the end of your send strings? It could also be a problem with your editor inserting hidden characters. You dont have to escape dots in Expect.
How excerpt of how I use mine to update an access list:
expect “(config-std-nacl)#”
send “permit 192.168.50.1\n”
expect “(config-std-nacl)#”
send “end\n”
Hi Paul,
I’m wondering if there’s way to store expect send output to an expect variable? and then apply that store variable to another expect send command to the device. Thanks.
Hi Paul,
This is very interesting block. I have one issue regarding parallel reload (Cisco switches). Actually we are using HA Library to connecting devices. My requirement is if i have three switches A,B,C . I will connect three boxes then store to different Handles. By using “foreach” i issue reload command on all switches. But i am struck here How to store background process (entire reload process) of these boxes. I won’t wait for switch by switch UP. i need entire switches up.
I would appreciate if you help me this issue.
Thanks
how would you save the report.log to attach the IP of switch/router it generated it from. So for example it can be used for automatic comparisons. thanks
# If we’re not already in enable mode, get us there
expect {
“*#” {}
}
expect {
“*>” {
send “enable\n”
expect “*assword”
send “$enablepassword\n”
}
}
For the above section, the script just halts at the below step for 10 seconds (default timeout)
For devices that are not already in enable mode, it halts at
deviceA>
After 10 seconds,
deviceA>enable
For devices that are already in enable mode, it halts at
deviceB#
After 10 seconds,
deviceB#conf t
Is there anyway to make this faster by altering the above portion of the script? I thought of using “set timeout 5” at the top, but that would impact “copy run sta” of some devices which takes more than 5 seconds.
You can set a lower timeout (I don’t remember what the default is) and use “sleep ” where you want the script to pause.
One other thing – if it’s timing out then it’s not receiving the characters it is expecting. You should also try modifying the expect portion and see why it’s not seeing a match. I’ll have to revisit the script and see if there are some improvements that I could make.
Adding sleep sounds like a good idea.
The problem is that some of the devices in my inventory are in User Exec Mode (>) and some in Privileged Mode (#) after I SSH. Hence I had to alter the script to expect both “*#” {} & “*>” { before entering Global Configuration Mode (config#)
Paul,
I completely new to scripting, great script I have set to save configs as ip+date.txt for my switches, but I need to be able to save them as hostname+date.txt not sure what is better way.
Hi Paul,
Thanks for sharing the script, I edit it as per below just for me to run the show commands and save it to the log file. I have a question, what should I add if wanted it to capture the output into separate logs file as per each device in the device-list.
Hope you can help 😀
#!/usr/bin/expect -f
# Set variables
set hostname [lindex $argv 0]
set username $env(USER)
set password [lindex $argv 1]
set enablepassword [lindex $argv 2]
# Log results
log_file -a ~/results.log
timestamp=`date +%m%d%H%M`
logdir=~/logs/expect
# This will rotate and append date stamp…
logfile=$logdir/results.log
newlogfile=$logfile.$timestamp
cp $logfile $newlogfile
# Announce which device we are working on and at what time
send_user “\n”
send_user “>>>>> Working on $hostname @ [exec date] <<<<” {
send “enable\n”
expect “*assword”
send “$enablepassword\n”
expect “*#”
}
}
# Let’s go to configure mode
# send “conf t\n”
# expect “(config)#”
# Enter your commands here. Examples listed below
send “term len 0\n”
expect “#”
send “sh int status\n”
expect “#”
send “sh ip int brief\n”
expect “#”
#send “ntp server 10.0.0.9\n”
#expect “(config)#”
#send “ip domain-name yourdomain.com\n”
#expect “(config)#”
send “end\n”
expect “#”
#send “write mem\n”
#expect “#”
send “exit\n”
expect “:~\$”
exit
how could i change the script so that i can manually enter a username instead of it using the username i am logged into with on the linux box?
Hello Paul,
I am a NOC engineer. I wanted to go learning scripts to automate tasks. So which scripting language should i go for. Expect/TCL or Python?
Thanks.