Automate SSH

I’ve seen lots of questions from people on how to automate an ssh connection but I don’t remember ever seeing an applescript solution, especially when you don’t have ssh keys setup on the 2 computers. I worked out the below method. The explanation of how it works is in the script.

You have to supply 4 things in the code; HOST, USER, PASS, and PROMPT. The PROMPT is the symbol used at the command prompt when connected to the remote computer. In general it will be either “>” or “#”. The example code connects to a remote computer, cd’s to the root of the drive, and gets a list (ls -al) of the directory.

-- This is how you can script ssh and send a username/password and perform some commands
-- We basically create a shell script in the applescript code and execute it using "sh -c" which allows us to pass a shell script as text to the command line
-- In the shell script we ssh into a computer, cd to the root of the drive, and perform a ls command, then exit
--
-- The major problem with scripting ssh is that ssh requires input from the command line. It doesn't want to be scripted.
-- To get around that the shell script uses the command line tool "expect", which is a tool to simulate a user entering commands at the command prompt
-- The key with expect is you have to know what to expect in response from the server
-- So basically you issue a command (eg. spawn ssh) and then an expect statement meaning wait until you receive a response on the command line and once that expect statement happens you send another command
-- For example, after issuing the ssh command we expect to receive a password prompt, then we send the password, then we expect the shell prompt (eg. #)... now we are logged in so we can start issuing commands to the other computer
--
-- To explain the back slashes... in a bash script we would have \" in the expect command to escape a quote. Since we're in applescript we have to escape each of those things because they have a special meaning to applescript so it becomes \\\" which is \\ to send a backslash and \" to send a quote
-- NOTE: with each send command we need to "enter" the command... thus the \\r to simulate pressing return

set shScript to "#!/bin/bash

HOST=192.168.1.xxx
USER=username
PASS=passwrd
PROMPT=#

expect -c \"
spawn ssh $USER@$HOST
expect \\\"password:\\\"
send \\\"$PASS\\r\\\"
expect \\\"$PROMPT\\\"
send \\\"cd /\\r\\\"
expect \\\"$PROMPT\\\"
send \\\"ls -al\\r\\\"
expect \\\"$PROMPT\\\"
send \\\"exit\\r\\\"
\"
"

do shell script "sh -c " & quoted form of shScript

great but I have posted several times the same way with expect command :D. It’s good you’ve posted it in code exchange

edit: it’s post #5 here

Great DJ Bazzie Wazzie. I searched for ssh and expect but didn’t find it. That’s why I had to create it myself. I wish I did find yours!

In any case it’s good to have both posted. We both use expect but a little differently. Plus I wrote mine like a shell script whereas you created a string. So both are valuable as both approaches have their merits. Thanks for pointing that out.

Here an updated version of the script. It now both supports the older password and newer Password prompt, also found out that some versions of ssh servers still use “password”. Just for compatibility outside Mac OS X and old Mac OS X systems it supports both. When ssh asks for a fingerprint it will send yes for you, like in my earlier versions, but some ssh servers will only ask for y and n instead of yes and no. To support these versions I’ve added another expect rule. Last but not least I added a timeout as well, by default a value that is lower than AppleScript’s timeout.

*Also my earlier versions were a bit hard to understand and changed it into a more human friendly version as well.

For the record: The difference between Hank’s version and mine is that Hank’s version is more like a session running multiple commands while I’m focusing more on sending only 1 command. Of course a bash script on the remote machine would be the answer to Hank’s script.


set sshServer to "<ssh server>"
set sshUser to "<ssh user>"
set sshPasswd to "<ssh password>"
set remoteCommand to "<remote command>"

set expectScript to "set timeout 30
spawn ssh " & sshUser & "@" & sshServer & space & remoteCommand & "
expect {
	\"Password:\" {
		send \"" & sshPasswd & "\\r\"
		exp_continue
	}
	\"yes/no?\" {
		send \"yes\\r\"
		exp_continue
	}
	\"password:\" { #to support older Mac OS X systems and other ssh servers
		send \"" & sshPasswd & "\\r\"
		exp_continue
	}
	\"y/n?\" { #to support other ssh servers
		send \"y\\r\"
		exp_continue
	}
}"

set theResult to do shell script "expect <<<" & quoted form of expectScript

Hey,

I did use both of youre scripts, and found out that regulus6633 s solution did work good, and i also managed to get into root, switch accounts and do stuff.

Script where slow, and i culd not pass variables into the script. for example, i want to list folders on a shared Linux Server, from a Mac… The Linux Server path is different that the mac paths, thats fixed by a variable, but to pass that into the regulus6633 s script, somehow it where not possible.

But on DJ Bazzie Wazzie ´s scipt i easely culd pass the variables, but i culd not login as root by sudo hehe, cause of the tty error, you cant put all the info in a line.

here is my script now, i did like working with DJ Bazzie Wazzie´s solution, reason it used 0.30 sek to do a line, but regulus6633 solution used 22 sek, but it felt more robust …

any ideas ?

Best
Andreas



tell application "Finder"
	set sel to the selection as text
	set the filepath to POSIX path of sel
end tell

set newfilepath to snr(filepath, "Volumes", "mnt")
display dialog newfilepath
--

on snr(the_string, search_string, replace_string)
	return my list_to_string((my string_to_list(the_string, search_string)), replace_string)
end snr

on list_to_string(the_list, the_delim)
	my atid(the_delim)
	set the_string to (every text item of the_list) as string
	my atid("")
	return the_string
end list_to_string

on string_to_list(the_string, the_delim)
	my atid(the_delim)
	set the_list to (every text item of the_string) as list
	my atid("")
	return the_list
end string_to_list

on atid(the_delim)
	set AppleScript's text item delimiters to the_delim
end atid


set sshServer to "192.168.100.100"
set sshUser to "linuxuser"
set sshPasswd to "password"
set rootsh to "sudo rootsh"
set sshPasswd2 to "password"
set remoteCommand to "ls -la " & newfilepath

set expectScript to "set timeout 30
spawn ssh " & sshUser & "@" & sshServer & space & rootsh & space & remoteCommand & "
expect {
   \"password:\" { #to support older Mac OS X systems and other ssh servers
       send \"" & sshPasswd & "\\r\"
       exp_continue
   }
   \"y/n?\" { #to support other ssh servers
       send \"y\\r\"
       exp_continue
  }
   \"linuxuser:\" {
       send \"" & sshPasswd2 & "\\r\"
       exp_continue
   }
   \"y/n?\" { #rootshich
       send \"y\\r\"
       exp_continue
}"

set theResult to do shell script "expect <<<" & quoted form of expectScript