Setting Account Picture/JPEGPhoto with dscl in terminal

accountspermissionterminal

I'm working on a script based on this question: What steps are needed to create a new user from the command line on Mountain Lion?

The script is packaged up in an empty installer as a postflight script.

It's all working well enough – however, I cannot get the Account picture set. I can use dscl to set the Picture property to an image file, for example the
default Apple Account photos.

I can even copy a photo I include in the package over to a number of directories, including /Users/newAccount/Public. But the permissions are messed up and no one but the newAccount can view the profile image. I am unable to chmod the file. Instead, I have to use the GUI and "get info -> Set Permissions"

The other option that I can see is if I set the JPEGPhoto value. This is what happens when you use a custom photo or take one in photobooth. However, I'm not sure how to convert the photo I include in the installer into Hex or Whatever is being stored in the JPEGPhoto value.

Thanks!
– Chris

Edit: Added script. Everything works in this script – the picture just won't display, due to permissions. The path is set properly. I've tried to place it several different locations that have shared access, but no matter what the permissions are wrong and I cannot chmod them.

###CREATE TP ADMINISTRATOR ACCOUNT###

LastID=`dscl . -list /Users UniqueID | awk '{print $2}' | sort -n | tail -1`

NextID=$((LastID + 1))
. /etc/rc.common
dscl . create /Users/administrator

dscl . create /Users/administrator RealName "Administrator Account"
dscl . create /Users/administrator hint "the password Duh"

dscl . passwd /Users/administrator password
dscl . create /Users/administrator UniqueID $NextID
dscl . create /Users/administrator PrimaryGroupID 80
dscl . create /Users/administrator UserShell /bin/bash
dscl . create /Users/administrator NFSHomeDirectory /Users/administrator
cp -R /System/Library/User\ Template/English.lproj /Users/administrator
chown -R administrator:staff /Users/administrator

cp $1"/Contents/Resources/admin.jpg" /Users/administrator/Public
dscl . create /Users/administrator Picture "/Users/administrator/Public/admin.jpg"

###CREATE TP ADMINISTRATOR ACCOUNT###

Best Answer

dscl

It seems that the most promising method is to modify the JPEGPhoto attribute for the user. The problem is, while the JPEG image can be converted very simply to a hex string, the value is too long to just pass at the command-line. This attribute seems to be what the GUI writes to when you drag in an image. Recovering the image from this variable when set is as simple as:

dscl . read /Users/username JPEGPhoto | xxd -r -p > ./username.jpg

The second common way mentioned on the forums is to:

dscl . delete /Users/username JPEGPhoto
dscl . delete /Users/username Picture
dscl . delete /Users/username Picture "/Library/User Pictures/username.jpg"

This only changes the 'login' icon and not the icon seen in the User detail page in System Preferences.

Using sysadminctl

When creating or managing users prefer sysadminctl over the list of dscl commands that are commonly mentioned in forums. sysadminctl sets the user up correctly with a SECURE TOKEN which is important if you want to use FileVault the user should be able to unlock the disk at boot. It also offers the ability to set the user image when created. Unfortunately it doesn't offer the ability to change user images.

Using dsimport

What does work for changing the user image is dsimport.

The script usage is:

./change_userpic.sh USERNAME /path/to/image/jpg

GIST

#!/bin/bash

declare -xr AWK_CMD="/usr/bin/awk"
declare -xr SW_VERS_CMD="/usr/bin/sw_vers"
declare -xr DSIMPORT_CMD="/usr/bin/dsimport"
declare -xr ID_CMD="/usr/bin/id"

USERNAME="$1"; export USERNAME
USERPIC="$2"; export USERPIC

OSVERSION=$(${SW_VERS_CMD} -productVersion | ${AWK_CMD} -F"." '{print $2;exit}'); export OSVERSION
# Add the LDAP picture to the user record if dsimport is avaiable 10.6+
if [ -f "${USERPIC}" ] ; then
    # On 10.6 and higher this works
    if [ "${OSVERSION}" -ge "6" ] ; then
        declare -x MAPPINGS='0x0A 0x5C 0x3A 0x2C'
        declare -x ATTRS='dsRecTypeStandard:Users 2 dsAttrTypeStandard:RecordName externalbinary:dsAttrTypeStandard:JPEGPhoto'
        declare -x PICIMPORT="/Library/Caches/${USERNAME}.picture.dsimport"
        printf "%s %s \n%s:%s" "${MAPPINGS}" "${ATTRS}" "${USERNAME}" "${USERPIC}" >"${PICIMPORT}"
        # Check to see if the username is correct and import picture
        if ${ID_CMD} "${USERNAME}" &>/dev/null ; then
            # No credentials passed as we are running as root
            ${DSIMPORT_CMD} "${PICIMPORT}" /Local/Default M &&
                echo "Successfully imported users picture."
        fi
    fi
fi