Having problems with Dock configuration

TheCookieMonsta
New Contributor II

I have created a configuration profile for the dock. I tried to do it with Dock Master and the dock resets after the computer reboots. (sounds like working as intended, however I do not want to have it this restrictive) Then I tried iMazing Profile Editor and the dock reset as well and the magnification got locked. 

so really want I want to do is to Crate a dock, place the icons, and then the user can modify it as they wish in the exception to removing 2 icons that must stay.

4 REPLIES 4

mm2270
Legendary Contributor III

"so really want I want to do is to Crate a dock, place the icons, and then the user can modify it as they wish in the exception to removing 2 icons that must stay."

Unfortunately what you're asking for here is really not easy at all. Almost impossible unless you have an ongoing policy that keeps adding those 2 dock items in if it finds them missing. Generally speaking the options for setting up the Dock fall into one of these types.

1. Configuration Profile, which usually makes the Dock immutable, cannot be altered by the user. Sounds like you don't want that.

2. Use a script and LaunchAgent that calls dockutil to set up the Dock how you want it, but only do it once, and then let the user make modifications as they would like. But that would mean they can also remove the 2 icons you want to always have.

3. Push just the 2 icons you want to their Dock using the Jamf Pro built in Dock icons function, which, I'm going to be honest, I haven't used in a few years now, so I honestly don't know if it still works or not?

As I mentioned, there is no option I'm aware of where you can make 90% of the Dock modifiable, and 10% of it immutable. Apple simply doesn't allow us to get that granular when it comes to the Dock (and a great many other things too)

If you really want that, you will have to use something like dockutil and have an ongoing policy that runs a script to call dockutil and keeps checking to see if the icons you need are in the user's Dock, and if they aren't, add them back in. You can't prevent the users from removing the icons, but you can add them back in each time the policy runs. That's about the best I can think of.

TheCookieMonsta
New Contributor II

how would I do it with a script?

I tried this one, but its not working for me:

 

#!/bin/bash

## This allows you to specify lists of items to remove and add in arrays, and then they'll be done in bulk using a for loop
## Items to remove should be the label (usually the name of the application)
## Items to add are the full path to the item to add (usually /Applications/NAMEOFAPP.app)
## A few examples are prepopulated in the arrays, but feel free to tweak as suits the needs of your organization

# original https://raw.githubusercontent.com/aysiu/Mac-Scripts-and-Profiles/master/DockutilAddRemoveArrays.sh
# bash string manipulations here https://www.tldp.org/LDP/LG/issue18/bash.html

# TO-DO:
# - check for jamf
# - check for dockutil; install from jamf (or download from site)
# - check for AD binding, add Directory Utility if bound
# - check OS version, add System Prefs vs System Settings
# - check OS version, add Safari from proper location

# check for dockutil, call policy if not present

if [[ ! -e "/usr/local/bin/dockutil" ]]; then
/usr/local/bin/jamf policy -event install-dockutil
fi

itemsToRemove=(
"Address Book"
"App Store"
"Books"
"Calendar"
"Contacts"
"Dictionary"
"Downloads"
"FaceTime"
"Freehand"
"iBooks"
"iPhoto"
"iTunes"
"Keynote"
"Launchpad"
"Mail"
"Maps"
"Messages"
"Mission Control"
"Music"
"News"
"Notes"
"Numbers"
"Pages"
"Photos"
"Podcasts"
"Reminders"
"Siri"
"Stocks"
"TextEdit"
"TV"
)

itemsToAdd=(
"//Applications/Bayview App Store.app"
"//Applications/Microsoft Teams (work or school).app"
"//Applications/Microsoft Outlook.app"
"//Applications/Microsoft Word.app"
"//Applications/Microsoft Excel.app"
"//Applications/Microsoft To Do.app"
"//Applications/Microsoft Remote Desktop.app"
"//System/Applications/System Settings.app"
)

for removalItem in "${itemsToRemove[@]}"
do
# Check that the item is actually in the Dock
inDock=$(/usr/local/bin/dockutil --list | /usr/bin/grep "$removalItem")
if [ -n "$inDock" ]; then
/usr/local/bin/dockutil --remove "$removalItem" --no-restart
fi
done


for additionItem in "${itemsToAdd[@]}"
do
# Check that the item actually exists to be added to the Dock and that it isn't already in the Dock
# Stripping path and extension code based on code from http://stackoverflow.com/a/2664746
additionItemString=${additionItem##*/}
additionItemBasename=${additionItemString%.*}
inDock=$(/usr/local/bin/dockutil --list | /usr/bin/grep "$additionItemBasename")
if [ -e "$additionItem" ] && [ -z "$inDock" ]; then
/usr/local/bin/dockutil --add "$additionItem" --no-restart
fi
done

sleep 3

/usr/bin/killall Dock

mm2270
Legendary Contributor III

So, while dockutil is a great and useful tool, one of the points people get tripped up on with it is that for it to really work, it has to be called as the user logged into the device. Either that, or you have to tell dockutil which dock.plist to work on. Because Jamf always runs scripts as root, it tends to cause issues when invoking dockutil unless you do one of those 2 options.

My preference has always been the former - to run the script calling dockutil as the logged in user. Basically, I create a script out to disk on the fly from within a script run by Jamf, then create a LaunchAgent on the fly that calls that script and load the LaunchAgent as the user. Since LaunchAgents run as the logged in user, it's always calling dockutil as the person on the machine, not as root.

Here's an example of the script I'm using (modified to remove my org specific details) that can be used to set up a Dock with icons after first login. This will not continue to add in any missing dock icons. That's something you'll need to work on incorporating by using some of dockutil's functionality to check the dock for items. I would suggest a similar approach of using a LaunchAgent that calls a script periodically to check for those items, and add them if they are missing.

#!/bin/bash

org="Organization-name-or-acronym"	## Edit this to suit your environment !!

## Get the logged in username
logged_in_user=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk '/Name :/ && ! /loginwindow/ {print $3}')

## Get the logged in username UID
logged_in_uid=$(id -u "$logged_in_user")

## Path to the dockutil binary
dockutil_path="/usr/local/bin/dockutil"

## Path to the LaunchAgent plist
launchagent_name="/Library/LaunchAgents/com.$org.dockconfig.plist"

## Path to the local script
script_name="/private/var/configureDock-$org.sh"


#################################### START OF SCRIPT CREATION ####################################

## Create the local script
cat << EOSCRIPT > "$script_name"
#!/bin/bash

retry_count="0"

logged_in_user=\$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ {print \$3}')

## path to Dockutil binary
dockutil_path="/usr/local/bin/dockutil"

setup_done_plist="/Users/\${logged_in_user}/Library/Preferences/com.\$org.dockconfig.plist"

## Check that the Dock is running before doing anything
until [[ \$(ps axc | grep "Dock" 2>&1 > /dev/null; echo \$?) == 0 ]]; do
	sleep 1
done

## Function to set up the Dock with the desired items
function setUpDock ()
{

## Array to store the items to be added to the Dock
dock_items+=(
"/System/Applications/System Preferences.app"
"/Applications/Safari.app"
"/Applications/Google Chrome.app"
"/Applications/Microsoft Outlook.app"
"/Applications/Microsoft Word.app"
"/Applications/Microsoft Excel.app"
"/Applications/Microsoft PowerPoint.app"
"/Applications/Microsoft Teams.app"
"/Applications/Self Service.app"
)


## Now add items to the Dock
qty="\${#dock_items[@]}"

echo "Number of items to add to the Dock: \$qty"

## This loops over the items in the above dock_items array, adding in each item to the Dock in order.
## It will keep track of the number of items being added, and when reaching the last one, restarts the Dock
i=1;
while read dock_item; do
	## First check to make sure the application is on disk at the specified path
	if [ -d "\$dock_item" ]; then
		## Now check to see if we have reached the end of the array of items or not
		if [[ "\$i" -lt "\$qty" ]]; then
			## If not at the end, add the item in with the --no-restart flag
			"\$dockutil_path" --add "\$dock_item" --no-restart
            ## Added brief pause between each --add operation to allow
            ## the Dock.plist time to catch up with the changes
            /bin/sleep 0.7
		else
			## Or add it in without the flag to have the Dock restart
			"\$dockutil_path" --add "\$dock_item"	
		fi
	else
		## If the app couldn't be found, make a note of it and skip it
		echo "The path to \$dock_item could not be found. Skipping..."
	fi
	let i=\$((i+1))
done < <(printf '%s\n' "\${dock_items[@]}")

## After completion of the above steps, we check to make sure all the items we expected added have been added,
## or we make a second attempt at adding the missing items

## Get list of the current Dock items
current_dock_items=$("\$dockutil_path" --list | /usr/bin/awk -F'file:' '{print \$1}' | /usr/bin/sed 's/	//g')

## Place items into an array for comparison
while read item; do
	current_dock_arr+=("\$item")
done < <(printf '%s\n' "\$current_dock_items")

## Get difference between the 2 arrays
diff=\$(/bin/echo \${dock_items[@]} \${current_dock_arr[@]} | /usr/bin/tr ' ' '\n' | /usr/bin/sort | /usr/bin/uniq -u)

if [ "\$diff" != "" ]; then
	if [ "\$retry_count" -lt 1 ]; then
    	retry_count=\$((retry_count+1))
    	setUpDock
	else
    	/bin/echo "Already made one retry attempt. Finalizing and exiting as is..."
        ## Turn off the show recents option for the Dock
		/usr/bin/defaults write com.apple.dock show-recents -bool false

		## Set a flag in a user level plist to indicate the configuration is complete
		/usr/bin/defaults write "\$setup_done_plist" DockSetupComplete -bool true
        exit 0
   	fi
else
	/bin/echo "All items accounted for in the current Dock. Finalizing and exiting..."
    /usr/bin/defaults write com.apple.dock show-recents -bool false

	## Set a flag in a user level plist to indicate the configuration is complete
	/usr/bin/defaults write "\$setup_done_plist" DockSetupComplete -bool true
    exit 0
fi

}


function clearDock ()
{


## First, remove all items from the standard Dock
"\$dockutil_path" --remove all

## Wait 1 second
sleep 2

## Now run the setupDock function to add apps
setUpDock

}

## Check that this user account has not had the Dock already configured
dock_setup_check=\$(/usr/bin/defaults read "\$setup_done_plist" DockSetupComplete 2>/dev/null)

if [[ -z "\$dock_setup_check" ]]; then
	clearDock
elif [[ "\$dock_setup_check" == "1" ]]; then
	echo "Dock setup completed for this account. Exiting..."
	exit 0
fi

exit 0

EOSCRIPT

##################################### END OF SCRIPT CREATION #####################################

## Fix permissions on the script
/bin/chmod +x "$script_name"
/usr/sbin/chown root:admin "$script_name"

## Create the LaunchAgent plist using defaults
/usr/bin/defaults write "$launchagent_name" Label "com.$org.dockconfig"
/usr/bin/defaults write "$launchagent_name" Program "/private/var/configureDock-$org.sh"
/usr/bin/defaults write "$launchagent_name" RunAtLoad -bool true

## Fix permissions and ownership on the LaunchAgent plist
/bin/chmod 644 "$launchagent_name"
/usr/sbin/chown root:wheel "$launchagent_name"

 

One thing not added to this script is launching the LaunchAgent. I don't do this here, as I prefer to wait until after the machine has rebooted. When the user logs in, the agent activates, does it's thing, makes a note that it ran once and then doesn't run again (the script). You could add something to kick off the LaunchAgent to this after it creates it though.