Scripting System Preferences

Scripting System Preferences

The Mac is widely regarded as the computer of choice for creativity. It is often at the centre of a wide variety of pursuits, from music to movies, from illustration to photography or from design to desktop publishing. And at the heart of the Mac is Mac OS X, helping us to be more productive by making the creative process more effortless, enjoyable and effective.

To allow us work and play in our own, individual way, the Mac OS has long allowed extensive customisation. While such features were originally accessed through a collection of control panels in the control panels folder, Mac OS X introduced a single application to bring together most of the system customisation tools: System Preferences.

The aim of this article is to explore some of the ways in which we might use AppleScript to change certain system settings.

About System Preferences

System Preferences offers a wide range of options to control the system. Even when a Mac is shared by several users, each person can customise his or her experience and maintain most settings separately. The controls are grouped together quite logically and presented in a clear, graphical form so that even a relative novice should have little difficulty understanding how to use them.

System Preferences' preference panes include: * .Mac used to set preferences for the users .Mac account and iDisk * Accounts user creation/deletion, administrator privileges and user limitations are set here * Appearance changes the general color of the OS as well as placement of Scroll arrows and Font Smoothing * Bluetooth pair Bluetooth devices, edit Bluetooth settings * CDs & DVDs used to set default settings upon inserting blank CD/DVDs, as well as music CDs, Picture CDs and Video DVDs * Classic used to activate the Classic environment as well as set up settings for the Classic environment * Date & Time used to set the Date & Time of the computer, as well as how the clock appears on the menu bar * Desktop & Screensaver used to set the Desktop Picture as well as the screensaver, and there settings * Displays set screen resolution and Color settings here * Dock adjust the dock size as well as magnification and position on screen * Energy Saver optimize energy settings as well as sleep times and processor usage * Expos set Active Screen Corners and Keyboard and Mouse settings to activate Expos * Ink set handwriting recognition settings * International set the default OS language as well as numerical formats * Keyboard & Mouse set keyboard settings, as well as change keyboard shortcuts, and mouse settings * Network set Ethernet, AirPort, Modem and VPN Settings * Print & Fax set the default Printer as well as fax settings * QuickTime set Network speeds, plug-in settings, update, and register Quicktime here * Security set FileVault settings, set up a Master password and set Account Security Settings * Share set firewall and computer services preferences * Software Update set default times to check for updates, and view updates already installed * Sound set Alert Sound, Volume and Input/Output option * Speech set the computers Default Voice, set up Speech Recognition, and other Speech Settings * Startup Disk set the default disk, Hard Drive or Otherwise, for the computer to boot into * Universal Access make your computer more accessible for those with, sight, hearing and other impairments * Other panes it's also possible to add preference panes to System Preferences with third-party softwareAccessing System Settings with AppleScript

From a scripting point of view, System Preferences' bias towards the graphic user interface (GUI) seems to have been somewhat at the expense of direct scriptability. While it would be helpful to have more scripting support added in future, we have to do what we can with what's currently available.

Although there are a number of ways to access system defaults, each is limited to certain individual settings. Until relatively recently, there has been no way to access system settings in a more general way.

Fortunately another feature, introduced in Mac OS X 10.3, includes support for the control of the GUI via AppleScript by means of an enhanced version of the System Events application. The GUI Scripting architecture is based upon the Mac OS X accessibility frameworks, and provides alternative methods of querying and controlling the interfaces of many applications and of the Mac OS itself. This means that AppleScript scripts can select menu items, push buttons, enter text into text fields, and generally control the interfaces of most non-Classic applications.

So the main methods of getting and changing system settings now include: * using a shell script to access specific defaults * extracting and modifying data in a property list file * using third-party software * GUI scripting of the System Preferences applicationAvoiding Potential Conflicts Between Access Methods

In spite of the availability of GUI scripting, it's often preferable to modify settings quietly in the background, using an alternative approach (where one exists).

When using other methods, particularly if directly modifying data in property list files, it's generally advisable to avoid potential conflicts by making sure the application normally used to access those files is not currently open while changes are made. Otherwise, there's a risk that the application could ignore (or even overwrite) any settings modified by other means.

In a number of cases, System Preferences may be left open and will simply reflect the changes being made (as it does, for example, with the techniques for Changing Power Management Settings suggested below). In other situations, a dialog sheet might be displayed to alert the user that some settings "have been changed by another application" (as with the method proposed for Changing Current Location, below if System Preferences' Network pane is selected). In addition, any attempts to change settings normally accessed through a dialog sheet (such as the "Schedule" options for Energy Saver) are likely to fail if that sheet is displayed at the time.

One way around such issues is to quit the application, if it's running. It's better to do this without a direct application tell statement which may actually cause an unlaunched application to open. Try using an indirect quit statement instead, such as:

Applescript:

quit application "System Preferences"

However, this doesn't consider that the user may currently be using the application involved. A more user-friendly approach might be to quit the application, make any changes using the alternative method chosen and then re-launch it (preferably reinstating previous window settings, etc).

set SysPrefs_status to |get SysPrefs status|()(* set defaults/settings using an appropriate non-System Preferences method *)
|restore SysPrefs| to SysPrefs_status

Using a Shell Script to Access Specific Defaults

Some shell commands provide direct access to certain system settings. Using a shell in this way can be an effective method, since the effect is the same as changing the setting in System Preferences but without the application intruding on the user.

Since this isn't a shell tutorial, we can't go into too much detail here. However, I've included a couple of shell examples along with a brief description of how we might find and implement an appropriate shell tool to achieve our aim.

Finding and Using a Suitable Shell Command

For this, let's assume that we want to change the current location in our network preferences.

Our first task is to carry out a search, to see if we can locate a suitable tool. To do this, we could use the apropos command to search the 'whatis' database for possibly relevant strings. So let's launch Terminal and, in a new Terminal window, type (or paste) something like: apropos system location then press the enter or return key.

Whoa! While some searches may return an unhopeful nothing appropriate, others (like this one) can present a welter of information. However, let's remain undaunted and wade through what's there. About halfway down the mass of data, we should see an entry that looks like:

scselect(8) - Select system configuration location

Might this do the trick? Let's find out by reading the relevant man (on-line manual) page...

Back in Terminal, type or paste (in a new window, if preferred) the words: man scselect, and press enter or return. This should give us some useful information about the command including a synopsis (outlining forms of syntax) and description (which should tell us if we're on the right track). From the description shown here, I think we've found something that might do the trick...

One final point on this. To avoid potential confusion over the file location of the tool to which we're referring, it's a good idea to include the file path in our shell script. We can usually determine this with the which command either in Terminal, or using a script:

Applescript:

do shell script"which scselect"

--> "/usr/sbin/scselect"

Changing Current Location

As described above, instead of opening the Network pane in System Preferences to change the current location (system configuration set), we could simply use scselect.

Applescript:

do shell script"/usr/sbin/scselect 'required-location-name'"

Accessing Energy Saver Settings

Another useful shell command in this context is pmset, which can read and set power management settings (normally accessed manually through System Preferences' Energy Saver pane). Either method reads or writes settings stored in /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist apart from scheduled power on/off events, which are stored in /Library/Preferences/SystemConfiguration/com.apple.AutoWake.plist.

The following guide to corresponding controls may help:

Table 1. Power Management Settings

The displaysleep and disksleep arguments were introduced in Mac OS 10.4 to replace dim and spindown respectively. Use the latter if you need compatibility with an earlier system. (While deprecated in Tiger, the older arguments will continue to work there when setting values.)

The slider-type values in pmset generally range from 1 (minute) to 180 (3 hours), with 0 representing "never". Checkbox-type values are usually either "0" (off/unchecked) or "1" (on/checked). A notable exception is the System Preferences' checkbox marked "Put the hard disk(s) to sleep when possible". When checked, this sets the disksleep/spindown value to 10 (minutes); unchecking it will set a value of 180 (3 hours). Any disksleep value can be set using pmset (although subsequently checking/unchecking the checkbox in System Preferences will revert to the 10/180 defaults).

Applescript:

Applescript:

Note that grep's -w (word-regexp) option is used here, to avoid any confusion with other arguments that could include the word "sleep" such as "disksleep" or "displaysleep".

Getting Scheduled Events

To determine any currently scheduled startup/wake and shutdown/sleep events:

Applescript:

do shell script"/usr/bin/pmset -g sched"

Changing Power Management Settings

To change power management settings, pmset must be run as root. In AppleScript terms, this means running it with administrator privileges, which would normally also require an administrator password either entered by the user or provided by the script itself. Where the current user is not an administrator, an administrator account name should also be included.

This, for example, should ask the user for an administrator password (if required), and set the computer to sleep when it is inactive for 30 minutes:

Applescript:

do shell script"pmset sleep 30"with administrator privileges

This should require no user input, and set the display to sleep when the computer is inactive for 20 minutes:

Clicking the "Schedule" button in System Preferences Energy Saver calls up a dialog sheet in which startup/wake and shutdown/sleep events can be scheduled. These events are repeated at a specified time according to the selected repeat option which could be one of the following: * Weekdays * Weekends * Every Day * A particular day of the weekThese options can also be set using pmset. As with System Preferences, pmset supports only one pair of repeating events at any time; a "power on" event (poweron, wake or wakeorpoweron) and a "power off" event (sleep or shutdown).

Date and time formats in pmset are MM/dd/yy HH:mm:ss (24 hour format). Weekdays are designated by a subset of MTWRFSU with each character representing a day of the week, Monday (M) thru Sunday (U).

The following examples assume that the appropriate administrator name and password have been set as indicated above.

Applescript:

The options available from pmset are slightly more flexible than those offered by System Preferences. However, while a non-standard combination of days can be selected using pmset, System Preferences will be unable to display such choices; the corresponding pop up button will appear to be blank.

For more details, type man pmset in a Terminal window and press the enter or return key or see below for details of how to create a PDF file.

Creating Unix PDF Manuals

While the formatting preferences in Terminal can be adjusted, you may still wish to enhance the way in which man pages are presented. To improve the general readability of such documents, you might want to consider creating dedicated PDF files.

Applescript:

Many folks will, of course, be attracted by the brevity of a shell script for such an operation. However, before deciding on the most appropriate method for a given situation, remember that a more verbose routine using System Events can often be considerably faster than invoking a shell.

Modifying Data

In many cases, data in a plist file can also be modified although doing so may not actually change the current setting. This is mainly because a number of the settings stored in plist files are loaded into memory at startup/login. Since the version in memory is usually that which is subsequently used, changing the plist file will often have little or no effect.

Nevertheless, the technique can sometimes work so, before resorting to GUI scripting, it might be worth a try. In addition, not all settings are 'registered' in the way described and are picked up by certain applications when they launch.

Screen Saver settings, for instance, are checked by the ScreenSaverEngine application whenever it launches. So, to change the preferred Screen Saver module, we could run something like:

Other applications, such as the Dock and SystemUIServer (which deals with any Apple menu items that appear to the right of the menu bar), might stay open after launch and wouldn't therefore be aware of a changed plist file setting. Nevertheless, if you're not averse to being a bit heavy-handed, you could always force the application to quit so that, when it re-launches (usually automatically), the new settings should take effect. (When trying this trick with the Dock, bear in mind that any minimized windows that it may contain will become maximized.)

Here's a short script, based on the earlier data extraction example, which toggles the window minimization effect:

Sometimes, a third-party application or scripting addition (often referred to as an osax after its filename extension) can be useful for changing certain settings.

However, if you wish to run this kind of solution on any other machine, that will also need the same third-party software installed since it won't have been included as part of the standard install. (In other words, such an approach can't be described as "vanilla".) Remember, too, that scripting additions should be installed in one of the Scripting Additions folders: /Library/ScriptingAdditions/ or ~/Library/ScriptingAdditions/.

For these examples, let's assume that we want to change the sound output volume...

Applescript:

As a relatively new technology, GUI scripting is by no means comprehensive or consistent in every circumstance but it can be invaluable for controlling applications that either do not have AppleScript support or are only partially scriptable.

Enabling GUI Scripting

By default, the accessibility frameworks are disabled. An administrative user can enable them by clicking the checkbox labelled Enable access for assistive devices, in the Universal Access System Preference pane, and entering their password in the resulting authentication dialog. Alternatively, in Mac OS X version 10.4 or later, access can be enabled using the AppleScript Utility (located in /Applications/AppleScript/).

In addition, if we have a script that relies on GUI scripting being enabled, we could even insert a handler like this:

Having made sure that it's enabled, we can now explore the delights of GUI scripting...

Some Drawbacks of GUI Scripting

Actually, before we do go on, perhaps I should mention that scripting via the GUI is not generally considered an ideal method. It has a number of potential disadvantages, and can be: * slow it's sometimes necessary to wait for certain UI elements to appear, before they're accessible * intrusive it may get in the way of whatever the user might be trying to do at any given moment * susceptible the user could, by changing object focus, get in the script's way at any given moment * unpredictable the UI structure of an object can change substantially between different software versions * local-dependent variations in language, keyboard layout and certain other local settings may need to be considered * complex identifying a specific target element, particularly one that's deeply nested, can be a tortuous processAs a last resort, though, GUI scripting can be remarkably effective. So if I haven't put you off completely by now, let's explore it a little further...

Opening the Required System Preferences Pane & Tab

Our first job is to open System Preferences, get to the required pane and, if it contains more than one tab, select the relevant one. For the sake of an example, let's say that we wanted to access the Output tab of the Sound preferences pane.

Applescript:

In this context, the term anchor is an element of a pane within a System Preferences window. It has only one (read only) property: name. This is used to identify it when using the reveal command. The anchor element and the reveal command are both referred to in System Preferences' AS dictionary.

Some panes (such as those whose id is "com.apple.preference.general", "com.apple.preference.digihub.discs", "com.apple.preference.expose", "com.apple.preference.dock", "com.apple.preference.security" or "com.apple.preference.startupdisk") might have only a single anchor usually named "main".

Applescript:

Other panes might include a "main" anchor along with several others. For example, pane id "com.apple.preference.sound" contains 4 anchors: "main", "output", "input" and "effects". Revealing the "main" anchor will simply show the sound pane that was chosen previously. (This could be used if access to only the output volume slider was required since that's generally available in all variants of the sound pane.) Revealing the output, input and effects anchors will access the balance, input level and alert volume sliders, respectively.

In many cases, revealing an anchor can perform the equivalent function of selecting a tab. However, that's not always the case.

The following, for instance, effectively emulates the clicking of the "Hot Corners..." button of "Desktop & Screen Saver". So it will display the "Active Screen Corners" sheet.

Applescript:

In other situations, revealing an anchor is about the only way to access certain elements. Anyone who has ever tried, via GUI scripting, to get into the Accounts/Login Options of System Preferences will know what a headache that can be.

But something like this (perhaps with more appropriate password precautions, if required) should do the trick:

to authenticate_changes() (* may need a few moments to execute *)tell application "System Events"totell window "Authenticate"of process "SecurityAgent"tell group 1 torepeatwith i from 1 to 2set value of text field i to authentication_data's item iendrepeat
click button "OK"of group 2endtellend authenticate_changes

In general, changing the values of system settings via GUI Scripting can work quite well. However, it's worth noting that some UI elements (notably certain sliders) appear to be Teflon-coated. Since their values are not entirely persistent, these are best set using an alternative method. They include:

Table 2. UI Elements Whose Values Are Not Persistent

General GUI Scripting Utilities

At this point, I might have attempted to go into some detail about the finer points of scripting the GUI. However, since that's a little beyond the scope of this piece, perhaps we can leave it to another time. All the same, since I'm aware of how tricky it can sometimes be to identify UI elements, I'll mention one or two products that might help just in case you're not already aware of them.

First, there are a couple of Apple applications that can make exploring a GUI object's structure a little easier: "Accessibility Inspector" and "Accessibility Verifier". If you have Apple's Developer Tools installed, you'll find them both in the folder /Developer/Applications/Utilities/Accessibility Tools/. If not, an older version of Accessibility Inspector, still available at the Apple Developer web-site, was released as sample code under the name UIElementInspector.

Then again, if you're serious about GUI scripting, you might want to consider PreFab UI Browser, which will not only help you navigate the user interface hierarchy, but can also generate useful AppleScript statements with a single click.

SysPref Scripter

I've also done a little work on developing a script to assist in this particular area of scripting. This was originally a collection of smaller scripts, for my own use and these have now been combined as a single script, which might hopefully be of some help to you.

Its aim is to identify the relevant property list files (for plist scripting) or UI elements (for GUI scripting) relating specifically to System Preferences and then to draft an initial script, which can be modified further as required.

For the most part, a series of dialogs should help to guide you through the various choices and stages of analysis. The following notes may also help:

General Principles: * It makes sense to consider scripting methods in a particular order, usually starting with the least intrusive. * If a suitable Unix command exists, such as scselect or pmset, it could be the best option. * After that, experiment with plist scripting. If that works, stick with it. * Finally, if all else fails, try GUI scripting. This should work for most of the remaining settings.Initial Use of SysPref Scripter: * Read each dialog carefully before you dismiss it since it will often explain what action you should take next. * To identify a UI element for GUI scripting, simply hold the mouse pointer over the target. Don't click it. * Conversely, to identify property list files/items for plist scripting, make sure you click, drag or select an item to change its value. * There's a two-stage identification process for plist scripting: 1) to identify the plist file, 2) to identify any modified items in the file. * Did I mention about reading each dialog carefully?Other SysPref Scripter Considerations: * Bear in mind that changing a value in System Preferences may not always result in the identification of a property list file or item. * In the event of a failure, try again once or twice in case there was a temporary glitch. Then, if no dice, move on. * Even if a file and item is identified, attempts to change it using a script may not work. * Attempts at plist scripting may also fail if date/time settings are changed during the run. * Occasionally (including on the first run), an extra dialog will explain that file modification dates may need adjusting.Third-Party Software: * For GUI scripting operations, the script requires requires the scripting addition Xtool. * However, other operations should still be possible without the need for Xtool - and a dialog should notify when it is required.Requires Xtool:

to |copy script|(script_list) set tid to text item delimiters set text item delimiters to return set script_string to script_list as Unicode text set text item delimiters to tid activate application default_app tell application default_app to if paste_script then if default_app starts with "Script Editor" then make document with properties {text:script_string} else if default_app starts with "Smile" then tell (make class sctx) set its text to script_string event SATICKSN end tell else set clip_store to the clipboard set the clipboard to script_string tell application "System Events" keystroke "nv" using command down keystroke enter_key end tell delay general_delay set the clipboard to clip_store end if else set the clipboard to script_string display dialog "The script is ready to paste." buttons "OK" default button 1 with icon 1 giving up after 1 end if error number -128end |copy script|

on dlog(msg, btns, btn, icn) tell application "System Preferences" to with timeout of app_timeout seconds activate tell (display dialog msg buttons {"Cancel"} & btns default button btn with icon icn giving up after dlog_timeout) if gave up then error number -128 button returned end tell end timeoutend dlog

to |choose item|(item_type, item_list, default_item) if (count item_list) > 1 then with timeout of dlog_timeout seconds if default_item is not in item_list then set default_item to item_list's beginning tell application "System Preferences" to try activate set item_list to (choose from list item_list with prompt "Choose the required " & item_type & ":" default items default_item) on error number -1712 (* errAETimeout *) tell application "System Events" to tell button "Cancel" of application process "System Preferences"'s front window to if exists then click error number -128 end try end timeout if item_list is false then error number -128 item_list's beginningend |choose item|

on |object text| for o try {o}'s t on error t end try set tid to text item delimiters set text item delimiters to "{" set t to t's text from text item 2 to end set text item delimiters to "}" set t to t's text beginning thru text item -2 set text item delimiters to tid tend |object text|

to |set copy options|() set app_list to {} set copy_list to {"Copy only"} set paste_list to {} repeat with i in {"com.latenightsw.scriptdebugger", "com.apple.scripteditor2", "com.satimage.smile"} tell application "Finder" to try tell (get application file id i's displayed name) set app_list's end to it set copy_list's end to "Copy and activate " & it set paste_list's end to "Paste in new " & it & " document" end tell end try end repeat tell |choose item|("script copy/paste option", copy_list & paste_list & back_button, default_option) to if it is not back_button and it is not default_option then set default_option to it set paste_script to it is in paste_list if it is "Copy only" then set default_app to "System Preferences" else repeat with i in app_list if i is in it then exit repeat end repeat set default_app to i's contents end if end if |choose script option|()end |set copy options|

-- GUI routine handlers --

on |mouse position|() delay pre_move_delay set cancel_time to (current date) + mouse_timeout repeat while (current date) comes before cancel_time set start_position to mouse location repeat check_rate times delay 0.1 if (mouse location) is not start_position then exit repeat end repeat tell (mouse location) to if it is start_position then return it end repeat error number -128end |mouse position|

to |choose property| for chosen_element if curr_script_option starts with "Get" then -- get property value set default_property to |choose target|("property", (|property text keys| for chosen_element) & " *every property", default_property) if default_property is " *every property" then set target_string to "properties" else set target_string to default_property end if else -- set property value set default_property to |choose target|("property", (|property text keys| for chosen_element), default_property) set target_string to "set " & default_property & " to " & (|object text| for run script "tell application \"System Events\" to " & default_property & " of " & (|object text| for chosen_element)) end ifend |choose property|

to |choose attribute| for chosen_element tell application "System Events" to if curr_script_option starts with "Get" then -- get attribute value set default_attribute to my |choose target|("attribute", name of chosen_element's attributes & " *every attribute", default_attribute) if default_attribute is " *every attribute" then set target_string to "value of attributes" else set target_string to "value of attribute \"" & default_attribute & "\"" end if else -- set attribute value tell chosen_element set settable_count to count (attributes where it is settable) if settable_count is 0 then my dlog("The selected element has no attributes that can be set.", back_button, 2, 2) return my |GUI routine|() else if settable_count is 1 then tell (first attribute where it is settable) to set target_string to "set value of attribute \"" & name & "\" to " & my (|object text| for value) else set default_attribute to my |choose target|("attribute", name of chosen_element's attributes where it is settable, default_attribute) set target_string to "set value of attribute \"" & default_attribute & "\" to " & my (|object text| for value of first attribute whose name is default_attribute) end if end tell end ifend |choose attribute|

to |choose action| for chosen_element tell application "System Events" set action_count to count chosen_element's actions if action_count is 0 then my dlog("The selected element has no actions to perform.", back_button, 2, 2) return my |GUI routine|() else if action_count is 1 then set target_string to "perform action \"" & name of chosen_element's first action & "\"" else set default_action to my |choose target|("action", name of chosen_element's actions, default_action) set target_string to "perform action \"" & default_action & "\"" end if end tell if (|object text| for chosen_element) starts with "pop up button" and target_string ends with "\"AXPress\"" then |get menu items| for chosen_elementend |choose action|

to |make UI script| for chosen_element set popup_text to "" tell curr_script_option's last word to if it is "property" then my (|choose property| for chosen_element) else if it is "attribute" then my (|choose attribute| for chosen_element) else my (|choose action| for chosen_element) end ifend |make UI script|

on |modified items| from orig against dupe set mod_list to {} tell application "System Events" to repeat with n from 1 to count orig's property list items tell orig's property list item n tell name to if exists then set n to it (* sequence of named keys may differ between files *) if value is not value of dupe's property list item n then set item_count to count property list items if item_count > 0 and item_count is (count property list items of dupe's property list item n) then set mod_list to mod_list & my (|modified items| from it against dupe's property list item n) else set mod_list's end to it end if end if end tell end repeat mod_listend |modified items|

to |make plist script| from orig_path against dupe_path tell application "System Events" to set mod_list to my (|modified items| from property list file orig_path against property list file dupe_path) set mod_count to count mod_list if mod_count is 0 then dlog("No property list item changes were detected in \"" & orig_path & "\". To try again, click the '" & back_button & "' button." & return & return & "Make sure the value of the same object is changed. If necessary, check that the currently selected property list file seems appropriate.", {back_button}, 2, 2) return |identify modified plist item| from orig_path end if set script_start to {} set script_end to {} set tid to text item delimiters set text item delimiters to " of contents of property list file \"" set path_text to last text item of (|object text| for mod_list's beginning) set text item delimiters to "\"" set path_text to path_text's first text item & "\")" set script_text to "preferences folder's path & \"" set text item delimiters to path to preferences as Unicode text if (count path_text's text items) is 1 then set script_text to "local domain's " & script_text set text item delimiters to path to preferences from local domain as Unicode text end if set path_text to path_text's last text item if path_text starts with "ByHost:" then set text item delimiters to {""} set text item delimiters to words of (system info)'s primary Ethernet address as Unicode text tell path_text's text items to if (count) is 2 then set script_start to {"set text item delimiters to {\"\"}"} set path_text to beginning & "\" & words of (system info)'s primary Ethernet address & \"" & end end if end if set script_text to "tell application \"System Events\" to tell property list file (" & script_text & path_text set text item delimiters to " of contents of property list file \"" if curr_script_option starts with "Set" then -- set plist value(s) set script_start's beginning to "quit application \"System Preferences\"" tell application "System Events" to repeat with i in mod_list set i's contents to "set value of " & first text item of my (|object text| for i's contents) & " to " & my (|object text| for i's value) end repeat if path_text contains "com.apple.dock." then set script_end to {"quit application \"Dock\"", ""} else if path_text contains "com.apple.systemuiserver.plist" then set script_end to {"do shell script \"killall SystemUIServer\"", ""} end if else -- get plist value(s) repeat with i in mod_list set i's contents to "value of " & first text item of (|object text| for i's contents) end repeat set text item delimiters to ", " set mod_list to mod_list as Unicode text if mod_count > 1 then set mod_list to "{" & mod_list & "}" end if set text item delimiters to tid |copy script|(script_start & {script_text, mod_list, "end tell", script_end})end |make plist script|

to |limit mod dates| for target_folder to target_date tell application "System Events" to tell target_folder set modification date of (files whose (name starts with "com.apple" or name ends with "references.plist") and modification date > target_date) to target_date if modification date > target_date then set modification date to target_date end tellend |limit mod dates|

to |limit plist mod dates| to target_date tell (time to GMT) if it is current_GMT then return my dlog("Some property list file modification dates may need to be adjusted to reflect possible recent time zone changes." & return & return & "This may take a few moments.", "OK", 2, 1) set current_GMT to it end tell tell application "System Events" tell user domain's preferences folder tell folder "ByHost" to if exists then my (|limit mod dates| for it to target_date) my (|limit mod dates| for it to target_date) end tell tell local domain's preferences folder tell folder "SystemConfiguration" to if exists then my (|limit mod dates| for it to target_date) my (|limit mod dates| for it to target_date) end tell end tellend |limit plist mod dates|

on |plist routine|() |limit plist mod dates| to current date if dlog("Click the 'Identify Plist File' button, then change the value of an object in the current pane (confirming the change if necessary)." & return & return & "Wait a few moments for the change to register.", {back_button, "Identify Plist File"}, 3, 1) is back_button then return |choose script option|() |identify modified plist file| from (current date) - (time to GMT)end |plist routine|

-- pane/anchor/script selection handlers --

to |choose script option|() set chosen_option to |choose item|("script option", script_option_list, curr_script_option) if chosen_option is copy_button then return |set copy options|() else if chosen_option is back_button then return |choose anchor| with going_back else if chosen_option is "Enable GUI options" then return |get osax|() end if set curr_script_option to chosen_option if curr_script_option is in GUI_option_list then |GUI routine|() else |plist routine|() end ifend |choose script option|

to |choose anchor| given going_back:going_back |close sheet|() tell application "System Preferences" to tell current pane set pane_id to id set anchor_list to name of anchors if (count anchor_list) is 1 then if going_back then return my |choose pane|() set anchor_name to anchor_list's beginning reveal anchor anchor_name return my |choose script option|() end if tell my |choose item|("anchor", anchor_list & back_button, anchor_name) if it is back_button then return my |choose pane|() set anchor_name to it end tell set login_anchor to anchor_name is "loginOptionsPref" if login_anchor then my |access login options|() reveal anchor anchor_name end tell delay general_delay tell application "System Events" to if exists image 1 of sheet 1 of window 1 of application process "System Preferences" then my dlog("That option does not appear to be available.", back_button, 2, 2) return my (|choose anchor| with going_back) else my |choose script option|() end ifend |choose anchor|

to |choose pane|() activate application "System Preferences" |close sheet|() tell application "System Preferences" set pane_list to localized name of panes if not show all then set pane_name to current pane's localized name set pane_name to my |choose item|("preference pane", pane_list, pane_name) set current pane to first pane whose localized name is pane_name end tell |choose anchor| without going_backend |choose pane|

to |set script options|() if osax_name is in (list folder (path to scripting additions) without invisibles) or osax_name is in (list folder (path to scripting additions from user domain) without invisibles) then set GUI_op

Re: Scripting System Preferences

Everywhere where it says 'class' followed by a four-letter code, the expression should be enclosed in chevrons (eg. Â«class xpsaÂ»). I'm sure kai would have included them originally, so presumably their absence is due to a change in this site's BBS software since then. I haven't had time to check over all the scripts or work out what the one you quoted's meant to do, but it should probably look like this: