If you’re just starting out using Mosyle MDM, you may have run into a situation where a Custom Command that you’ve sent to a device doesn’t appear to work. You test the script on your local machine, and subsequently tear your hair out when it works just fine.
Cause #1: You’re not running the command as the local user
MDM Custom Commands are, by default, run on target devices as the root user, and not the local user.
For example, if you want to create a script that disables Natural scrolling on the user’s Magic Trackpad, simply running the following command in a Custom Command profile won’t work:
defaults write NSGlobalDomain com.apple.swipescrolldirection -bool false
Because Custom Commands are executed by the Mosyle MDM agent as the root user, you’re only modifying the scrolling preferences for the root user, and not the currently logged in user.
The simple solution for this is to run the command via sudo, using the –u
flag to instruct sudo to run the command as the currently logged in user (stat -f “%Su” /dev/console).
sudo -u $(stat -f "%Su" /dev/console) /bin/sh <<'END'
defaults write NSGlobalDomain com.apple.swipescrolldirection -bool false
Add this sudo line to the top of your script, and all commands which follow that line will be run as the current user, instead of root.
Cause #2: Unqualified paths to executables
The other reason why your scripts may be failing is because you’re calling executables that are installed in locations that aren’t in the user’s $PATH.
Let’s say you want to run a script that uses the awesome JSON utility jq. If the script calls the jq
binary without a fully qualified path to that binary (i.e. /usr/local/bin/jq
) it will work fine on your local system, because /usr/local/bin
is likely in your $PATH.
The root user, however, does not have /usr/local/bin
specified in its default $PATH. So calling jq
will result in a “command not found” error if you try to run the same script on an MDM managed system.
The simplest solution to this is to assign the full path to the executables to variables at the top of your script, then use the variables via parameter substitution whenever you need call that executable from within the script.
#!/usr/bin/env bash
# Assign fully-qualified path to jq to variable
jq="/usr/local/bin/jq"
# Return jq version number
"$jq" --version