I made something I call the NoMAD menu for macOS updates. It provides information about the status of a MDM scheduled update and the remaining number of allowed deferrals before the Mac force-installs a system update.
The recommended method by Apple or Jamf for mass updates with user deferrals is not clear as to why the MDM command often fails. It could be related to network issues, disk space, or even battery status. I’m aware of cool tools like Nudge or SUPER, which I have used in the past with great results! However, I find them a bit challenging to set up correctly, and they don’t work in conjunction with the MDM update command.
To address this, I came up with a solution ‘set once & forget it’ called the Scheduled Updates Menu Bar (SUMB). It’s essentially a plugin for the open-source app SwiftBar. There are no notifications to bother the users. Instead, think of it as a constant nudging in the toolbar with an ugly red countdown. Additionally, SUMB leverages the Jamf APIs and the target Macs have to be on macOS 12.3 or above.
SUMB is provided ‘AS IS’ and serves more as a proof of concept than anything else. I don’t plan to maintain it, so feel free to copy, modify, or share it with or without attribution—I don’t mind. My hope is that it will inspire someone to develop a real application based on this idea.
Download SwiftBar-1.5.0.pkg (or make your own pkg and install it in the /Applications folder) | SHA1 : 9209284d165554cf121f4670eaac515482a06bc0
Download SUMB-Plugin-1.01.pkg – Source code | SHA1 : 4088d0814ec49903ef2b5ffe48c260f4138ce635
Sorry, those are unsigned (right click > open to install them manually). You can take a look inside with Suspicious Package.
In ⚙️ > Packages, give SwiftBar-1.5.0.pkg higher Priority so that it installs before SUMB.
Create a Jamf Policy :
- Trigger : Check-in
- Frequency : Once per computer
- Payload : Packages
In ⚙️ > User accounts and groups : create an account named « jamf-api » with the bare minimum permissions. We only need to check READ for the Computers row.
In ⚙️ > Scripts : Add the script and edit it with your Jamf Pro URL, username (jamf-api) and password.
Create a Jamf Policy
- Trigger : Check-in
- Frequency : Once every day
- Payload : Scripts
Run the following command line on computers : osascript -e 'tell application "System Events" to make login item at end with properties {name: "SwiftBar",path:"/Applications/SwiftBar.app", hidden:false}'
For example, let’s consider Mary’s computer running macOS 13.3, and we intend to offer her 5 chances/days/deferrals to update it to macOS 13.5 at her convenience.
To begin, send an MDM update command with 5 deferrals. Action > Send Remote Commands > Update OS version > Download and allow macOS to install later : Max User Deferrals : 5
Wait something like 20 minutes and execute the SUMB-API policy on Mary’s computer (flush it if it has been run before). This script will generate an app.sumb.managedsoftwareupdate.plist file in the /Shared/sumb folder, which will contain the status of the update command. A countdown to 5 should appear in the menu bar. Then every day, the SUMB-API script will update the deferrals remaining number.
During my tests, sending an other MDM update command while the previous one is still in progress confuses the update and deferral processes. However, you can find a Cancel button in the Software Update pane.
![cancel-update](https://private-user-images.githubusercontent.com/53154185/255895215-71e3339e-b84b-4c9c-b805-d5ca4f84e699.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE5MzcxMTcsIm5iZiI6MTcyMTkzNjgxNywicGF0aCI6Ii81MzE1NDE4NS8yNTU4OTUyMTUtNzFlMzMzOWUtYjg0Yi00YzljLWI4MDUtZDVjYTRmODRlNjk5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA3MjUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNzI1VDE5NDY1N1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWVkYmM0MGUyNjk0OGFjODAzZDM0NWFhZmViMmNiYmJhOGM0MjcyNTZlNWQxYmVjNDk2OGVkNzFlYjhkZWMxM2EmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.Kf7DhwPH5UsTV7OQoMRIkveMz0I-22-rwO6zEMJhNfc)
Bellow, this is where the SUMB-API script reads the info from :