Skip to content
Elliot Nevills edited this page Jun 21, 2024 · 22 revisions

How does Outset work?

Outset is controlled by six launchd plists:

/Library/LaunchDaemons/io.macadmins.outset.boot.plist
/Library/LaunchDaemons/io.macadmins.outset.cleanup.plist
/Library/LaunchDaemons/io.macadmins.outset.login-privileged.plist
/Library/LaunchAgents/io.macadmins.outset.login.plist
/Library/LaunchAgents/io.macadmins.outset.login-window.plist
/Library/LaunchAgents/io.macadmins.outset.on-demand.plist

Service Management (macOS 13+)

Optionally on macOS 13+ all except login-window can be managed using the SMAppService framework and the plists are located and loaded from within the app bundle.

Under macOS 13, the following commands are used to interact with Outset's agents:

  • --enable-services: will check for and load services. If no config profile to manage login items for io.macadmins.Outset is present this will cause a user notification of a new background process to be approved
  • --disable services: unloads the services. This does not remove the entry from login items which is by design according to Apple
  • --service-status: shows the current service status (Enabled, Not Registered, Requires Approval or Not Found)

Process

For each folder of items to process, if a file type is present, it always operates on:

  1. packages
  2. then scripts

If multiple items of a file type are present in a directory, processing will take place with alphabetical priority.

Script processing

For all script processing, the current console user (if present) is passed in as the first argument.

This can cause some previously working scripts to hiccup when migrating from Outset 3. An example below covers Python's argparse library:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("user", metavar="user", nargs=1, help="User to run against, used by outset")
args = parser.parse_args()
print(args)

> Namespace(user=['alice'])

What happens during boot?

The boot LaunchDaemon processes packages and scripts during the boot sequence, and will either run once, or at every subsequent boot, depending on the directory in which the files are placed:

/usr/local/outset/boot-once/
/usr/local/outset/boot-every/

When the Mac boots, launchd will run /usr/local/outset/outset --boot which does the following:

  • Verifies that all working directories exist, and creates them if not.
  • If the network_wait setting is set to True (which is the default setting):
    • disables the loginwindow process
    • waits until the Mac has a valid IP address
  • Processes and deletes everything in /usr/local/outset/boot-once/
  • Loads the loginwindow.
  • Processes everything in /usr/local/outset/boot-every/

What happens at the login window?

The login window runs user scripts located in the following directory:

/usr/local/outset/login-window/

Login window scripts are run as root.

When the system is at the login window either after boot or if the user logs out, launchd will run /usr/local/outset/outset --login-window

NOTE

Scripts in this location are always run. For limiting if/when login window scripts are run you will need to provide checks within your scripts to prevent undesired results, e.g. if you wish to run a task on user logout only, not before login.

When the login windows appers after boot, scripts here will run at the same time as boot-every or boot-once scripts however order is not guaranteed so the boot scripts may run first or the login-window script may run first. Therefore priority cannot be assumed.

What happens during login?

The login LaunchAgent runs any scripts during user login, and will run either once, or at every subsequent login, depending on the directory in which the files are placed:

/usr/local/outset/login-once/
/usr/local/outset/login-every/

When the user logs in, launchd will run /usr/local/outset/outset --login which does the following:

  • If the user is not in the ignored_users array:
    • Processes everything in /usr/local/outset/login-once/ in the user context.
    • Logs the names of all login-once items to ~/Library/Preferences/io.macadmins.Outset.plist under the key run_once
    • Processes everything in /usr/local/outset/login-every/ in the user context.

Outset completes the login run by checking if there are any packages or scripts in the the following directories:

/usr/local/outset/login-privileged-once/
/usr/local/outset/login-privileged-every/

If there are any files defined in these directories, Outset triggers an additional LaunchDaemon to run /usr/local/outset --login-privileged as root, which does the following:

  • If the user is not in the ignored_users array:
    • Processes everything in /usr/local/outset/login-privileged-once/ in the root context.
    • Logs the names of all login-privileged-once items to /Library/Preferences/io.macadmins.Outset.plist in a run_once-<username> array where <username> is the user name of the console user.
    • Processes everything in /usr/local/outset/login-privileged-every/ in the root context.

What order do jobs run in?

When processing items Outset handles each type (all pkgs then scripts) alphanumerically, meaning a file starting with 000 will be evaluated before one that starts with 0a, after which would be files like AAA that start with capitalized characters, then lowercase files aaa.

What happens during on-demand jobs?

The on-demand LaunchAgent and cleanup LaunchDaemon, respectively, process and remove scripts from the following directory immediately, in the user context, for any currently logged in user (for those using Fast User Switching, it will only run in the current GUI session, and will not run in any background sessions):

/usr/local/outset/on-demand/

When on-demand is initiated, launchd will run /usr/local/outset/outset --on-demand, which does the following in the current user session only:

  • Processes everything in /usr/local/outset/on-demand/
  • Deletes everything in /usr/local/outset/on-demand/

Removing Outset

If you decide you don't want to use Outset any more, these commands should remove all traces of the tool:

sudo launchctl bootout system /Library/LaunchDaemons/io.macadmins.outset.*
sudo rm -fv "/Library/LaunchDaemons/io.macadmins.outset.*"

userID=$(id -u $(whoami))
launchctl bootout gui/$userID /Library/LaunchAgents/io.macadmins.outset.login.plist
launchctl bootout gui/$userID /Library/LaunchAgents/io.macadmins.outset.on-demand.plist
launchctl bootout gui/$userID /Library/LaunchAgents/io.macadmins.outset.login-window.plist
sudo rm -fv /Library/LaunchAgents/io.macadmins.outset.*

sudo rm -rfv /usr/local/outset
sudo pkgutil --forget io.macadmins.Outset

Skipping a run-once script

If you decide that you may need to skip a run-once script or ensure that it's not ran when migrating to Outset v4, you can do so with this logic:

/usr/bin/defaults write ~/Library/Preferences/io.macadmins.Outset.plist run_once -dict-add "/usr/local/outset/login-once/SCRIPT_PATH_WITH_ENDING_HERE" -date "1970-01-01 00:00:00 +0000"

If you are running this as root (such as with JAMF or Munki when installing Outset), you'll need to run it as the user in question.

#!/bin/zsh
CURRENTUSER="$( echo 'show State:/Users/ConsoleUser' | /usr/sbin/scutil | /usr/bin/awk '/Name :/ { print $3 }' )"
USERID="$(/usr/bin/id -u "$CURRENTUSER")"
/bin/launchctl asuser $USERID /usr/bin/sudo -u $CURRENTUSER /usr/bin/defaults write /Users/$CURRENTUSER/Library/Preferences/io.macadmins.Outset.plist run_once -dict-add "/usr/local/outset/login-once/SCRIPT_PATH_WITH_ENDING_HERE" -date "1970-01-01 00:00:00 +0000"

Migrating from Outset 3

Just follow the deployment instructions. The installer will take care updating Outset 3 to Outset 4 and backup any preferences files.

Logging

Log files are saved to the logs directory in your outset directory.