I wrote a “simple” bash script to check SimpleMDM device list by API and check if any devices need updates and/or are compatible with the latest macOS. Of course, it will output some CSVs for fun and profit. Send to clients, managers, security professionals and be well.
Note: It was a quick hack and for reasons I made 3 output CSVs for testing various presentations of the data that combines the full SimpleMDM device list and matches the macOS with available updates and max supported versions. There may be errors or omissions. Please test. Use and modify. I know I will. This is a test. Just a test.
What if we wanted to know what is the current version of XProtect across the Mac fleet? and what if this wasn’t collected by default by MDM tool, in my case, SimpleMDM. Well, I can write a script to collect this info, for my purposes I’ve chosen to use silnite from Howard Oakley of eclectic light co fame and write the version number to a custom attribute. The next step is use SimpleMDM’s new dynamic groups (in preview, at the time of this blog post), and then I can watch the result filter in with a special group watching for “is matching this version” or the opposite “is not this version”. Just depends on what you want to act on or how you want to see the information. The new dynamic groups is the exciting part. I’m sooo excited.
The custom attribute
Screenshot
Setting up a custom attribute of “XProtectV: and a default value of “Version Unknown” should be done before the script runs. If I get the default result then the script didn’t run or some other reason.
The code
#!/bin/bash
LOG_DIR="/Users/Shared"
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
LOG_FILE="$LOG_DIR/silcheck-log-$DATE.txt"
/usr/local/bin/silnite aj > "/Users/Shared/silnite-xprotectv-$DATE.json"
XPROTECTV=$(/usr/bin/plutil -extract XProtectV raw "/Users/Shared/silnite-xprotectv-$DATE.json")
echo "$XPROTECTV" | tee -a "$LOG_FILE"
The simple script writes a log into /Users/Shared just because I want to and uses the silnite binary to write out the XProtect info and plutil to extract the info from the jsonNote: you could also use jq in latest macOS 15 but this way is more compatible across macOS versions for now. The XProtect version is saved as an attribute which SimpleMDM picks up and reports back to base.
The dynamic group
Screenshot
The filter headings are a little cut off in the screenshot but it basically says choose from all devices, refer to the custom attribute I set of XprotectV and makes sure the value equals the latest (at blog post writing) 5297 and further filter results for devices last seen in the last day. If I had switched it to the not equal to version 5297 I would see all the devices not up to date. And it’s easy to change on the fly. Easier than refreshing the main device dashboard page to see these results as I was trying to do previously and that method made it hard to further filter.
The exciting part
Yes the best part is to set up a job in SimpleMDM that runs the scripts on the devices to refresh the value of XProtect (I have it set to recurring as well) and then watch the results roll into a dynamic group which has its members populate as the scripts runs and results report back. Easey peasy.
Screenshot
Addendum:
Adding an example screenshot to show how you can change the filter from matches an exact value of XProtect, in this example, to “not equal to” to see all the devices that haven’t upgraded yet. It’s as easy as changing the filter and clicking on “staging filter changes” button. Et voilà !
macOS 15 Sequoia. Check your firewall checking scripts please
If anyone is following along with my attempt to re-create MunkiReport in SimpleMDM then you’ll be happy to know the space madness is still strong and macOS 15 has made one tiny thing break, my firewall checking script.
My firewall checking script began life as a simple check of the status in the alf pref file but that file no longer exists in macOS 15.
See this Knowledge base article which lists in bug fixes that the file no longer exists and that the socketfilterfw binary be used instead, except that doesn’t work when Macs are managed.
Application Firewall settings are no longer contained in a property list. If your app or workflow relies on changing Application Firewall settings by modifying /Library/Preferences/com.apple.alf.plist, then you need to make changes to use the socketfilterfw command line tool instead.
Yes, my Macs are managed with MDM and yes I have a profile to enable the firewall but no I don’t trust it so can I check please with another method. Trust but verify.
So thanks to some friends in the MacAdmins Slack I stole the idea from tuxudo to check firewall in macOS 15 using system profiler, because he had re-written the MunkiReport module already and so there I go again, stealing from MunkiReport and all the hard work they do.
After playing with the output of system_profiler a bit I looked at the “Mode”
/usr/sbin/system_profiler SPFirewallDataType -detailLevel basic |grep Mode
Mode: Allow all incoming connections
Stealth Mode: No
Of course I could write some nice code to clean this up or instead I switched to searching for “Limit” and if there’s no hit on that there’s no limit (translated: firewall is not enabled“)
And if there is a limit then the firewall is enabled.
Mode: Limit incoming connections to specific services and applications
Simple. Good enough to add to my SimpleMDM script to run and populate the value to the custom attribute and update my dashboard. And my crazy mission to build everything into SimpleMDM dashboard is still… madness …. but also quite fun.
Custom Attributes in SimpleMDM are a way to assign values in a few different cases. I will show one use case, scripting, and one example: checking the firewall.
I wanted to see the status of the macOS firewall in the device view dashboard. That’s so simple, right? Well, I wanted to see it at a glance for every device, and not have to go into each device entry to see if the firewall was enabled.
Write a script:
#!/bin/bash
# Check firewall status
firewall=$(defaults read /Library/Preferences/com.apple.alf globalstate)
if [ "$firewall" = "1" ]; then
echo "Firewall is enabled"
elif [ "$firewall" = "0" ]; then
# Set firewall status
#defaults write /Library/Preferences/com.apple.alf globalstate -int 0
echo "Firewall is NOT enabled"
else
echo "Unable to determine firewall status"
fi
Note: This is my script. This seems to work. If you have other working examples let me know.
Add it to SimpleMDM scripts
Add your script to the scripts section. Check the “Enable attribute support” check box.
Add a custom attribute
Set up a custom attribute that your script will populate with its variable later. I set up one for the firewall.
Create a job
Your script will need to run (once, or scheduled) to populate the value into the variable and into the custom attribute. Choose what script runs where on what Macs. And choose the custom attribute.
And choose the custom attribute.
Note: The cancel job if not started is helpful if your devices are not responding. And is a premonition to issues you may have with this feature and might give some flashbacks to the ancient way of using scripts in ARD (Apple Remote Desktop) to try to make changes, back in the days before MDM or good configuration management tools ie. munki puppet chef salt etc
Dashboard Devices
Add your custom attribute to the viewable columns in the Devices dashboard and your life will be full of joy. Seeing at a glance your scripts output variable as a custom attribute.
And now I just have to recreate everything in MunkiReport as a custom attribute and then I’ll be good.
Script debugging.
Running scripts is all well and good until your devices don’t check in and don’t run the scripts for whatever reason. Rebooting the Mac helps. Refreshing the inventory in SimpleMDM helps (maybe) and well, you’ll see it’s like the old ARD scripts run ad hoc and you’ll wish for better tools like fully functional DDM (declarative device management) which is like configuration management of the days of old. Incorporate MunkiReport and Fleet’s osquery tools and save me the trouble of doing piecemeal.
Enjoy the script output in the custom attributes for now and send me your awesome ideas for what to script next.
How to deploy applications using munki and simplemdm
You want to deploy apps to Macs but you also want to keep them up to date, fear not, we have a way. If you are using SimpleMDM for Mac management but hate the way MDMs deploy applications then listen up it’s easy(*) to set up Munki and use the power Autopkg to deploy and update all your apps. Note: SimpleMDM also offers a short list of curated apps to deploy without any extra setup but these instructions are for those who want to choose the apps they want to deploy. If that’s you then read on.
Managed Software Centre is the AppStore for all your apps you want your Macs to have
SimpleMDM: The basics
Macs are enrolled into SimpleMDM, then assigned to Groups. Groups have profiles assigned to them to enforce and escrow FileVault or set other policies. Simple enough, right?
Ok, what about apps?
SimpleMDM Category setting for a Munki’s Managed Software Centre
When you have apps in your Catalog you can assign a Munki category to the applications to make it show up in a nice group using Managed Software Centre (the client facing app).
With Apps in your Catalog you can manage them with Assignment Groups which are created as Munki (or not-Munki aka Standard). Next select Managed or Self-Serve, two concepts which make sense to Munki admins. One set of apps is required and will be installed without asking, and the other group is presented to the end user to choose as needed (they’re optional).
API key options. Allow Munki plugin access
API key
How do we get applications we want into SimpleMDM? Two ways exist. Import them manually and deploy via MDM or setup up Autopkg. For this we need the API key. Note: Only the munki plugin permissions are needed. Put the key into the Autopkgr.app SimpleMDM integration or set them as an environment variable and use autopkg in Terminal.
Autopkgr app choose autopkg recipes to use
Select recipes using Autopkgr (Linde Group) from the curated list of recipes created by IT Admins around the world or create your own recipes. What used to be a painstakingly difficult process by hand is now much easier with Recipe Robot by Elliot Jordan to help fish out the AppCast / Sparkle / Download URLs and transform into a nice autopkg recipe to be used by Munki (and ingested into SimpleMDM).
autopkg run -v Postlab.munki.recipe -k MUNKI_REPO_PLUGIN="SimpleMDMRepo" -k MUNKI_REPO="" -k extract_icon=True
MunkiImporter
Using API key provided by environment variable.
MunkiImporter: Using repo lib: MunkiLib
MunkiImporter: plugin: SimpleMDMRepo
Managed Software Centre notification
Managed Software Centre
Once Macs are enrolled and added to a SimpleMDM Group with the Munki assignment then the Managed Software Centre app will allow users to use the Self-Serve portal to install optional apps. Managed apps will install invisibly in the background.
The beauty of this integration is that Munki is awesome and works well. It is battle tested by many companies and organizations around the world. Using autopkg and its recipes to check for updates allows for a seamless automation of new apps into your catalog and then onto your fleet. Updated Macs are happy Macs.
Continuing our theme of welcoming our new macOS overlords, uh, I mean, blocking major macOS upgrades such as macOS 10.14 Mojave with AppBlock we shall examine some other methods of stopping the freight train known as Apple upgrades.
1) A smart person on the MacAdmins Slack posted a useful command to tell macOS not to download major upgrades.
blocks the installation of the Mojave notification package (at /Library/Bundles/OSXNotification.bundle).
However if it already installed, then it’s too late. They pushed out this command prior to that package being distributed by Apple, and they could subsequently see in install.log that the update is being found by softwareupdated but not being installed.
2) If you missed the chance to tell the Mac not to download major macOS upgrades then Rick Heil on his blog has detailed a way using munki to delete the bundle that triggers the macOS upgrade installer.
3) App Block
If your users are intent or their computers are all hell bent on downloading the install app then block it with App block detailed in my previously mentioned blog post
4) Warning
In an effort to get an early warning when users are about to upgrade I use Watchman Monitoring to send me an alert email when a Mac starts downloading the Install macOS app. Sometimes it’s enough of a warning to send an email to a user to ask them whether it is a good idea to upgrade at this time. If storage or software needed for production or backups aren’t qualified or tested thoroughly beforehand then upgrading in the early waves can be less than ideal and frought with peril.
In other interesting and related news, Victor (MicroMDM) was spelunking into the MDM Protocol for what prompts Macs like iOS devices to download major updates. Great post here
If you have any better ways to block macOS upgrades or want to contribute some great solutions let me know. Cheers
Apple’s DEP allows you to have new Macs (and old) quick added to your MDM. Signing up for the Device Enrolment Program allow you to use Mobile Device Management with your Macs and iOS devices.
You’ll need an email address that is not associated with an Apple ID and you’ll need your DUNS number among other things.