I am new to scripting. How can I write an Expect script to ssh into a device and prompt the user for password? We use a pin + RSA token code as the password so I can't store the password.
#!/usr/bin/expect -f
spawn ssh device1
You will need to use the interact command to type in the password yourself.
The below skeleton should get you on your way:
set prompt "$"
spawn ssh user#host
set timeout 10
expect {
timeout {
puts "Unable to connect"
exit 1
}
#Authenticty Check
"*(yes/no)?" {
send "yes\r"
exp_continue
}
"assword: " {
#Hand control back to user
interact -o "\r" exp_continue
}
"$prompt" {
puts "Cool by the pool"
}
}
I have used this code before to achieve what you wish to achieve. You can take it as a reference point to write your own version of the code.
#!/usr/bin/env expect -f
set passw [lindex $argv 0]
#timeout is a predefined variable in expect which by default is set to 10 sec
set timeout 60
spawn ssh $user#machine
while {1} {
expect {
eof {break}
"The authenticity of host" {send "yes\r"}
"password:" {send "$password\r"}
"*\]" {send "exit\r"}
}
}
wait
#spawn_id is another default variable in expect.
#It is good practice to close spawn_id handle created by spawn command
close $spawn_id
Source: Expect Wiki
The below code will ask the user to enter the password and will use it further in the script where a password will be asked. Just as $pass.
Grabbing password to be used in script further
stty -echo
send_user -- "Enter the password: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set pass $expect_out(1,string)
Related
I have 2 remote machines lets call them A and B.
I want to transfer files from A to B.
My expect script:
#!/usr/bin/expect
set cmd [lindex $argv 0]
set password1 [lindex $argv 1]
set password2 [lindex $argv 2]
spawn bash -c "$cmd"
expect {
-re ".*es.*o.*" {
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" {
exp_send "$password1\r"
exp_continue
}
-re ".*sword.*" {
exp_send "$password2\r"
}
}
The expect script is used in a shell script:
expect $my_path/my_expect_script.exp "scp -r $remote_A_user#$remote_A_host:$file_path/* $remote_B_user#$remote_B_host:$file_path" $remote_A_password $remote_B_password
Always the script returns an error when entering password for the first time, in the same execution the next attempt works.
yes
qa#172.23.0.2's password:
Permission denied, please try again.
Sometimes some files are not copied to remote B.
Do you know how can I manage to execute a scp expect script on 2 remotes.
Thanks,
First, after you authenticate successfully, there are no more commands in the script, so expect exits and that kills scp. To wait for scp to finish, you have to wait for eof
Next, assuming the file transfer takes more than 10 seconds, you should set the timeout value to Infinity: set timeout -1
Last, the 2nd password will never be sent: the first password prompt will always match first. If those are meant to be two distinct password prompts, you need to make them match some unique text about the different hosts.
Also, indentation aids comprehension
spawn bash -c "$cmd"
set timeout -1
expect {
-re ".*es.*o.*" { # <== this is meaningless to the reader: add a whole word
exp_send "yes\r"
exp_continue
}
-re ".*sword.*" { # <== need something more here
exp_send "$password1\r"
exp_continue
}
-re ".*sword.*" { # <== need something more here
exp_send "$password2\r"
exp_continue
}
eof
}
I am trying to have an expect script inside a bash to login to a router, execute a command and store output in a text file.
#!/usr/bin/bash
FQDN=$1
LogFile=/tmp/Router_${FQDN}.txt
> $LogFile
expect -d <<EOF > $LogFile
set timeout 20
set FQDN [lindex $argv 0]
set Username "user"
set Password "***$$$"
spawn ssh $Username#$FQDN
expect "*assword:"
send "$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
expect eof
EOF
cat $LogFile
I am getting the below error message.
system personnel =\r\r\n= may provide the evidence of such monitoring to law enforcement officials. =\r\r\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==\r\r\npassword: "
send: sending "\n" to { exp6 }
expect: does "" (spawn_id exp6) match glob pattern "#"? no
password:
Enter old password:
Based on the error it appears that script is hitting the {return} key "\r" which is not to be sent at password prompt.
I don't have a return once i ssh. Not sure where i am going wrong.
This is my expect script which is working fine. Its only when i code this inside a bash script its failing.
#!/usr/bin/expect -f
set timeout 20
set FQDN [lindex $argv 0]
set Username "user"
set Password "***$$$"
spawn ssh -o "StrictHostKeyChecking no" $Username#$FQDN
expect "*assword: "
send "$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
-Abhi
In a here-doc, variables like $Username and $Password are being expanded by the shell, so they're not seen as literals for Expect to expand. Since those shell variables aren't set anywhere, they're being expanded to null strings. As a result, it's executing ssh #$FQDN and sending an empty password.
You need to escape the $ so that Expect can process them.
You also don't need the set FQDN line in the Expect script, since you're using the shell variable for that.
#!/usr/bin/bash
FQDN=$1
LogFile=/tmp/Router_${FQDN}.txt
> $LogFile
expect -d <<EOF > $LogFile
set timeout 20
set Username "user"
set Password "***$$$"
spawn ssh \$Username#$FQDN
expect "*assword:"
send "\$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
expect eof
EOF
cat $LogFile
Or you could set them as shell variables, just like FQDN.
#!/usr/bin/bash
FQDN=$1
Username=user
Password="***$$$"
LogFile=/tmp/Router_${FQDN}.txt
> $LogFile
expect -d <<EOF > $LogFile
set timeout 20
spawn ssh $Username#$FQDN
expect "*assword:"
send "$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
expect eof
EOF
cat $LogFile
i wonder what may be wrong here
I do an sftp expect script which will prompt me for password, but never seems to send the password in. Or if it does send it encrypted, we still do not get to the sftp prompt. Any ideas?
cd /proj/eiffel004_config_fem107/slaves/RHEL6.4_GE_3/workspace/Remote_Agent_Test/
/usr/bin/expect << 'EOF'
set timeout -1
spawn sftp root#server
expect {
"*assword: "
}
send "thePassword \r"
expect {
"sftp> "
}
send "put filename \r"
expect {
"100"
}
send "exit \r"
EOF
Output is
+ cd /proj/eiffel004_config_fem107/slaves/RHEL6.4_GE_3/workspace/Remote_Agent_Test/
+ /usr/bin/expect
spawn sftp root#server
Connecting to server...
Warning: Permanently added 'server,102.44.79.32' (RSA) to the list of known
hosts.
root#server's password:
I have a bash script that calls an expect script with a password that initiates the ssh process:
#!/usr/bin/bash
/usr/bin/expect $PWD/sshScript.exp $SSHPASSWORD
The expect script calls the ssh command, waits for prompt to enter password and sends in the password.
#!/usr/bin/expect
set password [lindex $argv 0];
spawn ssh -o "StrictHostKeyChecking no" username#host
expect "Enter your AD Password:" {
send "$password\r"
}
I can get the remote server to ssh correctly and display the [user#host ~]$ but I want to add to the expect script a way to automatically run a bash script that is stored in the same location as the other two scripts.
I've tried to
a) scp the file to the remote and call it in the server but I can't seem to get expect to send any text pass the password
b) do spawn ssh -o "StrictHostKeyChecking no" username#host < secondscript.shto send in the script to run but it won't wait for the password to be entered before trying to run the script.
You may combine you bash and expect script together and use it to copy the 3rd bash script to the remote server, execute it and return the output.
Here's a simple NON-TESTED example:
#!/bin/bash
[... other bash code here ...]
SCRIPT='/path/to/script/to/run/remotely.sh'
LOGIN='test'
IP='your ip or hostname'
LOCATION='/destination/path/to/script/to/run/remotely.sh'
### start expect part here, you may add '-d' after 'expect' for debug
/usr/bin/expect << EOD
### set a 3 minute timeout
set timeout 180
### copy the script you wish to run on the remote machine
spawn scp -o StrictHostKeyChecking=no -p $SCRIPT $LOGIN#$IP:$LOCATION
expect {
timeout { send_user "\n# TIMED OUT. HOST NOT REACHABLE #\n"; exit 3 }
"*assword: "
}
send "your_password\r"
expect {
"*assword: " { send_user "\n# Incorrect Password. Login Failed. #\n"; exit 4 }
"100%" { send_user "\nFile copied\n" }
}
### ssh to remote server to run script
spawn ssh $LOGIN#$IP
expect {
timeout { send_user "\n# TIMED OUT. SSH DAEMON or PORT 22 CLOSED #\n"; exit 6 }
"*assword: "
}
send "your_password\r"
expect {
timeout { send_user "\n# TIMED OUT. PROMPT NOT RECOGNISED! #\n"; exit 7 }
### expect the prompt symbol
-re {[#>$] }
## execute your script on the remote machine
send "$LOCATION\r"
expect {
"enter what you expect here" { send_user "\nRESULT: Message based on what you set the expect to read $IP\n" }
-re {[#>$] }
}
[... other expect code here ... ]
### exit remote ssh session
send "exit\r"
### end of expect part of script
EOD
### continue bash script here
[... other bash code here ...]
I am trying to write an expect script which would ssh into a server, send sudo su, then check the iptables status and put the output in a log file on the server. Below is the script.
1 #!/usr/bin/expect
2 exp_internal 1
3 log_user 0
4 set timeout 10
5 set password "******"
6
7 spawn /usr/bin/ssh -l subhasish *.*.*.* -p 10022
8
9 expect {
10 -re "password: " {send "$password\r"}
11 -re "$ " {send "sudo su\r"}
12 -re "[sudo] password for subhasish:" {send "$password\r"}
13 -re "# " {send "service iptables status\r"}
14 }
15 set output $expect_out(buffer)
16 send "exit\r"
17 puts "$output\r\n" >> output.log
But while run in debug mode, I am getting error like this;
expect -d testcase
expect version 5.44.1.15
argv[0] = expect argv[1] = -d argv[2] = testcase
set argc 0
set argv0 "testcase"
set argv ""
executing commands from command file testcase
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {24105}
invalid command name "sudo"
while executing
"sudo"
invoked from within
"expect {
-re "password: " {send "$password\r"}
-re "$ " {send "sudo su\r"}
-re "[sudo] password for subhasish:" {send "$password\r"}
..."
(file "testcase" line 9)
Not sure where I am going wrong. It says invalid command name "sudo", I guess this is because expect doesn;t understand these command. How to go around it. Please help. Thanks.
The problem is in this line
-re "[sudo] password for subhasish:" {send "$password\r"}
In Tcl (and hence in expect) the square brackets are the syntax for command substitution (like backticks in the shell). So you either need to escape the brackets or use different quotes that prevent various expansions:
-re {[sudo] password for subhasish:} {send "$password\r"}
That brings up a different issue: are you expecting to see these exact characters? Because you're instructing expect to treat that as a regular expression, and square brackets in a regular expression means a character class, so it will match a single character, either a 's', 'u', 'd' or 'o'. So what you probably need is this:
-re {\[sudo\] password for subhasish:} {send "$password\r"}
or
-ex {[sudo] password for subhasish:} {send "$password\r"}
Thanks Glenn, it's working now. One more reason why it was not working was it requires to sleep between normal login and sudo login, otherwise "sudo su" were being sent before the $ prompt returned, for reference to others, here is the code,
#!/usr/bin/expect -f
#! /bin/bash
set timeout 60
log_user 1
set host *.*.*.*
set password ******
set user subhasish
set logfile output.txt
spawn ssh -p 10022 $user#$host
expect "*?assword:*"
send -- "$password\r"
#log_user 1
sleep 2
expect "$"
send -- "sudo su\r"
expect -gl {*password for subhasish:*}
send -- "$password\r"
expect "#"
send -- "service iptables status\r"
log_file /home/subhasish/output.log
expect "#"
log_file
send -- "exit\r";
send -- "exit\r";
exit 0