Restart from clone

I am new to AppleScript, Macs, and computers in general, so I’ll apologize in advance if I missed something blindingly obvious (in my defense, I am a stay at home Dad with 2 “helpful” children under 4 years old.)

What I am trying to create is a script to switch my startup disk to its clone - on an external drive - then restart. I want to save it as an application and give it a Butler hot key short cut. I found information about rebooting in Classic, but I have no idea how to adapt it to my needs. I ended up trying a GUI approach.

Using trial and error, UI Element Inspector, and UI Element script examples, I managed to get this to compile:

tell application "System Preferences"
	activate
	set current pane to pane "com.apple.preference.startupdisk"
end tell

tell application "System Events"
	if UI elements enabled then
		tell process "System Preferences"
			click button 3 of radiogroup of ScrollArea of group of SplitGroup of window "Startup Disk" of process "System Preferences"
		end tell
	else
		tell application "System Preferences"
			set current pane to pane "com.apple.preference.universalaccess"
			display dialog "UI element scripting is not enabled. Check \"Enable access for assistive devices\" at the bottom left of this pane."
		end tell
	end if
end tell
tell application "System Events" to restart

but when run it results in " System Events got an error: Can’t make button 3 of radiogroup of ScrollArea of group of SplitGroup of window “Startup Disk” of process “System Preferences” of process “System Preferences” into type UI element."

UI Element inspector provides the following information when I hold the cursor over my clone in System Preferences. I’m confused by not being able to make the AXButton “Mac OS X, 10.4.6 on jClone” into a UI element.

<AXApplication: “System Preferences”>
<AXWindow: “Startup Disk”>




<AXButton: “Mac OS X, 10.4.6 on jClone”>

Attributes:
AXRole: “AXButton”
AXRoleDescription: “button”
AXHelp: “Volume: jClone
System: Mac OS X, 10.4.6 (8I127)”
AXEnabled: “1”
AXFocused (W): “0”
AXParent: “”
AXWindow: “<AXWindow: “Startup Disk”>”
AXTopLevelUIElement: “<AXWindow: “Startup Disk”>”
AXPosition: “x=308.5 y=198”
AXSize: “w=136.25 h=83”
AXTitle: “Mac OS X, 10.4.6 on jClone”

Actions:
AXPress - press

I would be grateful to anybody who could steer me in the right direction. Thanks in advance.

j

hi J,

i’m not completely convinced that this will help you, but have you taken a look at the ‘bless’ command in the terminal? try: ‘man bless’ and see if that doesn’t get you headed in the right direction.

Thanks for the suggestion, waltr, although I have no idea if it points me in the right direction. I had seen bless mentioned regarding rebooting in Classic, but I’m not even competent in AppleScript, shell scripts are intimidating and pretty much indecipherable to me, so here goes nothing…

I just looked at the man page, and Change Startup Disk 1.6.1. My clone is already bootable, so from what I understand (a bit of an overstatement) I would need to include something like


--borrowed from Change Startup Disk 1.6.1, I might have cut out some important bits	
tell application "Finder" to set thetenfolder to folder "System" of startup disk as string
		set thetenfolder to quoted form of POSIX path of thetenfolder
		try
			do shell script "/usr/sbin/bless -folder " & thetenfolder & " -setOF" password admin_password with administrator priveleges

But wouldn’t I need thetenfolder of the clone? Would I change this

tell application "Finder" to set thetenfolder to folder "System" of startup disk as string

to somethig like this?

tell application "Finder" to set thetenfolder to folder "System" of  volume jClone as string
--I know this won't work as written

Am I remotely close? Should I go back to trying to figure out what is wrong with this?

click button 3 of radiogroup of ScrollArea of group of SplitGroup of window "Startup Disk" of process "System Preferences"

I suppose I also need to address the possibility that my clone might not be connected.

One of the options in SuperDuper! is to restart from the clone after updating, so it seems to me that I’m not attempting the impossible, although I may be attempting something beyond my meager capabilities.

Thanks again, and thanks in advance to anybody else who might have any advice.

j

p.s. I probably should have mentioned that I have a 17" PowerBook G4 running 10.4.6, with the clone partitioned on a Maxtor OneTouch II

Browser: Safari 417.9.3
Operating System: Mac OS X (10.4)

Hi Jaques, and thanks so much for the help.

Both approaches worked, although the GUI solution is more noob friendly, and I can put it to immediate use.

I’m glad my script wasn’t completely off base. I don’t know if I would have figured out that I needed to tell the button to click instead of telling System Preferences to click the button. I think I can figure out how to adapt it so it will change the startup disk back when the clone is booted - or get several steps in the right direction. I already found this posted by Bruce Phillips in another thread.

tell application "Finder"
	get name of first disk whose startup is true
end tell

I also tried, but failed, to make the process invisible, just because I want to avoid windows popping open and closed. I have a small script saved as an application with a Butler shortcut

--This usually prevents the window from briefly appearing and distracting me, I don't know why it doesn't always prevent it.
tell application "System Events" to launch application "iTunes"
tell application "System Events" to set visible of application process "iTunes" to false
tell application "iTunes"
	play playlist "WBUR" -- my local NPR station
end tell


so I tried

tell application "System Events" to launch application "System Preferences"
tell application "System Events" to set visible of application process "System Preferences" to false
tell application "System Preferences"
	set current pane to pane "com.apple.preference.startupdisk"
end tell

tell application "System Events" to tell window "Startup Disk" of process "System Preferences"
	tell button "Mac OS X, 10.4.6 on jClone" of radio group 1 of scroll area 1 of group 1 of splitter group 1 to if exists then
		click
		restart
	end if
end tell

and it ran without errors, but didn’t restart the computer, so I looked at the end of the event log, which said:
tell application “System Events”
exists button “Mac OS X, 10.4.6 on jClone” of radio group 1 of scroll area 1 of group 1 of splitter group 1 of window “Startup Disk” of process “System Preferences”
false (my emphasis)
end tell
so it seems that the window has to be visible for the GUI sripting to work.

The shell script is over my head, so I can’t really experiment with it. It works from the script menu, not as an application - it returns the message “alias jClone:” doesn’t understand the exists message." Is there is a way to save it as an application? It also asks for a password. When I first found the line in Change Startup Disk, I mistakenly thought it was working the password in to avoid the dialog. Can it be done without it?

I’ll post back if I make any headway or (more likely) when I get stuck again. It’s getting towards the wee hours EST, so I’m putting it off for now.

Thanks again.

j

hi J,

i think to get this to work the way you want, you’ll need to use the shell script. wonderful script Jacques! i’ll repost it here with comments, so hopefully you (J) can get it running:



tell application "Finder" to exists disk "jClone" --substitiute your 'clone' drive's name for jClone; also, do the same in the shell script below.

--change the boot volume and restart if the result is true

if the result then do shell script "/usr/sbin/bless -folder '/Volumes/jClone/System/Library/CoreServices' -setOF;/sbin/shutdown -r now" password "admin_password" with administrator privileges --put your admin password in for "admin_password", otherwise it will use a pop up dialog to ask the password.

you really don’t have to understand much as long as you do the replacements above. please post your results, this works flawlessly on my g4 (10.4.6).

Works perfectly, waltr, thanks for adding the comments.

Now that I know where to add my password, it seems obvious. Oh well.

Unfortunately, I didn’t save what didn’t work. I have no idea what mistake I made before (other than working on this at 1:30 a.m.) but it works as an application now, with or without the password dialog, and I do prefer not to have briefly appearing windows.

It shouldn’t be too hard for me to use if statements after fetching the boot drive name to switch between drives using one script. I’ll work on that during the kids’ naps, maybe.

Thanks for your help, I appreciate how quick the responses are. I think it takes me longer to post questions than it does to receive answers. I should learn to type.

j

hi J,

how about this:


tell application "Finder" to get name of startup disk
set myStartDisk to result

set myPass to "admin_password"

set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & myStartDisk & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"

if myStartDisk is "jClone" then
	tell application "Finder" to exists disk "Macintosh HD"
	if result then do shell script normalCommand password myPass with administrator privileges
	
else if myStartDisk is "Macintosh HD" then
	tell application "Finder" to exists disk "jClone"
	if result then do shell script normalCommand password myPass with administrator privileges

end if

just replace the names in the ‘if myStartDisk’ statements with your actual disks and put your password in and you are set. you could also extend this to three or more disks by copying the ‘else’ portion again and adding a different name.

EDITED: for consistency.

Wow, thanks.

I was about to post my latest attempt when I found the latest post - Mail was not running - so I guess I’ll skip that and try this. I was nowhere near this far along.

I’ll post back after dinner.

hi J,

i think i made a BIG mistake in that last post. how about this:



tell application "Finder" to get name of startup disk
set myStartDisk to result

set myPass to "admin_password"

if myStartDisk is "jClone" then
	set myOtherDisk to "Macintosh HD"
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & myOtherDisk & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk "Macintosh HD"
	if result then do shell script normalCommand password myPass with administrator privileges
	
else if myStartDisk is "Macintosh HD" then
	set myOtherDisk to "jClone"
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & myOtherDisk & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk "jClone"
	if result then do shell script normalCommand password myPass with administrator privileges
	
end if

i think there is a cleaner solution out there, but this should fix my screw up.

Hi waltr, this time I had Mail running.

I ran the script once and it restarted, but not from my clone. I was just reading through the script to try to figure out why when the e-mail came. In my haste, I started to reply before trying it out, but I’ll post back. I’m sure I’ll have a question or two.

Thanks for all the help. I really appreciate the work on my behalf as well as everything I’ll learn after I absorb all of this.

j

I just wanted to quickly confirm that it works pefectly before I tuck the kids into bed. I’ll ask my questions later. Thanks again (and again and again…)

j

hi J,

i wanted to clean this up. this does the same thing, but it’s MUCH cleaner. now if i didn’t screw anything up, it should work like a charm:


tell application "Finder" to get name of startup disk
set myStartDisk to result

--set these variables here, and only here
set myPass to "admin_password"
set firstHD to "jClone"
set secondHD to "Macintosh HD"

if myStartDisk is firstHD then
	set myOtherDisk to secondHD
	myChangeBoot(myOtherDisk, myPass)
else if myStartDisk is secondHD then
	set myOtherDisk to firstHD
	myChangeBoot(myOtherDisk, myPass)
end if

on myChangeBoot(theHD, thePass)
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & theHD & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk theHD
	if result then do shell script normalCommand password thePass with administrator privileges
end myChangeBoot

i also like that you only change the ‘settings’ in one place. now that’s progress.

btw–if you have questions on what i’m doing or how i’m doing it, post them here.

Hi waltr - I was typing while you were posting. I clicked preview and was surprised to see your new post as well as mine. I was working on a solution vaguely similar to yours, but of course you beat me to it. I’ll have to look at it more closely after a little sleep as it’s after midnight. I’ll definitely post any questions, but most of what you are doing is pretty clear. Thanks yet again.

Everything that follows was written before I saw your post.

I have been going over the script to understand it better. I added a dialog to appear when the disk I want to boot to isn’t mounted, and lots of comments to help me keep everything straight. That was the (relatively) easy part.

--Replace the names in the 'if myStartDisk' statements with your actual disks.
--Replace "admin_password" with your password to prevent a dialog requesting it.
--You could also extend this to three or more disks by copying the 'else' portion again and adding a different name.


--Get the name of the start up disk and save it as a variable
tell application "Finder" to get name of startup disk
set myStartDisk to result

--Save password as a variable
set myPass to "admin_password" --Your password here.

--Shut down the clone and boot Macintosh HD. A message will appear if Macintosh HD is not detected.
if myStartDisk is "jClone" then -- Your clone name here.
	set myOtherDisk to "Macintosh HD"
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & myOtherDisk & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk "Macintosh HD"
	if result then
		do shell script normalCommand password myPass with administrator privileges
	else
		beep
		display dialog "Macintosh HD is not found. Mount it and try again"
		
	end if
	
	
	--Shut down Macintosh HD and boot the clone. A message will appear if the clone is not detected.	
else if myStartDisk is "Macintosh HD" then
	set myOtherDisk to "jClone" --Your clone name here
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & myOtherDisk & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk "jClone"
	if result then
		do shell script normalCommand password myPass with administrator privileges
	else
		beep
		display dialog "jClone is not found. Mount it and try again" --Replace jClone with your clone name.
		
	end if
	
	
end if

I see what you had to fix, and I am bravely attempting to clean up the revised version, but my additions to it are slowing me down. I have some ideas and need to look up a few things. Maybe I’ll make some progress. At the very least, I’m learning a lot.

j

Hello again

I was going to ask about subroutines, but I think I am beginning to grasp them. I added one to let me know if the volume I want to boot is missing.


tell application "Finder" to get name of startup disk
set myStartDisk to result

--set these variables here, and only here
set myPass to "admin_password"
set firstHD to "jClone"
set secondHD to "Macintosh HD"

if myStartDisk is firstHD then
	set myOtherDisk to secondHD
	myChangeBoot(myOtherDisk, myPass)
else if myStartDisk is secondHD then
	set myOtherDisk to firstHD
	myChangeBoot(myOtherDisk, myPass)
end if

on myChangeBoot(theHD, thePass)
	set normalCommand to "/usr/sbin/bless -folder '/Volumes/" & theHD & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
	tell application "Finder" to exists disk theHD
	if result then
		do shell script normalCommand password thePass with administrator privileges
	else
		beep
		myNewBootMissing(theHD)
	end if
	
end myChangeBoot

on myNewBootMissing(theHD)
	display dialog (theHD) & " is not detected. Please mount it and try again" with icon caution
end myNewBootMissing

This does exactly what I want, as long as I’m just switching between my HD and my clone, and I might add it to the end of another script.

I am thinking about an expanded version (my wife, who receved a minor in programming 15 years ago and toils away at a PC for a paycheck has delegated tech duties to the brand spanking noob.) We have two computers (one is exclusively for my use) and they are both cloned on partitions of our external drive. I see how to add more variables, and it would be easy to write the script to reboot to my HD from whatever volume. But I think I would need a dialog to deal with all combinations of, in our case, 4 bootable volumes on three disks. I think that instead of

tell application "Finder" to exists disk theHD

I would need to choose among bootable volumes, but I have not yet found a way to detect them. Would it make more sense to enter all possible variables and choose from the full list?

I know that as long as I don’t mess with this

"/usr/sbin/bless -folder '/Volumes/" & theHD & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"

and this

do shell script normalCommand password thePass with administrator privileges

I’ll be okay, but could you explain what is happening? I see the path to CoreServices, but don’t understand much of the rest of the terminology.

You’ve been a great help, waltr, thanks

j

Edited for typos almost immediately after posting

hi J,

if you wanted to create a longer list of drives and choose from them, you could try something like this:


set aHD to (choose from list {"Macintosh HD", "jClone", "LaCie Disk", "Maxtor"} with prompt "Which disk do you want to boot from?" default items {"Macintosh HD"} without multiple selections allowed) as string

and then use multiple ‘if’ statements like we already have to check for your selection. the program would look very similiar to what it is now.

also, you could use something like this, or something like:


tell application "System Preferences"
   activate
   set current pane to pane "com.apple.preference.startupdisk"
end tell

instead of your ‘error beep’ so that you could choose a drive to boot from manually. really the options are limitless.

for the shell script, this:


"/usr/sbin/bless -folder '/Volumes/" & theHD & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"

just allows us to process the shell script as a string. i don’t know how technical you want the explaination, but here goes:

“/usr/sbin/bless -folder” calls the ‘bless’ program explicitly from it’s path. the ‘-folder’ option put bless into a mode where it is setting the boot volume to be a specific folder. from what i’ve read (man bless) this will work for both OS 9 and OS X. it’s a good option for this situation. you’ll have to read the man page for more on this.

“/Volumes” is where OS X mounts the external drive. it will always mount here, so our path is pretty dependable. once we know the name of ‘theHD’ we can add it to the string we’d like to run as a shell script, and then add the rest of the Path, “/System/Library/CoreServices”.

“-setOF” is probably the most important part of our bless command. it sets the “Open Firmware” to boot from our folder. pretty neat. the rest of the shell script is about rebooting.

the bless command needs to be run as ‘root’ user, so we have to “do shell script” on our string and use “administrator privileges” to make it run properly. you’ve seen how we save the password as text. i’d recommend you ‘compile’ the program as ‘run only’ so that no one (like your kids ) can get the admin password from your script. just some friendly advice.

let me know if i’m not being clear about any of this.

Thanks for clearing things up a bit for me, waltr.

I had something like your suggestion


set aHD to (choose from list {"Macintosh HD", "jClone", "LaCie Disk", "Maxtor"} with prompt "Which disk do you want to boot from?" default items {"Macintosh HD"} without multiple selections allowed) as string

in mind, and it seems like it might be less work than getting a list of connected volumes. Is that even possible?

I like this suggestion


tell application "System Preferences"
   activate
   set current pane to pane "com.apple.preference.startupdisk"
end tell

as an extension to my error beep - a dialog with 2 buttons. One to quit the script (and plug in the firewire cable that is next to but not in its port) and one to call up the pane to choose a different drive. I can’t figure it out exactly because I’m typing with one hand, feeding the baby with the other, and talking to my wife on speakerphone - I’ve reached my multitasking limit.

Thanks especially for the shell script explanation. The more detail the better. The bless man page was baffling me. I don’t have much of a foundation yet, but I tend to learn by jumping in with both feet.

Hey - a reply from Jacques - I’ll post this and take a look.

Thanks Jacqeus, you guys are great.

I tried that, but couldn’t make it work. Now I can go back and see what I did wrong.

I still have to decide how to handle passwords. I can customize the script for each machine, or try to make a single script that works on both (keeping in mind that “shortcuts” often make the trip longer.)

AppleScript Studio could put the options in one place, but that’s a whole new can of worms for me - and seems a lot like going into System Preferences.

At the very least, I have a one click solution just for my computer - my original goal is accomplished thanks to you and waltr. Plus I have a lot to work with so I can try to settle on a final version. And both kids are napping at the same time - this is a good day.

I learned this here http://www.macosxhints.com/article.php?story=20060511125715782

do shell script "/usr/sbin/diskutil eject /Volumes/jClone 
exit 0"

It might come in handy if I want to add the ability unmount (or is that dismount? so much to learn…) my clone at the end of the workflow.

j

EDIT - Oops, that won’t help me at all. I can’t eject the booted volume or the volume I want to boot from. If I had other bootable volumes on multiple external drives, maybe…

Hello again Jacques, waltr, and everybody else.

I have been working on modifying the script to choose bootable volumes posted by Jacques, and borrowed from a post from Dominik in this thread http://bbs.applescript.net/viewtopic.php?id=16969

I have cobbled this together because I probably won’t ever want to choose from among more than three mounted volumes (although that unlikely incidence is anticipated in the script) and one less click is one less click.

set bootList to {}
set myPass to "admin_password"

tell application "Finder"
	repeat with i in (get disks whose startup is false)
		if exists folder "System:Library:CoreServices" in i then set end of bootList to name of i
	end repeat
end tell

if bootList is not {} then
	set bootButtons to bootList
	if (count of bootButtons) ≤ 3 then
		set bootVolume to button returned of (display dialog "Boot from which volume?" buttons bootButtons)
	else
		set this to (choose from list bootList)
	end if
end if

Obviously it’s unfinished, but I’m making progress. I do have one question. what does “i” stand for?

repeat with i in (get disks whose startup is false)

I thought it was “item” or “every item” but that wouldn’t complile. I am trying to avoid abbreviations while I am learning because they make it harder for me to recognize what’s going on.

I’ve learned a lot in the past couple of days. I hope this is something that will be useful to others as well.

Back to the salt mines,

j

Thanks, Jacques.


Jacques wrote:

I replace the variable (i) by the variable (this_disk) in this script

Seeing that made me remember - the_item is what I had seen before, although this_disk is more clear.

I am also making more progress


set bootList to {}
set myPass to "admin_password"

tell application "Finder"
	repeat with i in (get disks whose startup is false) --  I think I'll replace the i with something like possibleBoots
		if exists folder "System:Library:CoreServices" in i then set end of bootList to name of i
	end repeat
end tell

if bootList is {} then
	beep
	display dialog "No bootable volumes detected. Mount a volume and try again" buttons {"Okay"} with icon stop default button 1
else
	
	set bootButtons to bootList
	if (count of bootButtons) ≤ 3 then
		set bootVolume to button returned of (display dialog "Boot from which volume?" buttons bootButtons)
	else
		set bootVolume to (choose from list bootList)
	end if
end if

I’m trying not to make it ugly, how am I doing?

EDITED - for typos