Blog

  • Steal This Idea

    check all your Macs at once with SOFA feed

    Note: this blog post relates to the previous one where I introduce the scripts to check SimpleMDM devices and compare with latest version info in the SOFA feed here: Use the SOFA feed to check if SimpleMDM devices needs updates

    Ok, please steal this idea. The idea? To check all your Macs at one time, instead of each device, on device, one at a time.

    What do I mean? Well, when I first heard about the SOFA feed which contained all the latest versions I didn’t know what to do with it honestly but soon after I realized that my clever script for checking XProtect version and which I made into a custom attribute in SimpleMDM and added to the dashboard was an incomplete idea.

    Ok, I’m smart, I got the XProtect version on each Mac by running a script and then I got SimpleMDM to display it in a dashboard. But what’s missing? Context. Is it the latest version or not? So I added a SOFA check to the script then made SimpleMDM display both the local version and the latest version so I’d know if it was the latest or not. Great, right? Well, maybe.

    The problem, I realized is that I wanted to do this for the macOS version too because I wanted to share info with a client/manager etc and realized the list of devices and info about macOS versions for example, lacked the context of whether it was the latest, and should we take action or not. That’s the point, right? collect info then do something about it, if action is required. Update your macOS now.

    And then I wondered why I’m getting every Mac to ask itself what is its macOS or XProtect version, etc, when SimpleMDM was asking a lot of those questions already and putting it in a dashboard, accessible via API….

    Then it happened, the idea that should be stolen by SimpleMDM and all other management tools. Don’t just display info about a Mac’s macOS version, show the latest version next to it, because I want to know if it should be updated. And also what is the latest that Mac can upgrade to. Maybe it’s running macOS 13.6, is that the latest or is 13.7.7, no wait it changed again, it’s 13.7.8. And by the way the latest compatible upgrade is 15.6.1, now that’s useful info.

    product_nameos_versionlatest_major_osneeds_updatelatest_compatible_oslatest_compatible_os_version
    Mac13,114.7.414.7.8yesSequoia 1515.6.1
    MacBookPro17,114.6.114.7.8yesSequoia 1515.6.1
    Mac13,215.615.6.1yesSequoia 1515.6.1
    iMac21,115.515.6.1yesSequoia 1515.6.1
    MacBookPro17,113.613.7.8yesSequoia 1515.6.1

    References:

    Check SimpleMDM device list and compare macOS version vs SOFA feed latest

    XProtect check version compared to latest SOFA

  • Use the SOFA feed to check if SimpleMDM devices needs updates

    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.

    The script is in my GitHub repo

    Fetching SimpleMDM device list...
    Downloading SOFA feed...
    ✅ Exported:
      → Full device CSV: /Users/Shared/simplemdm_devices_full_2025-07-30.csv
      → Outdated devices CSV: /Users/Shared/simplemdm_devices_needing_update_2025-07-30.csv
      → Supported macOS per model: /Users/Shared/simplemdm_supported_macos_models_2025-07-30.csv
    ✅ Export complete.
    

    References:

    SOFA MacAdmins Getting Started

    https://sofa.macadmins.io/getting-started.html

    https://github.com/macadmins/sofa/tree/main/tool-scripts

    SimpleMDM API docs

    https://api.simplemdm.com/v1#retrieve-one-dep-device

    squirke1977 / simpleMDM_API

    https://github.com/squirke1977/simpleMDM_API/blob/master/device_details.py

  • Dynamic Groups – SimpleMDM tricks and tips part2

    When we last left our hero the big news was the discovery custom attributes and running scripts to test for certain conditions in SimpleMDM, like “is the firewall on” to post in the main dashboard was all the excitement, this year we present “dynamic groups” which in combination with custom attributes or by itself ups the game to the next level. Keep up!

    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 json Note: 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à !

    Updated: May 16, 2025 – 19h00 local time

  • Good bye Rsync, hello open rsync

    So apparently I’ve missed the big story of Apple introducing BSD licensed open rsync in macOS 15 Sequoia back in the Fall of 2024. (Thanks to Rich Trouton’s recent blog post).

    Open Rysnc in macOS 15.4

    Openrsync it’s new. And I didn’t notice it, because I’ve been using a newer Apple silicon compiled rsync (see RSKgroup) because Apple hadn’t updated the included rsync 2.6.9 in decades and it was becoming a problem. It seems the big break of only shipping the newer openrsync happened in macOs 15.4 because until 15.4 Apple gave the option to use either the SAMBA or the new BSD licensed version with an environment variable.

    I use rsync a lot, for all my hand rolled artisanal backup scripts and the occasional push and sync between storage. Of course, for serious backups and archives I use Archiware P5 not the least because I need one dashboard to track backups, syncs, and archives, and more importantly I need to use LTO (tape backups) and Archiware is the best. As for useful terminal commands, rsync is often my go to for a lot of edge cases and quick storage comparisons.

    Apple’s open source GitHub for Rsync

    Open rsync was written by Kristaps Dzonsons in 2019 and is part of Open BSD but should run on all BSD or Linux distributions.

  • Firewall ch-ch-changes in macOS 15 Sequoia

    Knock knock

    “Who’s there?”

    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“)

    /usr/sbin/system_profiler SPFirewallDataType -detailLevel basic |grep Limit

    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.

  • SimpleMDM tricks and tips – part 1

    Custom Attributes

    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.

    Note: for more fun use cases see Steve Quirke’s blog post, or the talk “Making SimpleMDM complicated” by Lucas Hall at MacDevOps:YVR in 2021 or even the official documentation.

    The goal: 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.

  • “I love SQL” and other lies you tell yourself

    Navigating a database to get what you want, that is the goal. Do you love it? No, but you do need to do it? Yes, to get the data. Remember the goal.

    Many popular (and many lesser known) applications use SQL, and SQLite in particular, to store data. That’s fine. That’s great. But unfortunately on occasion you need to go spelunking to find data you want and get it out. This is not a blog post about how much I love SQL (structured query language), because I do not love it. This is also not a blog post about how SQL is awesome, because I can’t say that. But what I hope to share are some tips and tricks for getting in and out with the data you want.

    Use an app – DB Browser for SQLite

    https://sqlitebrowser.org/dl/

    If you’re not a fan of SQL and you’ve got a need for DB data then this app will let you open a database and explore. This is a great app because you can see the tables and what’s in the Db which will no doubt help you late explore in Terminal or in a script. I personally need a visual map sometimes before I jump in. Exploring the Db in this app will also show you the arcane commands necessary to do the same in Terminal. You will be in awe of whomever decided to create this complicated series of commands which makes long insane Unix commands seem logical in comparison.

    You can use DB Browser to export a csv (comma separated values) for a spreadsheet or as JSON (JavaScript Object Notation) which all the cool kids like these days. Better start loving this. More on JSON and APIs in a future blog post. Its not XML, but it makes you wish it was.

    Use Terminal – Type the commands by yourself

    In Terminal we can tell sqlite we want to export a csv file of everything. Add a header and tell it to be in csv mode then SELECT everything.

    sqlite> .header on

    sqlite> .mode csv

    sqlite> .output export.csv

    sqlite> .quit

    Export just some the data as a CSV

    sqlite3 /path/to/the/database.db
    SQLite version 3.40.1 2022-12-28 14:03:47
    Enter “.help” for usage hints.
    sqlite> .header on
    sqlite> .mode csv
    sqlite> .output JustTheSelectFieldsPlease.csv
    sqlite> SELECT label, timeDated, fancyList, sillyList, boringFiles, indexName FROM tableName;
    sqlite> .quit

    Automate and Make a Script

    #!/bin/bash
    sqlite3 /path/to/the/database.db <<EOF
    .header on
    .mode csv
    .output JustTheSelectFieldsPlease.csv
    SELECT label, timeDated, fancyList, sillyList, boringFiles, indexName FROM tableName;
    .quit
    EOF

    UPDATE: You must check out Datasette!

    After posting this I was reminded of an app called Datasette which is truly remarkable and awesome. It’s also a pip install thing but I’ve been using the standalone Mac app which has everything self-contained.

    With Datasette it’s easy to load SQLite DBs directly and filtering out the tables I want by easily set conditions, which makes exporting a workable JSON or CSV file quite easy in one step. There’s also a small and lightweight web app called Datasette Lite to make installing and running Datasette extremely simple. Datasette has plugins too. A lot. More to say on those in a later post.

  • Customizing MunkiReport: Dashboards

    I was chatting with Per Olofsson on a recent episode of the MacDevOps podcast about some recent fixes with relocatable Python he did for MunkiReport version 5.7.0 and I happened to mention how much I love my MR dashboards with custom hot keys. He is a long time user of MunkiReport but hadn’t heard that you could make custom dashboards and I couldn’t remember where I had heard of it or even how I made them. Pretty typical of tech these days I think. You learn something, you make something and then you move to the next thing and forget what you were doing or how you did it. Well, thanks to documentation we can share the knowledge and spread the love.

    Custom Dashboards

    The MunkiReport wiki actually has a short entry which explains how to make a custom Dashboards. Basically, add some YAML files in the dashboards folders and you’re done. Follow the Read Me file for instructions. Pro Tip: Use the Widget Gallery in MR to find useful pieces to build into your dashboards. Note: I’ve added these custom dashboards to my local folder which is set in my “.env” to be outside of the main munkireport folder so it easier to update across version upgrades.

    Here are four examples of MunkiReport dashboards:

    Security

    Munki

    Archiware P5

    The Archiware P5 dashboard references widgets from my custom P5 module. It’s easy to make modules for MunkiReport. Check the wiki for more info.

  • How To Securely Sync Your Synology NAS with P5

    Use Tailscale Mesh-VPN with P5 Backup and Sync

    In the old days we used to forward ports. On your router the traffic for a server or service went to a port (where a number represents a service, some which are defined, but can be arbitrary) and to a destination IP address. Well, wouldn’t you know it, if ssh is port 22 or web traffic is on port 80 then everyone and their port scanner comes knocking. So then your firewall is tested, and then auto-ban and geo-block and emails go out. What if we could avoid that and not open (or forward) any port to make services work across the internet?

    Tailscale is a mesh-VPN which uses WireGuard to securely establish a mesh (point to point) VPN of your devices. Suddenly your iPhone can securely send files to your Mac or raspberry Pi across the world. How cool is that? In today’s advanced lesson: you can backup and sync your Synology NAS using Archiware P5.

    Step 1: Setting up Tailscale on Synology

    It honestly used to be harder than this, these days you can simply add the Tailscale package via the Synology package center app and you’re done. Almost. There’s one more step.

    Step 2: Set up Outgoing VPN access via Tailscale which requires editing some files (which necessitate Terminal and remote login access). This only has to be done once but future updates may require fixes. This was tested in DSM 7. Pro tip: only allow remote access to a restricted and time limited account so you don’t leave it on accidentally.

    Step 3. Install Archiware P5 on Synology NAS

    Using Archiware P5 to Backup and Sync your NAS is a good thing if you’re already using Archiware P5 to backup and sync all the other things, then at least you have only one dashboard to look at. I use P5 with my clients to backup their shared storage to LTO and it makes sense to backup all the things no matter where they are with P5 also. With Synology NAS package center it’s a simple one-click install for P5. Add your P5 clients to your P5 server via Tailscale and you’ve got a secure setup.

    This post is just a quick overview of using Tailscale to set up your P5 clients (which is your Synology NAS in this case).

  • Munki makes MDM manageable

    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.

    Reference:

    SimpleMDM Munki integration blog post