Hello all.
I think I might have it, other than some editing for consistency.
My biggest stumbling block was a conflict between this, which returns a one item list:
set bootVolume to (choose from list bootList)
and this, which can’t parse a list:
tell application "Finder" to exists disk bootVolume
It ocurred to me that the exists command was redundant because of this:
tell application "Finder"
repeat with possibleBoots in (get disks whose startup is false)
if exists folder "System:Library:CoreServices" in possibleBoots then set end of bootList to name of possibleBoots
end repeat
end tell
I found two solutions, and each works. The first eliminates the exists command. My script is heavily commented, partly to describe how it is organized, partly to mark pitfalls for future reference. Please excuse the verbosity:
--With thanks to Jacques, walter, Dominik, and Adam Bell.
--EDIT: Comments updated to include corrections from Adam in post #36
-- Substitute your password within quotations for "adminPassword" to prevent a dialog requesting it.
set myPass to "adminPassword"
--This gets a list of mounted bootable volumes and saves it as a variable.
set bootList to {}
tell application "Finder"
repeat with possibleBoots in (get disks whose startup is false) --Get the mounted, unbooted disks.
if exists folder "System:Library:CoreServices" in possibleBoots then set end of bootList to name of possibleBoots --Filter out unbootable disks, set bootable disks to bootList.
end repeat
end tell
--This allows the user to cancel the script if no other bootable volumes are mounted. It is inelegant but easy to read and displays a nicer looking dialog.
if bootList is {} then
beep --Comment this word if you dislike beeps.
set stopSpaces to (space & space & space & space & space)
display dialog "No other bootable volumes detected." & return & stopSpaces & "Mount a volume and try again." buttons {"Okay"} with icon stop default button "Okay"
else
--This warns the user against unsaved changes. For a more traditional dialog, comment the following three lines and uncomment their equivalent below; if you prefer to live dangerously, comment the following three lines and leave their equivalent commented, too.
beep --Comment this word if you dislike beeps
set theSpaces to (space & space & space & space & space)
set lastWarnedRespose to button returned of (display dialog return & "Unsaved changes abandon," & return & theSpaces & "ye who continue here." buttons {"Cancel", "Continue"} default button 1 with icon caution)
--beep
--set foreSpaces to (space & space & space & space & space & space & space & space)
--set forewarnedResonse to button returned of (display dialog return & "Unsaved documents will be lost." & return & foreSpaces & "Proceed with caution." buttons {"Cancel", "Continue"} default button 1 with icon 2)
--This sets the subroutine that restarts the computer from the chosen volume.
set bootButtons to bootList -- This converts the list of bootable volumes to dialog buttons. Do not do "Cancel" & bootlist. It breaks the dialog because with "Cancel" first, the combination is text; AppleScript coerces the list bootlist to match the first item in the concatination. If you want the "Cancel" on the left, do {"Cancel"} & bootlist.
if (count of bootButtons) < 3 then --This cannot be ≤3 because a default "Cancel button is going to be added for safety.
set bootVolume to button returned of (display dialog "Boot from which volume?" buttons (bootButtons & "Cancel") default button "Cancel") --Do not do this - {bootButtons & "Cancel"} - it won't work because it returns a list within a list- bootButtons is {"A", "B"}. Concatinating "Cancel" coerces " it to {Cancel}, so adding it to the bootButtons list results in {"A", "B", "Cancel"}. If you enclose the concatination in braces you get {"A", "B", {"Cancel"}}.
myChangeBoot(bootVolume, myPass)
else
--There is a three button maximum for dialogs; this runs if that limit is exceeded.
set bootVolume to (choose from list bootList)
myChangeBoot(bootVolume, myPass)
end if
end if
--Restart from the chosen volume.
on myChangeBoot(bootVolume, myPass)
set rebootCommand to "/usr/sbin/bless -folder '/Volumes/" & bootVolume & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
do shell script rebootCommand password myPass with administrator privileges
end myChangeBoot
--Phew!
My alternate ending keeps the exists command in case it turns out that it’s better to do so:
else
--There is a three button maximum for dialogs; this is runs if that limit is exceeded.
set bootVolume to (choose from list bootList) --The return of this is a list, which breaks the exists command
set theChoice to bootVolume as string --This converts the list to a string, necessary for the exists command. Another solution is to disable the exists command.
myChangeBoot(theChoice, myPass)
end if
end if
--Restart from the chosen volume.
on myChangeBoot(bootVolume, myPass)
set rebootCommand to "/usr/sbin/bless -folder '/Volumes/" & bootVolume & "/System/Library/CoreServices' -setOF;/sbin/shutdown -r now"
tell application "Finder" to exists disk bootVolume
if the result is true then
do shell script rebootCommand password myPass with administrator privileges
end if
end myChangeBoot
So how did I do?
I’d like to return to the version that toggles between two volumes, but it is now - egad! - 4 a.m.
Thanks to everybody.
j