Script to run Adobe Update Remote Manager as Launch Daemon at Boot without MDM

Scenario: I need to figure out how to run the /usr/local/bin/RemoteUpdateManager at DeepFreeze maintenance cycle. During this maintenance cycle, the computers will restart to the login screen and enter a thaw and locked mode for a period of time. As mentioned we do not have a MDM yet, so I created a launch daemon which to my understanding should run the script at boot without requiring any input or to login.

Update.sh

#!/bin/bash
rum=/usr/local/bin/RemoteUpdateManager

if [[ -f $rum ]]; then
echo "Starting Adobe RemoteUpdateManger..."
sudo $rum --action=list #Listing the updates for now, but will install later
else
echo "Adobe RemoteUpdateManager not found."
fi

Based off Adobe's RUM guide, link, you have to use sudo for RemoteUpdateManager

com.test.schedule.plist

<?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>EnviromentVariables</key>
<dict>
    <key>PATH</key>
    <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
</dict>
<key>Label</key>
<string>com.test.updateschedule</string>
<key>ProgramArguments</key>
<array>
    <string>sudo</string>
    <string>sh</string>
    <string>/Library/Scripts/Updates.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/var/log/EsoUpdateError.log</string>
<key>StandardOutPath</key>
<string>/var/log/EsoUpdate.log</string>

Steps Taken

  1. Copy update.sh to /Library/Scripts/ and the .plist to /Library/LaunchDaemons/
  2. sudo chown root:wheel .sh
  3. sudo chown root:wheel .plist.
  4. sudo launchctl load -w /Library/LaunchDaemons/.plist
  5. The moment I load the .plist, it creates two logs at /var/log/. The standardoutpath log lists all the updates which is exactly what I want.

Issue

After restarting the computer to see if results stick, I notice that the results cannot be replicated. Instead I receive the following in StandardErrorPath log:

RemoteUpdateManager exiting with Return Code (1)

Based of the RUM guide, Return Code (1) is: "Generic error, for example an internal error. For example, this might be the case where Adobe Application Manager installation is corrupted or network is not present. In this case, typically, the process of downloading or installing updates cannot be started at all."

I went as far to apply chmod 777 and chown root:wheel to both the .sh and .plist, along with `/usr/local/bin/RemoteUpdateManager'. Tried without sudo in the .plist and .sh.


Solution 1:

Since the launchd plist is in /Library/LaunchDaemons/ it's going to be run as root. Given that, you don't need to call sudo as your first program argument, nor do you need it in the shell script. Also, it's good practice to use full paths in program arguments so /bin/sh instead of sh.

That's all just housekeeping though. What I find interesting is that it works when you are logged in as a user but does not work when launchd runs it upon load during restarting. The launchd.plist man page section for RunAtLoad has this little warning:

This key should be avoided, as speculative job launches have an adverse effect on system- boot and user-login scenarios.

For that reason I avoid using RunAtLoad true for root level launchd tasks. I suspect what you're seeing is that the system is not ready to run RemoteUpdateManager at the moment when launchd loads your plist.

RunAtLoad is awfully handy, though, so you may have to stick with it, but I'd play around other mechanisms to tell launchd when to run your script. You could try using StartInterval 60 or something to give the system 60 seconds to fully spin up after loading the plist. That assumes your maintenance window is at least 60 seconds long plus whatever time is needed by your script. An alternative could potentially be to use StartCalendarInterval but you'd want to be very sure that the maintenance window is rigidly defined in time and not cancellable by your users.

You could also keep RunAtLoad and use KeepAlive with SuccessfulExit true to make launchd keep trying to run your script until it successfully exits. It's not an elegant solution but it may work. If you're doing this make sure to set your ThrottleInterval to something reasonable or else launchd will complain mercilessly if the task is permanently failing.

The last thing to keep in mind is that your plist is going to cause your shell script to be run at EVERY restart. You should incorporate some mechanism in your shell script to detect if you're in a maintenance period and exit 0 if not.