jazzace.ca

Anthony’s Mac Labs Blog

📦 Feeding Outset 2:Override Boogaloo

Posted 2023 January 03

In my previous blog post, I described my AutoPkg recipe that builds a package for a script you might want to run via Outset. For me, I want to deliver most of my scripts to Outset’s login-once folder, since I use Outset to set some initial user settings in my computer labs. But since I only delete user accounts once every four months (or when the internal drive fills, whichever comes first), I can get into the situation where I want to push out an updated version of a script that some users have already run once (for example, to set up the default dock). Outset normally tracks whether or not an item at a particular path has been processed, not whether that item has changed, so how can I force an updated login-once item to be processed? The answer is what Outset calls a Login-Once Override — and yes, we can have AutoPkg automate that too.

Outset Overrides

Outset tracks when it successfully runs a login-once (or login-privileged-once) item in its user preferences[1] (~/Library/Preferences/com.github.outset.once.plist). For example:

<key>/usr/local/outset/login-once/setDock.sh</key>
<date>2023-01-02T17:47:19Z</date>

Each time a user logs in, Outset checks those user preferences. If a particular login-[privileged-]once item has already been processed for that user, it is skipped. However, you can add a Login-Once Override via a shell command to indicate that the item has changed and should be treated like a new item. The command looks something like this (using our previous example):

/usr/local/outset/outset --add-override /usr/local/outset/login-once/setDock.sh

That adds a timestamp for that item to the global Outset preferences ( /usr/local/outset/share/com.chilcote.outset.plist) using the same key/date pair format as in the user preferences. On subsequent user logins, Outset will compare the override timestamp for each item overridden with the last run timestamp for that particular user. If the override timestamp is newer, then the item will be processed again. (A more detailed explanation of Login-Once Overrides is available in the Outset wiki.)

Automating the Override

Your management system may provide you with a way to execute that shell command at the same time as you deploy the updated item to Outset, but the Outset wiki helpfully suggests another method: creating a postinstall script with the command and adding it to the package that delivers the item to Outset. This is a perfect task to automate. Since I already have an existing .pkg recipe that delivers the payload for Outset, I can add a couple of steps to it to incorporate a postinstall script. I’ve called the resulting recipe OutsetLoginOverridePkgReqd.pkg. Let me describe what I added.

Creating the scripts Directory

The PkgRootCreator processor creates the directory structure needed for your payload. However, you generally do not want the postinstall script to be in the same directory as the payload. The AutoPkg convention is to create a scripts folder at the same level in your AutoPkg cache as the payload. Invoking the PkgRootCreator a second time is the best way to accomplish this. So in my updated recipe, I do that just before invoking the PkgRootCreator for the payload itself.[2].

Creating the Login-Once Override

The other step to add for this recipe is to create the postinstall script. The FileCreator processor is perfect for this. You specify the text you want to include in the postinstall script using the file_content argument, which in this case is a shell script. Note that you can have a script that spans multiple lines, so it can be as simple or as complex as needed. In this case, I have three lines: a shebang, a documenting comment, and the Outset --add-override command. The FileCreator processor supports AutoPkg variable substitution, so that is how I pointed Outset to the item I am overriding:

/usr/local/outset/outset --add-override "/usr/local/outset/%ACTION_TYPE%/%name_with_ext%"

Using the earlier example, that would show up in the postinstall script as:

/usr/local/outset/outset --add-override "/usr/local/outset/login-once/setDock.sh"

I make certain the script is set to be executable by setting a file_mode of 0755 in the Arguments.

For the PkgCreator processor to add the postinstall script, I need to add the location of the script to the pkg_request dictionary using the scripts key.

<key>scripts</key>
<string>%RECIPE_CACHE_DIR%/scripts</string>

Finally, I added the scripts folder to the cleanup I do with PathDeleter after the package is built. We now have a recipe to create a package that delivers the Outset payload we want and triggers a Login-Once Override for it.

All the other steps from my previous post — creating the recipe override, adjusting the Input variables, optionally adding a PKG variable to the Input variables to point to a particular payload file — apply equally to this variation of the recipe.

Adding it to your Management System

The main reason I went down the path of creating a package for my Outset items was because Jamf Pro doesn’t natively support dropping a file in an arbitrary location on the managed system, but this method using AutoPkg creates a package that any management system can use. If your management system is Jamf Pro, then you probably already know that the JamfUploader family of AutoPkg processors can get this package into Jamf Pro, create/update a policy that deploys it, and even flush the log so that the payload will be delivered on next login. Since I describe how to build such recipes in detail in the recent presentations Graham Pugh and I have done, I won’t repeat those instructions here, but I have added the .jamf recipes I wrote for this purpose to my repo for you to use or peruse.

Adding a Login-Once Override is another great way to use Outset and automating the creation of a package that has a variable postinstall script is another one of the many ways AutoPkg can automate your workflows.


[1] Or do we call them ”settings“ now? [Return to main text]

[2] The PkgRootCreator processor establishes the value (path) for pkgroot, which is used by PkgCreator. In my recipe, I chose to create the paths to the payload second so that the pkgroot variable is set to what I want when I create the package. But I could also have set pkgroot to %RECIPE_CACHE_DIR%/payload in the pkg_request dictionary and not worried about which order I created the payload and scripts directory structures. [Return to main text]