0

macOS Ventura is apparently no longer letting us set the default Dock application items from root (command silently fails), so we are having to run in the user's space from our MDM script. Unfortunately, this means I have to chain a grep command with SU which is causing me all sorts of problems for items that have spaces:

zsh for the environment, other logic to set $current_user that's not relevant removed.

__dock_item() {
    printf '%s%s%s%s%s' \
           '<dict><key>tile-data</key><dict><key>file-data</key><dict>' \
           '<key>_CFURLString</key><string>' \
           "$1" \
           '</string><key>_CFURLStringType</key><integer>0</integer>' \
           '</dict></dict></dict>'
}

for dockItem in {/Applications/{"Google Chrome","Slack","zoom.us"}.app,"Done"}; do
    echo $dockItem
    if [[ -e "$dockItem" ]]; then
        if ! [[ $dockItem == "Done" ]]; then
            # Does not actually work, nor does setting GREP_ARRAY=(-q "$dockItem") with grep "${GREP_ARRAY[@]}"
            # does not properly escape the path when executed "Chrome.app does not exist"
            EscapedPath=$( echo "$dockItem" | sed 's/ /\\ /g' )
            if (/usr/bin/su - "${current_user}" -c "defaults read com.apple.dock persistent-apps | /usr/bin/grep -q $EscapedPath"); then
                printf '%s\n' 'Dock icon already found.'
            else
                printf '%s\n' 'Setting up Dock icons...'
                /usr/bin/su - "${current_user}" -c "defaults write com.apple.dock persistent-apps -array-add '$(__dock_item $dockItem)'"
            fi
        fi
    else
        printf '%s\n' 'Restarting Dock...'
        killall Dock
    fi
done

Any time it tries to process "Google Chrome" the grep command fails and the application is pinned to the dock again, creating an endless cycle of copies of Chrome being added.

I've tried multiple methods to escape $dockItem, and converting it to an array, but it fails to recognize the complete string in Ventura's zsh shell.

if (/usr/bin/su - "${current_user}" -c "defaults read com.apple.dock persistent-apps | /usr/bin/grep -q '$dockItem'"); then

Is not properly escaped when executed either.

1 Answers1

0

Why not use sudo instead of su? it doesn't run the command via the user's shell, so filenames and strings don't need an additional layer of quoting. It does mean, however, that you can't run things like pipelines (defaults read ... | grep) in the user's shell, but you didn't really need to anyway; run the grep in the parent shell on the output from sudo defaults read.

After discussion in the comments, it looks like another part of the problem is that the name is URL=encoded (i.e. spaces are converted to "%20"), which can be converted with sed or even directly in bash: "${dockItem// /%20}" I still haven't tested this, but I think it'd be something like this:

[...]
if /usr/bin/sudo -u "${current_user}" defaults read com.apple.dock persistent-apps | /usr/bin/grep -Fq "${dockItem// /%20}"; then
 [...]
    /usr/bin/sudo -u "${current_user}" defaults write com.apple.dock persistent-apps -array-add "$(__dock_item "${dockItem// /%20}")"
Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • My understanding is that I would need to also modify /etc/sudoers for that to work, which wouldn't be viable for this script to run. – FridaeCoffee Oct 31 '22 at 21:38
  • @FridaeCoffee This script is running as root, right? I don't have a Ventura system available to check, but the standard /etc/sudoers should have an entry allowing root to run any command as any user. – Gordon Davisson Oct 31 '22 at 21:49
  • Just tried the script, the output is just giving me an unhelpful "unmatched " log entry when I have set -x enabled and it reaches the sudo -u line and exits with a non-zero status. – FridaeCoffee Oct 31 '22 at 21:51
  • The script is run as root through our MDM tool. – FridaeCoffee Oct 31 '22 at 21:55
  • Hmm, can you check the output from `defaults read ...`? On my system I get e.g. `"_CFURLString" = "file:///Applications/Browsers/Google%20Chrome.app/"` (which has the space URL-encoded, rather than escaped). – Gordon Davisson Oct 31 '22 at 22:03
  • Well, I feel dumb now! sed -e 's/ /%20/g' fixed it. – FridaeCoffee Oct 31 '22 at 22:16
  • @FridaeCoffee You can even do that directly in bash with `${dockItem// /%20}` -- see update. – Gordon Davisson Oct 31 '22 at 22:26