Dockutil not executing command

tayyreyes
New Contributor

Hey everyone,

I am new to Dockutil and am having an issue running the script while imaging. The laptops being imaged are 10.11.3 MacBook Airs and Pros. What I want out of Dockutil is to add Google Chrome and Slack to newly imaged docks. I have created a pkg of Dockutil to download on each machine during imaging as well as a dmg (captured in Composer) that moves the Dockutil script to the /usr/local/bin location. I also set up a policy to execute the command "sh /usr/local/bin/dockutiltest.sh" that runs upon login once per computer per user. Both the pkg and dmg are loaded and stored on the machine; however, when I look at the policy logs I get plist errors:

Executing Policy Execute Dockutil Script
Running command sh /usr/local/bin/dockutiltest.sh...
Result of command:
/var/root/Library/Preferences/com.apple.dock.plist does not seem to be a home directory or a dock plist
/var/root/Library/Preferences/com.apple.dock.plist does not seem to be a home directory or a dock plist
No matching processes were found
Running Recon...
Retrieving inventory preferences from https://casper.boost.caffeine.io:8443/...
Locating accounts...
Searching path: /Applications
Locating package receipts...
Locating software updates...
Locating printers...

If I'm on the machine's terminal and execute commands, it works. I'm not sure what else I can change/edit to make the script run either after it reboots from imaging or upon login. Here is the script I have in the dmg that should run on each machine:

!/bin/bash

/usr/local/bin/dockutil --add '/Applications/Slack.app'
/usr/local/bin/dockutil --add '/Applications/Google Chrome.app'

killall -KILL Dock

I also want to note that I know you can make policies that update the dock for you but I don't want to scope that to "all computers" because this should be solely on fresh imaged machines.
Any ideas or suggestions would be extremely helpful!!! Thanks guys!!

18 REPLIES 18

jhbush
Valued Contributor II

I use a script and a launch agent to accomplish this per user.

#!/bin/bash

# Running checkSetupDone function to determine if the rest of this script needs to run.
# Yes, if $HOME/Library/Preferences/com.corp.docksetup.plist file does not exist.
# Otherwise, assume this setup script has already run for this user and does not
# need to run again.



checkSetupDone()    {

    if [ -f $HOME/Library/Preferences/com.corp.docksetup.plist ] ; then
        exit 0
    fi

}

configureDefaultDock()  {

    DOCKUTIL=/usr/local/bin/dockutil


    $DOCKUTIL --remove all --no-restart

    $DOCKUTIL --add '/Applications/Launchpad.app' --no-restart

    $DOCKUTIL --add '/Applications/Safari.app' --no-restart

    $DOCKUTIL --add '/Applications/Self Service.app' --no-restart

    $DOCKUTIL --add '/Applications/Mission Control.app' --no-restart

    $DOCKUTIL --add '/Applications/Microsoft Word.app' --no-restart

    $DOCKUTIL --add '/Applications/Microsoft Outlook.app' --no-restart

    $DOCKUTIL --add '/Applications/Microsoft PowerPoint.app' --no-restart

    $DOCKUTIL --add '/Applications/Microsoft Excel.app' --no-restart

    $DOCKUTIL --add '/Applications/Microsoft Lync.app' --no-restart

    $DOCKUTIL --add '/Applications/Cisco/Cisco AnyConnect Secure Mobility Client.app' --no-restart

    $DOCKUTIL --add '/Applications' --no-restart

    $DOCKUTIL --add '~/Downloads'

    touch $HOME/Library/Preferences/com.corp.docksetup.plist

}

checkSetupDone
configureDefaultDock

exit 0
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.company.dockSetup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>/Library/Scripts/companyDockSetup.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

jkuo
Contributor

@tayyreyes - to get mine to work, I had to reference the actual user in the dockutil command. Here's the beginning part of mine, that I think I adapted from someone else's script here on JAMF Nation:

#!/bin/sh

sleep 10

LoggedInUser=$3
LoggedInUserHome="/Users/$3"
plist=$LoggedInUserHome/Library/Preferences/com.apple.dock.plist

echo "Logged in user is $LoggedInUser"
echo "Logged in user's home $LoggedInUserHome"

if [ -e /usr/local/bin/dockutil ] ; then
    dockutilVersion=`/usr/local/bin/dockutil --version`
    echo "dockutil version: $dockutilVersion"
    echo "Clearing Dock..."
    sudo /usr/local/bin/dockutil --remove all --no-restart $LoggedInUserHome 
    echo "Adding Launchpad..."
    sudo /usr/local/bin/dockutil --add '/Applications/Launchpad.app' --no-restart $LoggedInUserHome 
    echo "Adding Self Service..."
    sudo /usr/local/bin/dockutil --add '/Applications/Self Service.app' --no-restart $LoggedInUserHome
    echo "Adding Google Chrome..."
    sudo /usr/local/bin/dockutil --add '/Applications/Google Chrome.app' --no-restart $LoggedInUserHome
else
    echo "dockutil not installed, skipping initial dock setup..."
fi

mm2270
Legendary Contributor III

Hi @tayyreyes I would say the main issue is because the Casper Suite will run scripts in a root context by default. Dockutil expects to be operating on the Dock plist of the user running the script, unless its directed to run on the plist at a different location.
The main error in the output under Result of command where it says:

/var/root/Library/Preferences/com.apple.dock.plist does not seem to be a home directory or a dock plist

Is what reveals the issue.

To resolve this, you can use the built in Casper Suite script parameter of $3, which resolves to the logged in user's name to help locate the correct Dock.plist to operate on. Very simple example:

#!/bin/sh

/usr/local/bin/dockutil --add '/Applications/Slack.app' /Users/$3

Also, I'm not sure I understand what you meant by "I also set up a policy to execute the command "sh /usr/local/bin/dockutiltest.sh" that runs upon login" Do you mean you deployed your dockutil script to the machine and then have it being run by a policy later? If so, its not strictly necessary to do this. Certainly possible, but the Casper Suite can just download and run the script directly from your JSS when the policy runs, rather than pre-deploying the script. Also, doing it that will let you use the $3 variable.

Hope that helps. Post back if you have more questions.

tayyreyes
New Contributor

Thank you @jhbush1973 and @jkuo! I will check your scripts out and see if I can get them to apply to our settings.

Also, thanks @mm2270 for explaining that error. Your explanation makes sense and I want to test using $3 to see if this works. Should I add this to the script itself that's in the dmg I created to specify the file location? Or should I update the script and add it to Casper Admin to add that file on the image itself? Thanks again!

jkuo
Contributor

@tayyreyes - no problem!

Regarding the $3, you would just use it in the script (see the variable LoggedInUserHome in my example, or /Users/$3 in @mm2270 's example), and then you can set a Casper policy for the script to run on login.

mm2270
Legendary Contributor III

@tayyreyes, just keep in mind that $3 actually only works in 3 triggers that I know of - login, logout and Self Service. If a script is run under any other trigger, it won't understand $3 as being the logged in user. But since you said you were running a script at login, this should work OK to use it.

As for using $3 in a script that is called by a command directly to the path of the script to run it, well, I guess it will work, but honestly I've never done it that way, so I don't know. Usually I let Casper run my scripts for me by adding the script directly into a policy, rather than deploying a file down first and then having it run the script by its path.
If you want to deploy the script file, and you find its not working with $3 in it for some reason, your choices would be:

  1. Use the script in a policy directly rather than deploying it first, then running it later
  2. Get the logged in user as @jkuo is doing, which is typically what I do as well
  3. Or, you can try calling the jamf binary to run the script to see if it will use $3.
/usr/local/jamf/bin/jamf runScript -script dockutiltest.sh -path /usr/local/bin/

The syntax is a little odd, but basically, you put in the script name only after the -script flag, then the path to the script only after the -path flag. That runs the script the same as if the policy downloaded it from the JSS and ran it directly.

tayyreyes
New Contributor

@jhbush1973 I actually just tried out your script and it works great when I push it out to a test machine via Casper Remote. I want to continue to test this out with imaging but quick question with your second script. Is that the launch agent that calls for the 1st script to run at reboot? How do you incorporate that? Do you put it as a file in a certain location? Or did you create a policy for that script to run?

tayyreyes
New Contributor

Tried putting the script in a policy with the "login" trigger. Here is the script (using @jhbush1973's script as reference ) that works when I remotely push it to the laptop via Casper Remote:

!/bin/bash

configureDefaultDock() { DOCKUTIL=/usr/local/bin/dockutil

$DOCKUTIL --remove all --no-restart

$DOCKUTIL --add '/Applications/Launchpad.app' --no-restart

$DOCKUTIL --add '/Applications/Safari.app' --no-restart

$DOCKUTIL --add '/Applications/Calendar.app' --no-restart

$DOCKUTIL --add '/Applications/Notes.app' --no-restart

$DOCKUTIL --add '/Applications/Photos.app' --no-restart

$DOCKUTIL --add '/Applications/App Store.app' --no-restart

$DOCKUTIL --add '/Applications/System Preferences.app' --no-restart

$DOCKUTIL --add '/Applications/Google Chrome.app' --no-restart

$DOCKUTIL --add '/Applications/Slack.app' --no-restart

$DOCKUTIL --add '/Applications/Self Service.app' --no-restart

$DOCKUTIL --add '~/Downloads'

touch $HOME/Library/Preferences/com.corp.docksetup.plist

}

configureDefaultDock
killall -KILL Dock

Sending remotely it loads correctly and looks good. However, when putting it in a policy, it doesn't update on the scoped machine. It will restart the Finder showing the script is being ran but it doesn't show up the way I set it to. Any ideas?

jkuo
Contributor

I'd try it with the home directory immediately after the --no-restart, e.g. the /Users/$3 or the $LoggedInUserHome examples from above.

mm2270
Legendary Contributor III

@tayyreyes in reference to @jhbush1973's script, his was being run by a LaunchAgent, which actually runs scripts or commands as the logged in user. As such, his script doesn't need to have the path to a home directory for dockutil to work on, since it can only be running as the logged in user. That's just how LaunchAgents work.
When you place that same script into a policy, again, its going to run the dockutil commands as 'root' So you run into the same issue as before where its not able to affect the changes since its expecting to make changes to the root account's Dock, not the user's Dock that's logged in.
As @jkuo mentioned, you can add the user home with /Users/$3, or /Users/$loggedInUser or whatever at the end of each dockutil line and that should address the issue.

ericyue
New Contributor

+1 on having trouble with dockutil. So I watered down the examples to this

#!/bin/bash LoggedInUser=$3 LoggedInUserHome="/Users/$3" plist=$LoggedInUserHome/Library/Preferences/com.apple.dock.plist echo "Logged in user is $LoggedInUser" echo "Logged in user's home $LoggedInUserHome" sudo /usr/local/bin/dockutil --add '/Applications/Notes.app' $LoggedInUserHome

I ran it by calling the JamF binary such as /usr/local/jamf/bin/jamf runScript -script dockutiltest.sh -path /usr/local/bin/ and I get this result:

Running script dutest.sh... Script exit code: 1 Script result: Logged in user is Logged in user's home /Users/ /Users/Library/Preferences/com.apple.dock.plist does not seem to be a home directory or a dock plist

Notice the it's not resolving the logged in user or the user's home. Why?

mm2270
Legendary Contributor III

@ericyue You can't use $3 to resolve to the username when a script is run normally in Terminal. It only applies when a script is called by the jamf binary during login, logout and Self Service, and perhaps one other time I'm not thinking of. But when you run it with sudo jamf runScript, etc. it has no idea what $3 means, so that's why its not working.
This is generally why I avoid using $3 in my scripts. While its nice to just drop that in and have it work, its limited, since it won't work in all instances where a script might be called. For the sake of greater flexibility and portability, I prefer to use a method similar to what @jkuo posted several posts above to get the logged in user name. The one I've been using more lately is:

stat -f%Su /dev/console

If you replace

loggedInUser=$3

with

loggedInUser=$(stat -f%Su /dev/console)

and try it again it should work,

tayyreyes
New Contributor

Thank you guys for all your help! I wasn't able to figure out how to put the script into my image but instead I created a policy. Here is the final script that worked for us:

!/bin/sh

LoggedInUser=$3
LoggedInUserHome="/Users/$3"

configureDefaultDock() {

echo "Logged in user is $LoggedInUser" echo "Logged in user's home $LoggedInUserHome"

if [ -e /usr/local/bin/dockutil ] ; then dockutilVersion=/usr/local/bin/dockutil --version echo "dockutil version: $dockutilVersion" echo "Clearing Dock..."

/usr/local/bin/dockutil --remove all --no-restart $LoggedInUserHome

echo "Adding Launchpad..." /usr/local/bin/dockutil --add '/Applications/Launchpad.app' --no-restart $LoggedInUserHome echo "Adding Safari..." /usr/local/bin/dockutil --add '/Applications/Safari.app' --no-restart $LoggedInUserHome echo "Adding Calendar..." /usr/local/bin/dockutil --add '/Applications/Calendar.app' --no-restart $LoggedInUserHome echo "Adding Notes..." /usr/local/bin/dockutil --add '/Applications/Notes.app' --no-restart $LoggedInUserHome echo "Adding Photos..." /usr/local/bin/dockutil --add '/Applications/Photos.app' --no-restart $LoggedInUserHome echo "Adding App Store..." /usr/local/bin/dockutil --add '/Applications/App Store.app' --no-restart $LoggedInUserHome echo "Adding System Preferences..." /usr/local/bin/dockutil --add '/Applications/System Preferences.app' --no-restart $LoggedInUserHome echo "Adding Google Chrome..." /usr/local/bin/dockutil --add '/Applications/Google Chrome.app' --no-restart $LoggedInUserHome echo "Adding Slack..." /usr/local/bin/dockutil --add '/Applications/Slack.app' --no-restart $LoggedInUserHome echo "Adding Self Service..." /usr/local/bin/dockutil --add '/Applications/Self Service.app' --no-restart $LoggedInUserHome echo "Adding Downloads..." /usr/local/bin/dockutil --add '~/Downloads' --no-restart $LoggedInUserHome

touch $LoggedInUserHome/Library/Preferences/com.company.docksetup.plist

else echo "dockutil not installed, skipping initial dock setup..." fi

}

configureDefaultDock
killall -KILL Dock

exit 0

Thanks again!!!

McKinnonTech
New Contributor III

@tayyreyes Do you still use this script?

I've created my own version for 10.11 using yours and others I've found and nothing seems to work.

Here's mine:

#!/bin/sh

LoggedInUser=$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')
LoggedInUserHome="/Users/$LoggedInUser"

configureDefaultDock() {

echo "Logged in user is $LoggedInUser"
echo "Logged in user's home $LoggedInUserHome"

if -e '/usr/local/bin/dockutil'
then dockutilVersion=$(/usr/local/bin/dockutil --version)

echo "dockutil version: $dockutilVersion"

echo "Clearing Dock..." /usr/local/bin/dockutil --remove all --no-restart "$LoggedInUserHome"

echo "Adding Launchpad..." /usr/local/bin/dockutil --add '/Applications/Launchpad.app' --no-restart --position 1 "$LoggedInUserHome"
echo "Adding Calendar..." /usr/local/bin/dockutil --add '/Applications/Calendar.app' --no-restart  --position 2 "$LoggedInUserHome"
echo "Adding TextEdit..." /usr/local/bin/dockutil --add '/Applications/TextEdit.app' --no-restart --position 3 "$LoggedInUserHome"
echo "Adding App Store..." /usr/local/bin/dockutil --add '/Applications/App Store.app' --no-restart --position 4 "$LoggedInUserHome"
echo "Adding Google Chrome..." /usr/local/bin/dockutil --add '/Applications/Google Chrome.app' --no-restart --position 5 "$LoggedInUserHome"
echo "Adding GarageBand..." /usr/local/bin/dockutil --add '/Applications/GarageBand.app' --no-restart --position 6 "$LoggedInUserHome"
echo "Adding Applications..." /usr/local/bin/dockutil --add '~/Applications' --no-restart --position 7 "$LoggedInUserHome"
echo "Adding Downloads..." /usr/local/bin/dockutil --add '~/Downloads' --no-restart --position 8 "$LoggedInUserHome"

touch "$LoggedInUserHome"/Library/Preferences/com.company.docksetup.plist

else echo "dockutil not installed, skipping initial dock setup..."

  fi

}

configureDefaultDock
killall -KILL Dock

exit 0

I get "line 11: -e: command not found"

The dockutil file is definitely in /usr/local/bin/, but it doesn't appear to find it.

Is there some strange condition when using -e that it has to be a regular file, or have an extension?

khey
Contributor

just wondering why are you guys using scripts if you can use Policy instead.

i got mine working by creating Dock Items and Policy to run once per user per computer.

McKinnonTech
New Contributor III

@khey This doesn't solve the issue of OS X adding unnecessary apps to the Dock and from what I've read the Dock Items policy is really inconsistent.

BOBW
Contributor II

@McKinnonTech

try this change line 11 to:

if [ -e /usr/local/bin/dockutil ]

cddwyer
Contributor

Scripts execute as the root user so unless you run that as the logged in user it will be trying to modify the root account's dock.