Mac admin'ing

Force-stopping the MunkiStatus progress bar at the login window

Sometimes, the MunkiStatus progress bar over the login window can get stuck, and pressing the Stop button can take a while to halt the progress bar completely.

To kill it immediately, press Cmd-Option-Shift-Escape (this is a slight modification of the usual force-quite key combination, which is Cmd-Option-Escape).

Full credit to Yehuda Bialik and Greg Neagle for this tip. The Wiki on Bootstrapping With Munki is now updated also to include a note this keyboard shortcut.

Mac admin'ing

Using AppleScript to install macOS software updates via System Preferences

Right now, this is a bit more of a proof-of-concept, but since /usr/sbin/softwareupdate has become increasingly unreliable in the past year for automating and enforcing Apple software updates, having a way to automate installing updates through the GUI on certain relatively unattended Macs is worth exploring. I’ve created a GitHub project for that called Sys Pref Software Updates (or spsu, for short).

Mac admin'ing

Fixing Jamf device signature error

Even though this Jamf Nation thread is five years old, as of this writing, it’s still got the solution to the Device Signature Error - A valid device signature is required to perform the action error message.

In my experience, the actual working solution is to run sudo jamf enroll -prompt and then enter credentials when prompted. Repeatedly running sudo jamf recon (even after a reboot) or sudo jamf policy doesn’t fix the issue, nor does verifying that the system clock time is correct.

Now why this comes up in the first place on a freshly factory-reset computer that DEP-enrolled in Jamf—who knows but Jamf?

Mac admin'ing

Running commands as a user when scripting for Munki or Jamf

Munki and Jamf run as root, so scripts they execute execute as root, not user.

One great way around this is to use Outset‘s login scripts (login-once, login-every), but sometimes you may have occasion to actually run a script immediately as the logged-in user.

Obviously, you’ll want to get the currently logged-in user into a variable you can use—several methods for that are described in How To: Get the currently logged in user, in a more Apple approved way—and you’ll want to watch out for the “logged in user” being _mbsetupuser, root, or just blank.

Then, you can use su to substitute a user identity:
/usr/bin/su -l "$loggedInUser" -c "commandyouwanttorunastheuser"

This is kind of a hack, so whether you’re using this as a postinstall_script in a Munki nopkg or a script that a Jamf policy is calling, you’ll definitely want to thoroughly test it to make sure it does what you want it to do

Mac admin'ing

Fix for custom user icons freezing up System Preferences

Even though there is some flexibility in terms of what sizes and resolutions you can use for custom user icons (to select for user pictures), if your icon’s resolution is way off, you may see a frozen blank, grey screen when trying to change the picture from that too-high-res picture to something else:

To get out of that, you’ll have to force-quit System Preferences, and then delete the picture manually with the terminal:
sudo dscl . delete /Users/username JPEGPhoto

The fix to prevent this from happening again is rather simple. Just make sure your image matches the size and pixels-per-inch that the macOS system user icons have:

Then, you should be able to select another image after your image is selected.

Mac admin'ing

Introduction to Nudge

What is Nudge?

In 2018, Erik Gomez created Nudge, which is open source and has nine other contributors as of this writing.

Part of the beauty of Nudge is its simplicity—it doesn’t actually install any updates itself (it does invoke the softwareupdate binary to check for or download Apple software updates, but it doesn’t actually install anything). That means if Apple changes how it does updates so as to make it particularly difficult for tools like Munki (yay!) or Jamf (eh…) to manage updates, you can just… nudge… users to install their updates via System Preferences.

How does it work?

There is a launch agent that checks to see if your major OS is up to date (e.g., 10.15) or if your minor OS is up to date (e.g., 10.15.2 build 19C57). It will pop up a window if the OS isn’t “up to date” (however you define it), and get more aggressive as the cut-off date (something you also define) gets closer (or has passed).

You build it with munkipkg, though I’d recommend distributing separately from the package both the nudge.json (renamed from example_config.json) and the update_ss.png image. The former you can even host online (not on the user’s machine), but both you may want to update from time to time, even if the rest of the Nudge package (including scripts, launch agent, your company logo) stay the same.

The Nudge script will check to see if the major OS and/or minor OS/build are/is up to date, and, if not, nudge the user to install the updates.

What does this look like to the user

Every half hour, the user will get a window that appears over whatever she is working on, and the window isn’t moveable and can’t be closed with a red X button.

Initially, there will be a Close button readily available.

With the default timer settings, the window will come back to the front once every 4 hours.

Once it’s within three days of the cut-off date, the user will have to click I understand in order to get the Close button to appear.

Then, the user is okay to click the Close button. Of course, your hope is that the user will just click Update Machine instead to actually get the machine to update instead of just dismissing the dialogue.

With the default timer settings, the window will come back to the front once every 2 hours.

The same click-I-understand-before-you-click-close-but-really-please-just-update-your-machine routine shows up, too, when there is only one day left.

With the default timer settings, the window will come back to the front once every 10 minutes.

If the cut-off date is within an hour or if it’s passed already, there is no option to close or say you understand. You can’t dismiss the window.

With the default timer settings, within an hour of the cut-off date, the window will be brought back to the foreground every 1 minute.

And with the default timer settings, when the cut-off date has passed, the window will be brought back to the foreground every 10 seconds.

What can you configure via the .json file?

I’m a huge fan of Munki, but one downside to using Munki to install Apple software updates is you can’t really add a preupgrade_alert for a non-optional item, which means you can’t really alert users that, say, a particular Apple software update may have the screen turn black for a full minute.

With Nudge, you can configure pretty much any of the text using the .json file.

You can also have the Update Machine button go wherever you’d like it to go. You can even have it invoke Munki or Jamf.

If you don’t want it to invoke up Munki or Jamf, or to launch up a pre-downloaded update or upgrade installer, you can also have this in your .json file:
"path_to_app": "/System/Library/PreferencePanes/SoftwareUpdate.prefPane",
so it just launches up System Preferences > Software Update, so the user can install updates via the “Apple sanctioned” way.

If you don’t want to bother the user every half hour, you can set the days_between_notifications preference. This goes by actual day and not necessarily a full 24 hours. For example, if the user was notified Thursday afternoon and dismissed the Nudge notification, she may see the notification again on Friday morning (since Friday is the next day after Thursday).

You can also adjust the timer settings to be more or less aggressive with how quickly the open window will be brought back to the foreground.

What else is there about Nudge?

This blog post isn’t intended to be a comprehensive Nudge handbook—just an introduction to Nudge.

You can (and should), of course, read the Nudge README.

I’d also highly recommend just reading the actual Nudge code, since it gives you a sense of the sequence of things and how it all works (especially if you read the comments in the code).

Finally, check out the #nudge channel on the MacAdmins Slack if you have any questions about how to use Nudge.

Mac admin'ing

Forcing updates to Google Chrome using Chrome preferences / a Chrome profile

Why use Chrome relaunch notification instead of Munki

I’m a huge fan of using Munki to patch software on macOS, but Munki is generally polite—it usually won’t kill an application while the user is using it. There is an option in Munki to force an install after a certain date, but that will log the user out of her computer completely in order to install whatever item you set as a forced install.

The actual preferences for Chrome relaunch notification

If you want to just have Chrome update to the latest version without logging out the user, but you want to force that to happen (say, if there’s a fairly serious zero-day security vulnerability), you can use Chrome preferences to do so:

defaults write RelaunchNotification -int 2

defaults write RelaunchNotificationPeriod -int 3600000

The first command forces a relaunch instead of just recommending one. The second one gives the period of time (in milliseconds) the user has before the relaunch happens.

Using a profile instead of commands to manage the preferences

Those commands probably aren’t something you want to run at scale. You’d want to use that as a quick test, and then you could deploy those settings as a .mobileconfig profile, which you can use mcxToProfile to do. You can also apparently use ProfileCreator to do so as well (using ProfileManifests), but I haven’t fully explored that yet. And, if you’re a Jamf user, you can use plutil -convert xml1 to use custom settings for a Jamf-created profile.

Deploy (and undeploy) thoughtfully

I’m going to give a major caveat that, unless you want to perpetually annoy your users, you probably don’t want to have this profile installed all the time, because it means every single time there’s a Chrome update (and Google does update Chrome quite frequently), your users will have only an hour (or whatever time period you set for RelaunchNotificationPeriod) to relaunch Chrome. Not all Chrome updates are immediately critical, so use this obnoxious “you must relaunch” Chrome policy judiciously.

What your users will see

This is the type of warning users will see:

Will users lose their open tabs?

I can’t say definitively, because the functionality may change in the future, but as of the writing of this blog post (late November, 2019), even if users have not set Continue where you left off, this forced relaunch will, in fact, re-open the tabs that were open before:

Um, test for yourself, obviously. You don’t want to have a bunch of angry users. You could, alternatively, have your .mobileconfig profile manage the RestoreOnStartup preference.

What’s the actual user experience like for the restart?

In my testing, it seems the 6-minute warning is the last one you can dismiss, and then when it’s ready to relaunch to install the update, Chrome gives absolutely no notification that the relaunch is happening when it happens. Chrome just closes out and then relaunches.

Further reading

More details at Google’s Notify users to restart to apply pending updates.

Even more technical details at Chrome Enterprise policy list.

Mac admin'ing

Setting up Reposado without downloading Apple update pkgs

Reposado allows you to set up your own local repo of Apple software updates. This can be handy if you want to control the flow of updates (having a testing branch, for example, and then promoting items from testing to production).

With Apple deprecating custom catalog URLs in Catalina (they still work for now, though), you may not want to actually create a full Reposado repo. Maybe you just want a way to check for product keys without replicating the entire repo, including pkgs.

It’s fairly simple to do this:

git clone
sudo mkdir -p /usr/local/reposado
sudo cp -R reposado/code/* /usr/local/reposado/
sudo mkdir -p /Library/Application\ Support/reposado/html
sudo mkdir -p /Library/Application\ Support/reposado/metadata

This is the key part, when you go to configure Reposado, you want the Base URL to be blank:

sudo /usr/local/reposado/repoutil --configure
Filesystem path to store replicated catalogs and updates [/Library/Application\ Support/reposado/html]: /Library/Application Support/reposado/html

Filesystem path to store Reposado metadata [/Library/Application\ Support/reposado/metadata]: /Library/Application Support/reposado/metadata

Base URL for your local Software Update Service
(Example: -- leave empty if you are not replicating updates) []:

Then, you can run

sudo /usr/local/reposado/repo_sync

and the total download should be only about 150 MB (as opposed to hundreds of GB if you were to download all the pkgs as well).

Mac admin'ing

Munki hack: force uninstall after a certain date

Munki has an option to force install by a certain date (specifically, using the force_install_after_date key), but it doesn’t do a force uninstall after a certain date.

You can make an item a managed uninstall, which means Munki will uninstall it when possible, but if that requires a logout or reboot, you don’t know when that might happen.

So to force an uninstall after a certain date, there’s a messy hack you can employ, which is to create an uninstall nopkg.

So, for example, if you want to force remove item X, you would have, of course, an item X in your repo, but you would then create a nopkg item for uninstall-X, which, when “installed” would uninstall X.

Now, this can be a bit tricky, because Munki has built-in logic for how it does its installs. For example, let’s say item X had a relationship with item Y, where item Y is an update for X. If you use Munki’s built-in installation logic to make item X a managed uninstall, Munki would know to remove item Y as well. But if you create a separate nopkg that just runs some script to remove item X, the nopkg doesn’t also necessarily know item Y is an update for item X.

Likewise, if you have item X as a managed install as well, you could have Munki fighting with itself, since it will try to install item X but also (via your hacky nopkg) install item uninstall-X. (In ordinary circumstances, make an item both a managed install and a managed uninstall would usually have Munki just keep it installed.)

But if you are careful with how you construct things, this can definitely work. I wouldn’t recommend it (better to just let managed uninstalls do its job), but if you absolutely need to remove a certain piece of software by a certain date, this can do it.

Another potential hack is to have item Z force install by that same date, and then make item X a regular managed uninstall, and when users are forced to install item Z, item X will uninstall at the same time.

Mac admin'ing

Using Munki to ignore Catalina upgrade in macOS

Apple used to make you go out of your way to download an OS upgrade. Then, Apple started having those OS upgrade installers auto-download to the /Applications folder. Then Apple made it so OS upgrades appeared as regular updates.

For Mac admins who aren’t ready to have their clients upgrade to Catalina (and potentially have a lot of things break), there is a way to tell the client machine to ignore the update and thus not advertise it to the user.

For those who are Munki admins, I’ve created a nopkg that will allow you to “install” ignoring the Catalina upgrade (but you can easily tweak the script to ignore any update) and also “uninstall” ignoring the Catalina upgrade (or any update).

Note: If you “ignore” Catalina, you can still find it in the Mac App Store, but if you try to install it, it will open up System Preferences and say it can’t be found. So “ignoring” actually means “disabling.” That doesn’t stop you from using Munki to install an upgrade, though.