Image of terminal

Expect Scripting For Network Engineers (Cisco)

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.

//
// ]]>

106 comments

      1. 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?

  1. 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;}’

    1. 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.

    1. 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.

  2. 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

  3. This is an incredible example that pretty much shows me everything I need to know to automate some simple tasks. Thank you!

  4. 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.

  5. 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!

    1. 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

  6. 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?

    1. 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.

  7. 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?

  8. 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

    1. 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.

      1. 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

    2. 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

      1. 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

      2. 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.

  9. 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?

  10. 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

  11. 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

    ===================================================

    1. 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

    1. 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.

      1. 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?

    2. 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.

      1. 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.

  12. 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 🙂

    1. 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

  13. 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.

  14. /usr/bin is the typical location for expect in most linux distros incliuding fedora, redhat enterprise linux, and centos

  15. 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?

  16. 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 ??

  17. 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’

  18. 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

  19. 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!!

  20. 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.

  21. 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

  22. 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. 🙂

  23. 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

  24. 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

      1. 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

  25. 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

  26. 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

  27. 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?

    1. 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.

      1. 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~

  28. 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:~$

    1. 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

  29. 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!

    1. 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”

  30. 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.

  31. 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

  32. 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

  33. # 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.

    1. 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.

  34. 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#)

  35. 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.

  36. 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

  37. 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?

  38. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s