remote login script

Hello,

I’m pretty new to applescript (actually writing my first applescript right now) so I hope I’m not asking something too trivial.

The following code is giving me a ““Terminal got an error: Can’t continue waitForContent.” number -1708” error, and I don’t understand what I’m doing wrong. The handler is simple, with a repeat loop inside, and when I replace the handler call with the equivalent code, it works.

Additionally, I’d like to hear any comments on this script, what I could do better and so on (I know about the security hazard of having a password in clear in an applescript, but ssh keys aren’t an option for me unfortunately…)


tell application "Finder"
	set displayAreaDimensions to bounds of window of desktop
	set widthOfDisplayArea to item 3 of displayAreaDimensions
	set heightOfDisplayArea to item 4 of displayAreaDimensions
end tell

set heightOfMenuBar to 22 -- same as height of Window Bar

-- bug only happening with Terminal.app: instead of (x1, y1, x2, y2) where (x1, y1) are the coordinates of the upper left corner of the window and (x2, y2) the coordinates of the lower right corner, you have to use (x1, y1 + heightOfWindow, x2, y2 + heightOfWindow)

-- heightOfWindow = y2 - y1

(* Example: without bug, bottom right corner should be ¬
	{0, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar, ¬
	widthOfDisplayArea / 2, ¬
	heightOfDisplayArea - 1}
*)

set top_left to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_left to {¬
	0, ¬
	(heightOfDisplayArea - 1), ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set top_right to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_right to {¬
	widthOfDisplayArea / 2, ¬
	(heightOfDisplayArea - 1), ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set left_half to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set right_half to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}


--##################################################
--############## HARDCODED PARAMETERS ###################
--##################################################

set myWindowPosition to left_half -- left_half, right_half, top_left, top_right, bottom_right or bottom_left of the screen
set myWindowTitle to "myMachine “ ssh root@10.0.0.1"
set logName to "my-machine"

property myExpect : "#!/usr/bin/expect 
spawn /usr/bin/ssh root@10.0.0.1
expect \"password: \"
send \"xxxxx
\"
expect \"# \"
send \"zsh
\"
interact"

set expectFinished to "]" -- some character only displayed when the expect script is finished

set pathToTempScript to "/Users/me/" -- you can change this to whatever you want, remember to put it somewhere where admin rights are not necessary.
set pathToLogs to "/Users/me/logs/"

--################################################
--############## END OF HARDCODED PARAMETERS ############
--################################################

on waitForContent(windowID, stringExpected)
	repeat while (contents of window id windowID does not contain stringExpected)
		delay 1
	end repeat
end waitForContent

set myTempFile to "expect" & (random number from 100 to 999)

set myDate to (current date) as «class isot» as string

-- set {year:y, month:m, day:d, hours:hr, minutes:mn, seconds:sc} to myDate
-- set monthAsNb to m as number
-- set theDate to y & "-" & monthAsNb & "-" & d & "-" & hr & mn & sc

do shell script "/bin/cat > " & pathToTempScript & myTempFile & " << EOF 
" & myExpect & "
EOF"
do shell script "/bin/chmod +x " & pathToTempScript & myTempFile

tell application "System Events"
	if (count (processes whose name is "Terminal")) is 0 then -- you have to check if Terminal.app is already running, otherwise Terminal.app will open one additional window at startup.
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt" in window 1
			set my_win_id to id of window 1
		end tell
	else
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt;"
			set my_win_id to id of window 1
		end tell
	end if
end tell


tell application "Terminal"
	waitForContent(my_win_id, "Script Started")
	do script pathToTempScript & myTempFile in window id my_win_id
	set bounds of window id my_win_id to myWindowPosition
	waitForContent(my_win_id, expectFinished)
	set custom title of window id my_win_id to myWindowTitle
end tell

do shell script "/usr/bin/srm -rf /Users/me/" & myTempFile -- securely erase the temporary expect script

Here is the error message:

tell application "Finder"
	get bounds of window of desktop
		--> {0, 0, 1920, 1200}
end tell
tell current application
	random number from 100 to 999
		--> 940
	current date
		--> date "Freitag, 19. März 2010 10:54:25"
	do shell script "/bin/cat > /Users/me/expect940 << EOF 
#!/usr/bin/expect 
spawn /usr/bin/ssh root@10.0.0.2
expect \"password: \"
send \"xxxxx
\"
expect \"# \"
send \"zsh
\"
interact
EOF"
		--> ""
	do shell script "/bin/chmod +x /Users/me/expect940"
		--> ""
end tell
tell application "System Events"
	count every process whose name = "Terminal"
		--> 1
end tell
tell application "Terminal"
	do script "/usr/bin/script -a /Users/me/logs/my-machine--2010-03-19T10:54:25.txt;"
		--> tab 1 of window id 17664
	get id of window 1
		--> 17664
	waitForContent(17664, "Script Started")
		--> error number -1708
Result:
error "Terminal got an error: Can't continue waitForContent." number -1708

Hi,

this a very common error. Any handler call in an application tell block
throws this error, because no application knows what a handler is
Use the keyword my to tell AppleScript iteself to execute the handler


my waitForContent(my_win_id, "Script Started")

by the way: AppleScript can run shell scripts with the do shell script command without opening Terminal.app

Thank you! I knew it was something very basic… :rolleyes:

I know you can use “do shell script” (I use it in the script) but I want this script to open a Terminal window and log me into a remote machine, so that I can then type commands in this window.

It was a bit confusing to me that I had to put “tell application “Terminal”” again in the handler, whereas the handler is already called for within a “tell” block.

Here is the corrected version, I hope somebody find it useful.


tell application "Finder"
	set displayAreaDimensions to bounds of window of desktop
	set widthOfDisplayArea to item 3 of displayAreaDimensions
	set heightOfDisplayArea to item 4 of displayAreaDimensions
end tell

set heightOfMenuBar to 22 -- same as height of Window Bar

-- bug only happening with Terminal.app: instead of (x1, y1, x2, y2) where (x1, y1) are the coordinates of the upper left corner of the window and (x2, y2) the coordinates of the lower right corner, you have to use (x1, y1 + heightOfWindow, x2, y2 + heightOfWindow)

-- heightOfWindow = y2 - y1

(* Example: without bug, bottom right corner should be ¬
	{0, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar, ¬
	widthOfDisplayArea / 2, ¬
	heightOfDisplayArea - 1}
*)

set top_left to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_left to {¬
	0, ¬
	(heightOfDisplayArea - 1), ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set top_right to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_right to {¬
	widthOfDisplayArea / 2, ¬
	(heightOfDisplayArea - 1), ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set left_half to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set right_half to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}


--##################################################
--############## HARDCODED PARAMETERS ###################
--##################################################

set myWindowPosition to left_half -- left_half, right_half, top_left, top_right, bottom_right or bottom_left of the screen
set myWindowTitle to "MY MACHINE “ ssh root@10.0.0.1"
set logName to "my-machine"

property myExpect : "#!/usr/bin/expect 
spawn /usr/bin/ssh root@10.0.0.2
expect \"password: \"
send \"xxxxx
\"
expect \"# \"
send \"zsh
\"
interact"

set expectFinished to "[root@my-machine:/]# " -- some character only displayed when the expect script is finished

set pathToTempScript to "/Users/me/" -- you can change this to whatever you want, remember to put it somewhere where admin rights are not necessary.
set pathToLogs to "/Users/me/logs/"

--################################################
--############## END OF HARDCODED PARAMETERS ############
--################################################

on waitForContent(windowID, stringExpected)
	tell application "Terminal"
		repeat while (contents of window id windowID does not contain stringExpected)
			delay 1
		end repeat
	end tell
end waitForContent

set myTempFile to "expect" & (random number from 100 to 999)

set myDate to (current date) as «class isot» as string

-- set {year:y, month:m, day:d, hours:hr, minutes:mn, seconds:sc} to myDate
-- set monthAsNb to m as number
-- set theDate to y & "-" & monthAsNb & "-" & d & "-" & hr & mn & sc

do shell script "/bin/cat > " & pathToTempScript & myTempFile & " << EOF 
" & myExpect & "
EOF"
do shell script "/bin/chmod +x " & pathToTempScript & myTempFile

tell application "System Events"
	if (count (processes whose name is "Terminal")) is 0 then -- you have to check if Terminal.app is already running, otherwise Terminal.app will open one additional window at startup.
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt" in window 1
			set my_win_id to id of window 1
		end tell
	else
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt;"
			set my_win_id to id of window 1
		end tell
	end if
end tell


tell application "Terminal"
	my waitForContent(my_win_id, "Script started")
	do script pathToTempScript & myTempFile in window id my_win_id
	my waitForContent(my_win_id, expectFinished)
	set custom title of window id my_win_id to myWindowTitle
	set bounds of window id my_win_id to myWindowPosition
end tell

do shell script "/usr/bin/srm -rf /Users/me/" & myTempFile -- securely erase the temporary expect script


small update, I added the possibility to choose which set of settings from Terminal is going to be used. If anybody has improvement propositions, I’d be very interested.


tell application "Finder"
	set displayAreaDimensions to bounds of window of desktop
	set widthOfDisplayArea to item 3 of displayAreaDimensions
	set heightOfDisplayArea to item 4 of displayAreaDimensions
end tell

set heightOfMenuBar to 22 -- same as height of Window Bar

-- bug only happening with Terminal.app: instead of (x1, y1, x2, y2) where (x1, y1) are the coordinates of the upper left corner of the window and (x2, y2) the coordinates of the lower right corner, follwing coordinates have to be used (x1, y1 + heightOfWindow, x2, y2 + heightOfWindow)

-- heightOfWindow = y2 - y1

(* Example: without bug, bottom right corner should be ¬
	{0, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar, ¬
	widthOfDisplayArea / 2, ¬
	heightOfDisplayArea - 1}
*)

set top_left to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_left to {¬
	0, ¬
	(heightOfDisplayArea - 1), ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set top_right to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	(heightOfDisplayArea - heightOfMenuBar) / 2 + heightOfMenuBar - 1}

set bottom_right to {¬
	widthOfDisplayArea / 2, ¬
	(heightOfDisplayArea - 1), ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set left_half to {¬
	0, ¬
	heightOfMenuBar, ¬
	(widthOfDisplayArea / 2) - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}

set right_half to {¬
	widthOfDisplayArea / 2, ¬
	heightOfMenuBar, ¬
	widthOfDisplayArea - 1, ¬
	2 * (heightOfDisplayArea - 1) - (heightOfDisplayArea - heightOfMenuBar) / 2 - heightOfMenuBar}


--##################################################
--############## HARDCODED PARAMETERS ###################
--##################################################

set myWindowPosition to left_half -- left_half, right_half, top_left, top_right, bottom_right or bottom_left of the screen
set myWindowTitle to "MY MACHINE “ ssh root@10.0.0.1"
set logName to "my-machine"
set myUser to "root"
set myIP to "10.0.0.1"
set myPass to "xxxxx" -- would be nice to store the password in keychain, unfortunately looking up a keychain entry via applescript is so slow it is unusable. Other possibilities like using "security find-internet-password" or any third party tool acting as "proxy" create a security problem, because anybody can call the third party tool and access the password once "always allow" has been clicked once. It is thus no more secure (or at least not enough to be worth it).

global myExpect
set myExpect to "#!/usr/bin/expect 
spawn /usr/bin/ssh " & myUser & "@" & myIP & "
expect \"password: \"
send \"" & myPass & "
\"
expect \"# \"
send \"zsh
\"
interact"

set expectFinished to "[root@my-machine:/]# " -- some character only displayed when the expect script is finished

set myTermSettings to "mydefault"

set pathToTempScript to "/Users/me/" -- all temporary expect scripts are deleted afterwards, so it can be anywhere, as long as admin privileges are not required for reading/writing.
set pathToLogs to "/Users/me/logs/" -- all temporary expect scripts are deleted afterwards, so it can be anywhere, as long as admin privileges are not required for reading/writing.

--################################################
--############## END OF HARDCODED PARAMETERS ############
--################################################

on waitForContent(windowID, stringExpected)
	tell application "Terminal"
		repeat while (contents of window id windowID does not contain stringExpected)
			delay 1
		end repeat
	end tell
end waitForContent

set myTempFile to "expect" & (random number from 100 to 999)

set myDate to (current date) as «class isot» as string

do shell script "/bin/cat > " & pathToTempScript & myTempFile & " << EOF 
" & myExpect & "
EOF"
do shell script "/bin/chmod +x " & pathToTempScript & myTempFile

tell application "System Events"
	if (count (processes whose name is "Terminal")) is 0 then -- checking if Terminal.app is already running, otherwise Terminal.app will open one additional window at startup.
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt" in window 1
			set my_win_id to id of window 1
		end tell
	else
		tell application "Terminal"
			do script "/usr/bin/script -a " & pathToLogs & logName & "--" & myDate & ".txt;"
			set my_win_id to id of window 1
		end tell
	end if
end tell


tell application "Terminal"
	my waitForContent(my_win_id, "Script started")
	set current settings of window id my_win_id to settings set myTermSettings
	do script pathToTempScript & myTempFile in window id my_win_id
	my waitForContent(my_win_id, expectFinished)
	set custom title of window id my_win_id to myWindowTitle
	set bounds of window id my_win_id to myWindowPosition
end tell

do shell script "/usr/bin/srm -rf " & pathToTempScript & myTempFile -- securely erase the temporary expect script