Creating Config Profiles instead of a First Boot Script

 

As a follow up to my first boot script blog, I wanted to spend a bit more time with configuration profiles to see if they could be used to replace some or all of it.

It has become increasingly apparent that Apple is in favour of managing settings via configuration profiles and the MDM system so we thought it was time to modernize the techniques we are using. In addition to this, while we have used a first boot script for quite a few of the recent OS versions which have worked great, with 10.9 and now 10.10 there were a few things that have been bugging us:

  • Having to work around preference caching.
  • Write lots of data into existing user homes and the system user template folder.

Preference Caching

Preference caching broke quite a few scripts people were using to configure OS X settings.  Traditionally, OS X and most applications use XML files stored in specific locations (Library/Preferences folders) in the root of the hard drive, the System folder and each users home folders.  You could use various methods to write data into these files, or even replace the files to affect the associated settings. 

Although introduced earlier, certainly since 10.9 the operating system started caching the information stored in these XML files.  If you edit the files directly, the change you made often gets replaced with the cached version.  Ben Toms has a great article on preference caching that explains it in more detail here.

There are commands like “defaults” that are preference caching aware which is good for one line key/value pair edits and entries. For more complex plists you can use Python, which is using CFPreferences, so would also work.  Some of the other commands like plistbuddy require you to kill cfprefsd before making changes, unless you’re editing files on a non-booted volume.

Configuration Profiles are also able to work with preference caching and apply as soon as they are deployed to the target device and so are the main focus for this blog.

Writing data into user homes and the system template

The second reason for wanting to use profiles is to avoid writing data into user home libraries and the System user template.  These methods generally avoid preference caching as they aren’t actually in use (although this isn’t guaranteed).  

The System folder has always been considered Apple’s domain so anything we put in there has the risk of being wiped out with an OS or other system related update.  To change the settings for existing user home folders, we had to use a loop in the script that contained the necessary commands to insert the key/value pairs.  This also worked, but is quite complex.

What Settings Could We Switch To Config Profiles?

The first boot script we use has quite a lot of different jobs to do so the first task was to list them out and investigate whether they could be switched to configuration profiles.  The below table lists each task and whether a config profile worked.

TaskProfile?Notes
Creating a local admin accountNoNot possible with a profile, but can use the new 10.10 tool sysadminctl
Setting time zone and time serverNoThe time zone and NTP server addresses are stored in /etc/localtime and /etc/ntp.conf respectively.  These are traditional UNIX Config files and can’t be manipulated with profiles.  Luckily the systemsetup command makes the process nice and simple.
Region, keyboard and languageYesKeys set in the com.apple.HIToolbox.plist and .GlobalPreferences.plist files.
Apple Remote DesktopNoSimilar to setting the time zone and server, there is a purpose built binary that can achieve this so no need to switch it to a profile
Enabling SSH accessNoSame as above, the purpose built command line binary works best
Setting up the Login WindowYesKeys set in com.apple.loginwindow.plist
Disable iCloud Setup at loginYesKeys set in com.apple.SetupAssistant.plist
Disable diagnostics at loginNoThe plist file is stored in a non-standard location (/Library/Application Support) so profiles aren’t any use.
Disable Time Machine Popups Offering for New DisksYesKeys set in com.apple.TimeMachine.plist
Turn off GatekeeperYesAvailable in the GUI configuration profile settings
Turn on right-clickYesKeys set in a bunch of mouse and trackpad plists (more details below)
Turn off restore windowsYesKey set in .GlobalPreferences
Stop writing .DS_Store files on the networkYesKey set in .GlobalPreferences
Set the Users HomepageYesKey set in com.apple.Safari.plist

 
 
Creating a config profile

There are two main options for creating configuration profiles, either in a graphical interface, or by creating custom XML files. Some of the tasks above require the use of custom config profiles. These are used to set XML keys that are not available in the standard GUI options.

The core part we are interested in can be shown in this example snippet from the com.apple.TimeMachine.plist profile:

PayloadContent

	com.apple.TimeMachine
	
		Set-Once
		
			
				mcx_preference_settings
				
					DoNotOfferNewDisksForBackup
					
				
			
		
	

The Easy Ones

There were a few preference settings that could be replaced with simple checkboxes and dropdown menus. These were:

Some of the login window options

Although there are custom settings we have been adding into the login window preference file, the majority of the options can be set in the GUI:

custom settings config profiles

custom settings config profiles options

Security & Privacy

We would normally set the Gatekeeper options using

spctl --master-disable

but this can be set in the GUI as below:

security and privacy config profiles

Custom Settings

There are a few ways you can create custom configuration profiles.

Upload the plist file directly

Depending on the MDM system, in some cases you can simply upload the configured preference file. To get the preference file setup, I would normally recommend using a cleanly installed version of OS X and removing any keys that you don’t want. So if I wanted to set a few keys in the com.apple.TimeMachine.plist file, I would use the terminal to add the necessary keys such as:

/usr/bin/defaults write /Library/Preferences/com.apple.TimeMachine DoNotOfferNewDisksForBackup -bool true

Then I would take a copy of the preference file so I can amend it:

mv /Library/Preferences/com.apple.TimeMachine.plist /Users/dave/Desktop/

Then we need to convert it from binary to xml so we can edit it:

plutil -convert xml1 /Users/dave/Desktop/com.apple.TimeMachine.plist

Once you have an xml version of the file you can open it in a text editor and remove any keys you don’t need in your profile.

This edited preference file can then be uploaded into your MDM.

Convert to a Configuration Profile first

The second option is to convert the preference file into a configuration profile. This will allow you to deploy the setting using a large range of tools including an MDM server, Munki (since version 2.2) or using the profiles command in the Terminal.

It is possible to create a mobileconfig file directly in a text editor. There are a bunch of profile specific xml keys such as:

PayloadDisplayName
PayloadRemovalDisallowed
PayloadUUID

Note – not a full list of mobileconfig keys

and the core

PayloadContent

that contains the management settings.

Luckily, Tim Sutton has created a very handy script called mcxtoprofile.py (available here). This script allows you to (amongst other things) specify a plist file as the input and have it create the mobileconfig file for you. Here’s an example command:

mcxToProfile.py --plist com.apple.TimeMachine.plist --identifier DoNotOfferNewDisksForBackup

By default, configuration profiles lock the settings they are managing. In lots of cases, this works fine but in some cases, particularly when you start dealing with custom profiles and third party applications, locking the settings will either cause the managed setting to be ignored, or make the application crash.

To get around this, you need to change the default profile behavior so the setting is set, but unlocked so the corresponding application can change it if it needs to. You can do this per preference file in the profile with one of the following keys:

Always –

Forced

– This will lock the setting (default behavior)

Often –

Set-Once

– This will set the key initially and then reset it each time a user logs in (if they change it)

Once – Combining the

Set-Once

with

mcx_data_timestamp

set to the current NSdate will allow the setting just to be set once. This is useful if you want to set up the users environment a certain way for their first login, but allow them to change it afterwards.

Always:

mcxToProfile.py --plist com.apple.TimeMachine.plist --identifier DoNotOfferNewDisksForBackup --manage Always

Often:

mcxToProfile.py --plist com.apple.TimeMachine.plist --identifier DoNotOfferNewDisksForBackup --manage Often

Once:

mcxToProfile.py --plist com.apple.TimeMachine.plist --identifier DoNotOfferNewDisksForBackup --manage Once

Final First Boot Script

As I mentioned at the start, there are a few settings that couldn’t be set with config profiles, or were so easy to do with a terminal command it wasn’t worth switching across.

In these cases, we kept the first boot script code. You could turn these into a series of payload free packages, or if you are using Casper, add them to individual policies to be triggered as required.

Below is the script we ended up with:

#!/bin/sh

# Requires 10.10 or higher.

# Create a local admin user account
sysadminctl -addUser localadmin -fullName "Local Admin" -UID 499 -password "apassword" -home /var/localadmin -admin

# Set the time zone to London
/usr/sbin/systemsetup -settimezone "Europe/London"

# Enable network time servers
/usr/sbin/systemsetup -setusingnetworktime on

# Configure a specific NTP server
/usr/sbin/systemsetup -setnetworktimeserver "ntp.amsys.co.uk"

ARD="/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart"

# Switch on Apple Remote Desktop
$ARD -configure -activate

# Configure ARD access for the localadmin user
$ARD -configure -access -on
$ARD -configure -allowAccessFor -specifiedUsers
$ARD -configure -access -on -users localadmin -privs -all

# Enable SSH
systemsetup -setremotelogin on

exit 0

Summary

So now we have the config profiles in our MDM. When a device enrolls it falls into the necessary groups and configures its settings based on the XML information.

If anyone wants to grab a copy of our completed mobileconfig files and the amended first boot script, you can get them on our github page here.

Apple is clearly pushing profiles as the primary settings management method so its worth spending some time with config profiles and seeing what you can switch over to them.

9 Replies to "Creating Config Profiles instead of a First Boot Script"

  • Laeeq

    Nice article, thanks.
    .DS Store file you just mentioned above, what is it used for and what is its side effects if it is on the share?

  • Hi,

    It’s just an annoyance really. OS X creates a .DS_Store file in every folder it visits to keep track of icon locations etc. If this is on a Windows server, there will be a trail of these files left all over the place that all the Windows users can see so we generally switch off this feature for network shares.

  • Mike Berry

    Hi David, a quick question. If for instance a previously managed (via MCX) Mac has been upgraded and it has cached those Managed Preferences. Obviously wiping out the /Library/Managed Preferences folder now results in the repopulation of that folder at reboot. Where exactly is OS X restoring this from, giving that the Mac is no longer joined to an OD server?

  • MrB

    Thank you for the article. Lots of helpful information here.

    On a slightly related tangent, users (hidden) with an uid < 500 are no longer supported in Yosemite. You may want to update your account creation to use the IsHidden attribute. (https://support.apple.com/en-us/HT203998).

  • Nil

    Hi David,

    Excellent article!

    I’m curious about the language settings, did you check the .plists into your JSS and apply them at computer level?

    I’m trying to move away from deploying language settings with .DMGs and.

    ´

  • Anver

    Hi Daniel

    Thanks first for the article. Great input!

    When I try to upload my self made profile to the JSS I get the error: The file could not be parsed.

    I removed the:
    – PayloadIdentifier
    – PayloadType
    – PayloadUUID

    Could that be the reason and how to i generate them?

    Best Anver

  • David Acland

    Hi Anver,

    Those keys are definitely needed so is a likely reason for the .mobileconfig file not uploading to the JSS.

    All the best

    David

Leave a Reply

Your email address will not be published. Required fields are marked *