I am attempting to automate the change of switch configurations on multiple cisco switches. I get all the way to the config section and when the config.txt variable is sent, the output has curly brackets at the end and is not a valid command. Here is the output and below that I will post the code.
All I am trying to do is login to my switch and run the following command
configure replace flash:/thenameofconfig
The script will loop through multiple switches in the device list and apply the correct config based o
IL-test-SW1#configure replace flash:/il-test-sw2-confg} {}
Code:
#!/usr/bin/expect -f
# Set up various other variables here ($user, $password)
set username user
set password user
set enablepassword user
# Log results
#log_file -a ~/results.log
log_file -a /tmp/results.log
# Get the list of hosts, one per line #####
set f [open "device-list.txt"]
set hostname [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "configs.txt"]
set configs [split [read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hostname {
# Don't check keys
spawn ssh -o StrictHostKeyChecking=no $username\#$hostname
# spawn ssh $user#host
# expect "password:"
# send "$password\r"
# 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)#"
send "shell processing full\n"
expect "(config)#"
send "end\n"
expect "*#"
#Iterate over the commands
foreach config $configs {
expect "*#"
send "$configs\n"
expect "\[no]:"
send "y\n"
expect "*#"
}
# Tidy up
# expect "*#"
# send "exit\r"
# expect eof
# close
send "exit\n"
expect ":~\$"
exit
}
Cannot seem to get rid of the {} at the end of the configure replace command.
Any help will be greatly appreciated.
Figured it out. Was the following line
set hostname [split [read $f] "\n"]
Needs to be:
set hostname [split [read -nonewline $f] "\n"]
Related
Afternoon,
I have googled this all day and even attempted other solutions in python but not had any success.
I have some old-ish network gear that seems to have a weird terminal type when you SSH to them, the one where CTRL+h is backspace!
This is causing problems for my expect script than needs to do 3 things, 1) log in 2) escalate privileges (think cisco enable) 3) save the config
Tried to set the terminal type but not sure that vt100 is correct, i doubt it is. I also added the sleep commands to see if a delay would solve it, no dice.
here is my script so far
#!/usr/bin/expect
set ::env(TERM) vt100
## Get username
send_user "Username: \n"
expect_user -re "(.*)\n" { set user $expect_out(1,string) }
## Get pass
stty -echo
send_user "Password: \n"
expect_user -re "(.*)\n" { set pass $expect_out(1,string) }
stty echo
## Get list of hosts
set f [ open "hosts.txt"]
set hosts [ split [read $f] "\n"]
set hosts [ lreplace $hosts end end ]
close $f
## iterate host
foreach host $hosts {
spawn ssh "$user\#$host"
expect {
"continue connecting" { send "yes\r"; exp_continue }
"assword" { send "$pass\r" }
}
expect "Copyright (c)" {
sleep 1
send "\r"
sleep 1
send "en 14\r"
sleep 1
send "$pass\r"
sleep 1
send "config save\r"
sleep 1
send "exit\r"
}
}
Output from script
deanmoore#laptop% ./zyxel
Username:
dean.moore
Password:
spawn ssh dean.moore#host1
dean.moore#host1's password:
Copyright (c) 1994 - 2013 ZyXEL Communications Corp.
host1> ^[[47;223R%
deanmoore#laptop% 7;223R
I have already done an expect script. It works well. The script will read a txt file called ip_list. And then running command and output a log file. My question is if there are many different IP address in the txt file, how to modify my code to print out like one IP address for one log file?
set f [open "ip_list.txt"]
set addr [split [read $f] "\n"]
close $f
foreach addr $addr {
if {$addr eq {}} continue;
set timeout 180
match_max 1000000
spawn telnet $addr
expect {
"*timed out*" {puts "Host not responding"; continue}
"'^]'." {sleep .1}
}
expect "*login*" {send "$user\r"}
expect "*assword:*" {send "$pass\r"}
expect {
"Login incorrect" {puts "Bad Password or User"; exit}
-re {[#>] ?$} {send "page-off\r"}
}
log_file $customer\-License-$date.log
expect -re {[#>] ?$}
send "show clock\r"
sleep .5
expect -re {[#>] ?$}
send "\r"
puts "Connection closed, connecting to next one\r"
sleep 1
log_file
expect eof;
}
Any idea could help, thank you!
What I am trying to do is to:
Create a .exp file, which will read from the *.txt file from the same directory and parse all the content in the text file into a string variable in the expect script.
Loop the string, which contains a series of host names, and excecute a series of command until the string is enumerated.
So what the script does, is read a series of hostname from a txt file in the same directory, and then read them into a string, and the .exp file will auto log into each of them and excecute a series of commands.
I have the following code written but it's not working:
#!/usr/bin/expect
set timeout 20
set user test
set password test
set fp [open ./*.txt r]
set scp [read -nonewline $fp]
close $fp
spawn ssh $user#$host
expect "password"
send "$password\r"
expect "host1"
send "$scp\r"
expect "host1"
send "exit\r"
Any help is greatly appreciated....
The code should read the contents of the two files into lists of lines, then iterate over them. It ends up like this:
# Set up various other variables here ($user, $password)
# Get the list of hosts, one per line #####
set f [open "host.txt"]
set hosts [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hosts {
spawn ssh $user#host
expect "password:"
send "$password\r"
# Iterate over the commands
foreach cmd $commands {
expect "% "
send "$cmd\r"
}
# Tidy up
expect "% "
send "exit\r"
expect eof
close
}
You could refactor this a bit with a worker procedure or two, but that's the basic idea.
I'd refactor a bit:
#!/usr/bin/expect
set timeout 20
set user test
set password test
proc check_host {hostname} {
global user passwordt
spawn ssh $user#$hostname
expect "password"
send "$password\r"
expect "% " ;# adjust to suit the prompt accordingly
send "some command\r"
expect "% " ;# adjust to suit the prompt accordingly
send "exit\r"
expect eof
}
set fp [open commands.txt r]
while {[gets $fp line] != -1} {
check_host $line
}
close $fp
Using any of the two solutions here, I would also create a logfile that you can view at a later time. Makes it easy to troubleshoot any problems after the script is run, especially if you're configuring several hundred hosts.
Add:
log_file -a [log file name]
Before your loop.
Cheers,
K
I writing a script to read user name, password and host info from a file.
I then parse this info to get the variables. I would then like to add these variables to an expect script that reads all the ip address in my file and performs certain commands on the remote devices that I am trying to log into. The script works when it connects to a known host however What I am seeing is that there is one device that is not up and running and the system promps with the following error.
ssh: connect to host 192.168.3.2 port 22: No route to host
the file
I would like to do 2 things
1. Skip the host and move to the next host
2. log the host that is down to another file so that I can troubleshoot the network issue to that host.
Please see the script below. Please any help is greatly accepted.
#! /usr/bin/expect -f
## Read the file
set fid [open /csv_pars/employee1.csv]
set content [read $fid]
close $fid
## Split into records on newlines
set records [split $content "\n"]
## Iterate over the records
foreach rec $records {
## Split into fields on comma
set fields [split $rec ","]
## Assign fields to variables and print some out...
lassign $fields\ ipaddr username password
puts "$ipaddr"
puts "$username"
puts "$password"
if {$ipaddr == ""} continue
spawn ssh -X "$username#$ipaddr"
sleep 2
expect "password:"
sleep 2
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
You need to expect to see one of two things: the password prompt, or the error message:
spawn ssh -X "$username#$ipaddr"
expect {
-re "password: ?$" {
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
"No route to host" {
set fid [open error.log a]
puts $fid "[clock format [clock seconds]]: No route to host $ipaddr"
close $fid
}
}
I have a bash+expect script which has to connect via ssh to the remote comp (and i can't use ssh keys, need password identification in here), read the file there, find specific line with the "hostname" (like "hostname aaaa1111") and store this hostname into the variable to be used after while. How can i get the value of the "hostname" parameter? I thought that line content will be in $expect_out(buffer) variable (so i can scan it and analyze), but it's not. My script is:
#!/bin/bash
----bash part----
/usr/bin/expect << ENDOFEXPECT
spawn bash -c "ssh root#$IP"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \r"
expect ":~#"
set line $expect_out(buffer)
puts "line = $line, expect_out(buffer) = $expect_out(buffer)"
...more script...
ENDOFEXPECT
When i try to see line variable, i see only this: line = , expect_out(buffer) = (buffer) What is the right way to get the line from the file into the variable?
Or is it possible to open the file on the remote computer with expect, scan the file and get what i need to the variable?
Here http://en.wikipedia.org/wiki/Expect there is an example:
# Send the prebuilt command, and then wait for another shell prompt.
send "$my_command\r"
expect "%"
# Capture the results of the command into a variable. This can be displayed,
set results $expect_out(buffer)
seems that it doesn't work in this case?
You might just want to try and do it all from expect, as expect can control bash.
The following should do what you've described. Not sure if this is exactly what you are trying to do.
#!/bin/sh
# the next line restarts using tclsh \
exec expect "$0" "$#"
spawn bash
send "ssh root#$IP\r"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \n"
expect ":~#"
set extractedOutput $expect_out(buffer)
set list [split $extractedOutput "\n"]
foreach line $list {
set re {(?x)
.*
(*)
-S.*
}
regexp $re $line total extractedValue
if {[info exists extractedValue] && [string length $extractedValue] > 1} {
set exportValue $extractedValue
break # We've got a match!
}
send "exit\r" # disconnect from the ssh session
if {[info exists exportValue] && [string length $exportValue] > 1}{
send "export VARIABLE $exportValue\r"
} else {
send_user "No exportValue was found - exiting\n"
send "exit\r"
close
exit 1
}
# now you can do more things in bash if you like