Skip to main content
Jamf Nation, hosted by Jamf, is a dynamic and knowledgeable community of Apple-focused IT admins and Jamf Pro users. Join us in person, in October, for the annual Jamf Nation User Conference (JNUC) to discover new and better ways to manage Apple devices.
CCA Badge CJA Badge CMA Badge

Mavericks Wallpaper - the bash version

Posted: 4/23/14 at 2:44 PM by franton

Where I work has two separate desktop background policies: a standard one for all people and a custom one for certain departments. 10.9 really threw some spanners in the works when Apple shifted from MCX to their sqlite3 database to control this.

However thanks to being persistently bugged by Casper warning email messages around 50+ times per day, I think I have it! I should point out there are solutions out there for this, but they're mainly for the Munki crowd and written in python and in one case, Ruby. I am not a Ruby man. Or Python.

Anyway I like the idea of as few policies to do the job as possible. Also, as few scripts as possible too. So before I release this on my github ... here's what I have.


# Script to set desktop background for students

# Author :
# Version 1.0 : Initial Version
# Version 1.1 : 23/04/2014 - Massive reworking to use applescript for 10.8 and below, modify the db for 10.9+
# Version 1.2 : 24/04/2014 - Removed applescript because of osascript parsing issues. replaced with mcx.

OSversion=$( sw_vers | grep ProductVersion: | cut -c 20-20 )
currentuser=$( ls -l /dev/console | awk '{print $3}' )

if [ "$4" = "custom" ];

if [[ "$OSversion" -ge "9" ]];

sqlite3 /Users/$currentuser/Library/Application\ Support/Dock/desktoppicture.db << EOF
UPDATE data SET value = "/Users/Shared/Background/custombg.jpeg";

killall Dock

defaults write Background '{default = {ImageFilePath = "/Users/Shared/Background/custombg.jpeg"; };}'
killall Dock


if [[ "$OSversion" -ge "9" ]];

sqlite3 /Users/$currentuser/Library/Application\ Support/Dock/desktoppicture.db << EOF
UPDATE data SET value = "/Library/Desktop Pictures/default_grey2560x1600.jpeg";

killall Dock

defaults write Background '{default = {ImageFilePath = "/Library/Desktop Pictures/default_grey2560x1600.jpeg"; };}'
killall Dock

exit 0

A little explanation as I haven't finished annotating my code yet. If you put the word "custom" in parameter 4 when calling the script, you'll get the custom background file or else you get the standard one.

For 10.8 computers and under, the script setting is done through an osascript call which has been detailed on many other posts on jamfnation. Since Casper scripts run as root, i'm using "su -l" to run the command as the currently logged in user which seems to help A LOT.

For 10.9 computers and above, i'm directly manipulating the currently logged in user's desktoppictures.db file and reprogramming ALL entries in the data table. To force the change through, I'm killing the dock process. It's not the most seamless process in the world, but it does work. This has not been tested for multi monitor support but it should theoretically work.

Credits and kudos for providing the information to make this all work go to the following: for his work on the database file side of things
/url">@rtrouton][/url for his work located at [

CCA Badge CJA Badge CMA Badge

Posted: 4/23/14 at 2:45 PM by franton

Please also take extreme note of the fact that the database file does NOT need the spaces in the file path escaped whereas the Applescript version does!

CCT Badge

Posted: 4/23/14 at 2:50 PM by scottb

Kudos! Something we've been ignoring but I will try this for sure. Thanks for posting it up!

CCA Badge CJA Badge CMA Badge

Posted: 4/23/14 at 2:53 PM by franton

@boettchs You're very welcome! It's obviously very specific to my own requirements but it should be easily tailored to yours. Obviously test like crazy!

Posted: 4/23/14 at 6:43 PM by Account deleted

This looks great \- thanks for posting.

CCA Badge

Posted: 4/23/14 at 7:02 PM by mm2270

Thanks for posting. Although we don't have a need to adjust or manage the desktop picture here, I think the general model of this script could be adapted to work with other sqlite databases that Apple is using (which there seem to be more of with each new OS)

Also just wanted to quickly mention that your "OSversion" line could be simplified to just this-

sw_vers -productVersion | cut -d. -f2

Posted: 4/23/14 at 8:18 PM by gregneagle

This is clever.

But an advantage of Python scripts like this one: is that they use documented Apple APIs and therefore are likely to continue to work even if Apple changes how the data is stored.

You don't even have to understand the Python \- you can just use it -- in a Bash script if you want. In that case it's really no different than calling the `sqlite3` command from inside a Bash script (and less complicated, to boot):

/path/to/ --path /Users/Shared/Wallpapers/my_wallpaper.png
CJA Badge CMA Badge

Posted: 4/23/14 at 8:50 PM by freddie.cox

Thanks everyone for their input and discussion on this topic.

I have been putting off desktop background update/maintenance as we drift away from MCX. Also as we get closer to a widespread 1:1 student deployment I don't worry (or care) as much about those student's desktop backgrounds being managed. However, I do like having a unified look in our remaining labs. This discussion will give me a place to start!

CCA Badge CJA Badge CMA Badge

Posted: 4/24/14 at 2:01 AM by franton

Thank you @gregneagle !

I actually investigated Graham's python script but i'm in the situation where our version of Casper doesn't really deal with python scripts too well. If it had, I would have used it instead. Storing scripts and other utilities on the desktop clients is sadly also right out for us. I won't bore you with the details as to why, suffice to say it's not a technical issue.

@mm2270 That's a good point but I was hacking this thing up quickly. Refinement comes later once it works ;)

CCA Badge CJA Badge CMA Badge

SOLVED Posted: 4/24/14 at 3:49 AM by franton

Dear All,

I've modified the script above to remove the osascript stuff and replaced with the legacy mcx method.

CCA Badge CJA Badge CSE Badge CMA Badge

Posted: 7/24/14 at 1:19 PM by wmateo

cant this all work with a simple configuration profile? and the plist?

CCA Badge CJA Badge CMA Badge

Posted: 7/24/14 at 1:24 PM by franton

No as desktop wallpapers are set in a database file instead of the plist now.

Posted: 7/30/14 at 12:44 PM by alex_drinkwater

Hi Franton,

Thanks very much for posting this.
I'm trying to get something based on it to work, but getting odd errors. Here's the script:

# Set Mavericks Desktop Picture for user.
# Based on script
# Run from Login hook
# Alex Drinkwater 2014

picturepath=/Library/Desktop\ Pictures/backgroundDefault.jpg

if [ ! -z "$4" ]
    if [ -f "$4" ]

sudo sqlite3 /Users/$currentuser/Library/Application\ Support/Dock/desktoppicture.db << EOF
UPDATE data SET value = "$picturepath";

killall Dock

exit 0

It's odd. I've been testing it by running it in the terminal, supplying the relevant arguments.

It seems to work on some machines, and not on others.

All the machines were built from the same image, and have the same policies applied.

I've tried running the script from local admin and network-authenticated non-admin accounts. On the machines where the script works, it works for both. On the other machines, it doesn't work for either.

Anyone any clues about what might be going wrong?


Posted: 7/31/14 at 3:27 PM by alex_drinkwater

It's worth noting that if you don't need to conditionally change the desktop picture, but just want to be able to preset a particular background, it seems from my brief research, to be possible simply to setup the desktop picture as you want for a model user, and capture, package and deploy the desktoppicture.db to other users and machines via a policy. Seems to work on machines with identical monitors, at least.

If you do need to change the picture, you could make a package that conditionally installed one desktoppicture.db file or another for each user.


CCT Badge CCA Badge

Posted: 9/12/14 at 4:37 AM by andysemak

please excuse the n00bness.

In one area of our University, they require a different wallpaper to be used to the one that is deployed as part of our base image.

i use the bash script above to force this change at logon and it works very well. the users have now asked that a different wallpaper is used for 2 accounts that are created via policy post install. How can I adapt this script so that when the user logs in with either the 'graphicsadmin' or 'edit' accounts they get a different wallpaper to the one that is used for all other accounts (local and ADS).

Many thanks,


CCA Badge CJA Badge CMA Badge

Posted: 9/12/14 at 5:17 AM by franton

Hi @andysemak ,

The trick is to modify the script to use a supplied username from Casper itself, then use different policies to do the script calling.

Posted: 10/3/14 at 11:47 AM by McLeod

I attempted to run @franton][/url 's script which is posted above after making a few changes. Got an error "unexpected end of file". Attempted to run the following commands below manually, and still wasn't able to get the wallpaper to stick:

sqlite3 /Users/localaccount/Library/Application\ Support/Dock/desktoppicture.db UPDATE data SET value = "wallpaper directory entered here";

killall Dock

Not sure what steps to take from here but editing the plist and this local database aren't working for me. Did anyone else have luck with another method?

CCA Badge CJA Badge CMA Badge

Posted: 10/3/14 at 12:02 PM by franton

Please look at my original example again. You'll notice I'm not escaping out the file path with a \ in the sql commands.

Posted: 10/3/14 at 12:19 PM by McLeod

I ran into the same error "unexpected end of file".

My current script:


\# Script to set desktop background for SoulCycle Studio Macs running 10.9 and older OS Versions of OS X by user

\# Variables
OSversion=$( sw_vers -productVersion | cut -d. -f2 )
CurrentUser=$( ls -l /dev/console | awk '{print $3}' )
StudioWall="/Library/Desktop\ Pictures/SoulCycle_Retail_Wallpaper.jpg"

\# Code excution
if [[ "$OSversion" -ge "9" ]]; then sqlite3 /Users/$CurrentUser/Library/Application Support/Dock/desktoppicture.db << EOF UPDATE data SET value = "$StudioWall"; EOF

killall Dock

then rm -rf /Users/$CurrentUser/Library/Application\ Support/Dock/desktoppicture.db defaults write $Plist Background '{default = {ImageFilePath = "/Library/Desktop\ Pictures/SoulCycle_Retail_Wallpaper.jpg"; };}'

killall Dock


exit 0

As a work around I'm packaging the desktopbackgroup.db as a dmg from a current configured user and deploying it with FUT.

CCA Badge CJA Badge CMA Badge

Posted: 10/3/14 at 5:45 PM by franton

Trying to do variable substitution will not work at you're not in a shell environment when you run those SQLite commands!

CCA Badge

Posted: 1/28/15 at 7:12 AM by jthurwood

Hi @franton

Have you managed to get this working with a second display?



CCA Badge CJA Badge CMA Badge

Posted: 1/28/15 at 10:03 AM by franton

I'm not currently in a position to test, as I don't personally own one and i'm not currently employed. At some point I need to rework things a bit like:

wallpaper="/path/your_picture.jpg" /usr/bin/sqlite3 "~/Library/Application\ Support/Dock/desktoppicture.db "update data set value = '$wallpaper'"

That code needs a lot more refinement. I would have a look at the Graham Gilbert's python script that @gregneagle mentioned earlier too.

CCA Badge

Posted: 2/26/16 at 2:40 PM by ScottyBeach

@ franton:
That very nice. Thanks for it.
For bonus points, how would we add a directory of a dozen photos to the SQLite DB and switch them every boot? The directory full of pics need to be treated like,e some sort of array? The setting to change at boot a separate setting in a defaults write command?
Enquiring (not very good scripting) minds want to know.
- Scott

CCA Badge CJA Badge CMA Badge

Posted: 2/26/16 at 3:40 PM by franton

@ScottyBeach May I refer you to this? @rtrouton has some example code that is better suited than mine is.

CCA Badge CCE Badge CUG Badge Integrator Badge

Posted: 2/26/16 at 3:49 PM by bentoms

@ScottyBeach Not a bash version, but this from @gregneagle might work.

CCA Badge CCE Badge CJA Badge CMA Badge

Posted: 3/7/16 at 9:27 AM by seanhansell

I've forked and modified this script in order to variablize the Desktop Picture path.

If you're interested, you can view progress on the fork here:

A documentation, logging, and comment pass is already coming. The main difference with this version is that instead of passing a binary flag (in this case the word "custom"), pass the path to the Desktop Picture at Parameter 4.


# Script to set desktop background via Casper. Forked from the original work of Richard Purves <>.

# Maintainer : Sean Hansell <>
# Version 1.0 : Initial Version
# Version 1.1 : 2014-04-23 - Massive reworking to use Applescript for 10.8 and below or modify the sqlite DB for 10.9+
# Version 1.2 : 2014-04-24 - Removed AppleScript because of osascript parsing issues. Replaced with MCX.
# Version 1.3 : 2016-03-07 - Overhaul to variablize the desktop picture path.

# Casper Static Variables
desktop_picture="${4}" # Path to Desktop Picture. Define this in Casper.

# Dynamic Variables
os_version=$( sw_vers | grep ProductVersion: | awk '{print $2}' | sed 's/\./\ /g' | awk '{print $2}' )
current_user=$( ls -l /dev/console | awk '{print $3}' )
current_user_home=$( dscl . -read "/Users/${current_user}" NFSHomeDirectory | sed 's/NFSHomeDirectory\:\ //' )
desktop_db="${current_user_home}/Library/Application Support/Dock/desktoppicture.db"

if [[ -z "${desktop_picture}" ]]
    echo "desktop_picture variable is empty. Nothing to do."
    exit 1

if (( $os_version > 8 ))
    sqlite3 "${desktop_db}" << EOF
UPDATE data SET value = "${desktop_picture}";
    defaults delete "${desktop_domain}" Background
    defaults write "${desktop_domain}" Background '{default = {ImageFilePath = "'"${desktop_picture}"'";};}'
    chown "${current_user}" "${desktop_plist}"

killall Dock

echo "Desktop picture changed to ${desktop_picture}"
exit 0