Category: Documentation

  • Community Projects: Part 2

    DiskEncrypter – a shared shell script helps the world

    A Community Code Evolution Story: From Simple Utility to Security Tool

    Introduction

    What started as a straightforward 515-line bash script in October 2022 has evolved into a, uh, slightly more complicated, 1,125-line “enterprise-grade” encryption enforcement system.

    This is the story of how a simple external drive encryption script was shared with the community and provided a starting point for others to create their own “enhanced” utility which can now be one piece of a security solution that protects users from data loss, encourages users to encrypt external drives, and provides a framework to enforce an encryption policy.

    This DiskEncrypter_Enhanced.sh script is also a journey that spans nine major versions, each addressing real-world problems discovered through testing and user feedback. Along the way, I learned valuable lessons about user experience, data safety, and the importance of preventing accidental data loss—especially when it comes to irreplaceable photos and videos on camera cards.

    Chapter 1: The Beginning – DiskEncrypter.sh v1.0 (October 2022)

    The Original Vision

    Created by Thijs Xhaflaire, the original `DiskEncrypter.sh`script had a clear mission: automatically detect unencrypted external drives and prompt users to encrypt them. It was designed for macOS enterprise environments where data security compliance required all removable media to be encrypted.

    What It Did Well

    The original script handled the basics competently:

    – Detected external APFS, HFS+, and ExFAT/FAT volumes

    – Prompted users with a swiftDialog interface

    – Encrypted APFS volumes directly

    – Converted HFS+ volumes to APFS before encryption

    – Erased and reformatted ExFAT/FAT volumes as encrypted APFS

    – Offered a “mount as read-only” option for users who didn’t want encryption

    The Hidden Limitations

    But as deployments grew, limitations became apparent:

    1. Single-Volume Processing**

    If you inserted a disk with three partitions, the script would only process the first one. The other two? Invisible to the system.

    “`bash

    Original approach

    if [[ $StorageType =~ “Apple_APFS” ]]; then

        # Process APFS

    elif [[ $StorageType =~ “Apple_HFS” ]]; then

        # Process HFS+

    elif [[ $StorageType =~ “Microsoft Basic Data” ]]; then

        # Process ExFAT

    fi

    Only ONE branch executed, then script exits!

    “`

    2. No Logging Infrastructure**

    Troubleshooting was a nightmare. Basic `echo` statements went nowhere when run as a LaunchDaemon.

    3. No Testing Capability

    Want to test the script? Hope you don’t mind encrypting real drives, because there was no dry-run mode.

    4. Generic Error Messages

    “FileVault is disabled on disk4s1” – Great, but which drive is that? What’s it called?

    5. The Re-Prompt Problem

    User mounts a drive as read-only. Five minutes later, they insert another drive. The script triggers again and asks about BOTH drives, including the one already mounted read-only. Every. Single. Time.

    Chapter 2: The First Major Overhaul – v2.0 Enhanced (December 2025)

    ### Modernization for macOS 15+ Sequoia

    When macOS 15 (Sequoia) shipped, several compatibility issues emerged. This sparked a complete reimagining of the script’s architecture.

    ### The Two-Phase Architecture

    The biggest change was moving from a linear “process-and-exit” model to a sophisticated two-phase system:

    **Phase 1: Discovery**

    “`bash

    # Scan ALL drives

    # Detect ALL partitions

    # Check ALL volume types independently

    # Build a queue of unencrypted volumes

    “`

    **Phase 2: Processing**

    “`bash

    # Process each queued volume sequentially

    # Track what was encrypted

    # Show comprehensive summary at end

    “`

    This solved the multi-volume problem instantly. Now a disk with three APFS volumes, two HFS+ partitions, and an ExFAT partition would have ALL of them discovered and processed.

    ### The Multi-Volume Victory

    Here’s a real example of the difference:

    **Original v1.0 (Single partition found):**

    “`

    Processing /dev/disk4

    Found: disk4s1 (APFS volume “Old”)

    Encrypted: disk4s1

    Exit.

    “`

    **Enhanced v2.0 (All partitions found):**

    “`

    Discovery Phase:

    – disk29s1 “Old” (APFS, unencrypted) → Added to queue

    – disk29s2 “New” (APFS, unencrypted) → Added to queue

    – disk29s3 “Lucky” (APFS, unencrypted) → Added to queue

    – disk28s3 “Untitled 2” (HFS+, unencrypted) → Added to queue

    Processing Phase:

    [1/4] Encrypting “Old” (disk29s1)… Done

    [2/4] Encrypting “New” (disk29s2)… Done

    [3/4] Encrypting “Lucky” (disk29s3)… Done

    [4/4] Converting and encrypting “Untitled 2” (disk28s3)… Done

    Summary: 4 volumes encrypted in this session

    “`

    Volume Names Everywhere

    Every dialog, every log message, every notification now showed friendly volume names alongside technical IDs:

    “`

    Before:”Processing disk4s1″

    After:”Processing ‘MyBackups’ (disk4s1)”

    “`

    Users could finally understand what was happening to which drive.

    The LaunchDaemon Dialog Fix

    A critical bug emerged: when run as a LaunchDaemon (root), swiftDialog couldn’t accept keyboard input. Password fields were useless. The fix used `launchctl asuser` to run dialogs in the user’s GUI session context:

    Now dialogs appeared correctly with proper focus and keyboard interaction.

    Chapter 3: Production Readiness – v2.1 (December 2025)

    ### The Logging Revolution

    v2.1 introduced a professional four-level logging system:

    | Level | Output | Use Case |

    |——-|——–|———-|

    | **0 – Minimal** | Errors only | Production (silent success) |

    | **1 – Normal** | Errors + key operations | Standard deployment |

    | **2 – Verbose** | + detailed progress | Troubleshooting |

    | **3 – Debug** | Everything | Development/diagnosis |

    **Dual-destination logging** sent output to both console and macOS unified logging:

    “`bash

    log_info() {

        if [[ $LOG_LEVEL -ge 1 ]]; then

            echo “[$(get_timestamp)] INFO: $*”

            logger -p user.info “DiskEncrypter [INFO]: $*”

        fi

    }

    “`

    Now you could watch logs in real-time:

    “`bash

    log stream –predicate ‘eventMessage CONTAINS[c] “DiskEncrypter”‘ –info

    “`

    ### Dry-Run Mode: Test Without Fear

    “`bash

    sudo ./DiskEncrypter_Enhanced.sh –dry-run –log-level 3

    “`

    This became invaluable for:

    – Testing in production environments

    – Training new IT staff

    – Validating configuration changes

    – Demonstrations

    Every disk operation was logged but not executed:

    “`

    [DRY RUN] Would execute: diskutil apfs encryptVolume disk4s1 -user disk

    INFO: DRY RUN: Encryption would start for disk4s1

    “`

    ### Command-Line Arguments

    For the first time, you could override plist settings from the command line:

    “`bash

    # Debug logging without changing plist

    ./DiskEncrypter_Enhanced.sh -l 3

    # Dry-run with verbose logging

    ./DiskEncrypter_Enhanced.sh –dry-run -l 2

    “`

    Priority: **Command-line → Plist → Default**

    Chapter 4: The Bug Hunt – v2.2 (December 2025)

    ### The Critical Read-Only Bug

    A critical bug was discovered: the script couldn’t detect read-only volumes, causing users to be re-prompted endlessly.

    **The Bug:**

    “`bash

    # Wrong field name!

    volumeMountInfo=$(diskutil info “$VolumeID” | grep “Read-Only Volume:”)

    if [[ “$volumeMountInfo” == “Yes” ]]; then

        # This NEVER executed!

    fi

    “`

    **Why It Failed:**

    “`bash

    $ diskutil info disk4s2 | grep “Read-Only Volume:”

    # (no output – field doesn’t exist!)

    $ diskutil info disk4s2 | grep “Volume Read-Only:”

       Volume Read-Only:          Yes (read-only mount flag set)

    # ^^^ The actual field name!

    “`

    **The Fix:**

    “`bash

    volumeMountInfo=$(diskutil info “$VolumeID” | grep “Volume Read-Only:”)

    if [[ “$volumeMountInfo” =~ ^Yes ]]; then

        log_info “Volume $VolumeID ($volumeName) is mounted read-only, skipping”

        continue

    fi

    “`

    This simple fix eliminated the annoying re-prompt problem.

    ### NTFS Support Added

    Windows NTFS volumes were now recognized and handled:

    “`bash

    if [[ $StorageInfo =~ “Microsoft Basic Data” ]] ||

       [[ $StorageInfo =~ “Windows_FAT” ]] ||

       [[ $StorageInfo =~ “DOS_FAT” ]] ||

       [[ $StorageInfo =~ “Windows_NTFS” ]]; then  # NEW!

    “`

    Chapter 5: The Safety Revolution – v2.3 (December 2025)

    ### The Security Gap

    A realization hit: unencrypted drives were mounted read/write while waiting for user decision. This created a window where data could accidentally be written to unencrypted media.

    ### Auto Read-Only Mounting

    v2.3’s solution was elegant: automatically mount ALL unencrypted volumes as read-only immediately upon detection, before showing any dialog.

    **New Function:**

    “`bash

    mountReadOnly() {

        local VolumeID=$1

        local volumeName=$2

        log_info “Auto-mounting volume as read-only: $VolumeID ($volumeName)”

        # Unmount first

        diskutil unmountDisk “$VolumeID” 2>/dev/null

        # Mount as read-only

        diskutil mount readOnly “$VolumeID”

        return 0

    }

    “`

    **Updated Workflow:**

    “`

    v2.2:

    1. Drive detected → Mounted read/write ⚠️

    2. Dialog shown

    3. If “Mount read-only” → Remount

    v2.3:

    1. Drive detected → Auto-mounted read-only ✅

    2. Dialog shown (drive already safe)

    3. If “Keep Read-Only” → Already done!

    “`

    ### Updated User Messages

    Dialogs now explicitly stated the protection status:

    “`

    This volume has been mounted as read-only for your protection.

    To write files, you must encrypt the disk.

    “`

    Button labels changed:

    – **Before:** “Mount as read-only”

    – **After:** “Keep Read-Only” (more accurate)

    ### Comprehensive User Documentation

    v2.3 introduced `USER_GUIDE.md`, a 22KB end-user safety manual with:

    – Clear explanation of the three button options

    – Decision guide chart by drive type

    – Step-by-step backup workflows

    – Critical warnings for ExFAT/FAT32 (data loss risk)

    – Password management best practices

    **Example Safe Workflow:**

    “`

    WRONG:

    ❌ Insert ExFAT drive with photos → Click “Encrypt” → ALL PHOTOS DELETED

    CORRECT:

    ✅ Click “Keep Read-Only”

    ✅ Copy all photos to Mac

    ✅ Verify photos copied correctly

    ✅ Eject drive

    ✅ Re-insert drive

    ✅ NOW click “Encrypt”

    ✅ Photos safe on Mac, drive encrypted

    “`

    Chapter 6: The Camera Card Protection – v2.4 (December 2025)

    ### The Data Loss Catastrophe Waiting to Happen

    v2.3 was safer, but a critical vulnerability remained: users could still choose to “Erase and Encrypt” ExFAT/FAT32 drives, which contained camera cards with irreplaceable wedding photos, vacation videos, and professional photography.

    **The Risk Scenario:**

    “`

    1. Wedding photographer inserts SD card (ExFAT) with 500 photos

    2. Dialog appears: “Erase and Encrypt” option available

    3. Photographer thinks “encrypt” = “protect my photos”

    4. Clicks button, enters password

    5. ❌ ALL 500 WEDDING PHOTOS DELETED FOREVER

    “`

    This was a bad situation waiting to happen.

    ### The Bold Decision: Remove the Erase Option

    v2.4 made a controversial choice: **completely remove the encrypt option for ExFAT/FAT/NTFS volumes.**

    This volume cannot be encrypted without erasing all data.

    To protect your data from accidental loss, encryption is not

    offered for this disk type (ExFAT/FAT/NTFS).

    Why encryption is not offered:

    • Encrypting this volume type requires complete erasure

    • All existing data would be permanently lost

    • This protection prevents accidental data loss on camera cards,

      USB drives, and other portable media

    To encrypt this drive:

    1. Back up all data to a secure location

    2. Use Disk Utility to erase and format as APFS

    3. Then encryption can be applied without data loss”

    <

    Chapter 7: The UX Polish – v2.4.1 (December 2025)

    ### The Scrolling Problem

    v2.4’s dialogs had too much text—users had to scroll to see everything. This defeated the purpose of clear communication.

    **The Problem:**

    “`

    Main Dialog:

    [15+ lines of text explaining everything]

            ▼ SCROLL REQUIRED ▼

    “`

    ### The Infobox Solution

    v2.4.1 leveraged swiftDialog’s `–infobox` parameter to split content:

    “`bash

    # Concise main message (5 lines)

    customMessage=”Non-encryptable volume: **\”$volumeName\”** ($VolumeID)

    File System: **$fsType**

    $subTitleNonEncryptable”

    # Detailed infobox (collapsible)

    infoboxMessage=”### Why Encryption Is Not Offered

    • Encrypting this volume type requires **complete erasure**

    • All existing data would be **permanently lost**

    • This protection prevents accidental data loss

    ### To Encrypt This Drive (If Needed)

    **Step 1:** Back up all data to a secure location

    **Step 2:** Open Disk Utility and erase the drive

    **Step 3:** Format as **APFS** (Mac only)

    **Step 4:** Re-insert for automatic encryption

    ⚠️ **Warning:** Only proceed if you have backed up all data!”

    Chapter 8: The Feedback Loop Fix – v2.4.3

    ### The Duplicate Dialog Bug

    Just when everything seemed perfect, a new bug emerged in production:

    **The Problem:**

    “`

    1. User inserts USB drive

    2. Script displays dialog

    3. User clicks “Eject”

    4. Script executes: diskutil unmountDisk disk4

    5. ❌ Unmount event triggers LaunchDaemon AGAIN

    6. ❌ Script runs concurrently with first instance

    7. ❌ Dialog appears TWICE

    8. ❌ User must click “Eject” again

    “`

    The LaunchDaemon was monitoring both mount AND unmount events, creating a feedback loop.

    The Two-Pronged Solution

    v2.4.3 implemented two complementary mechanisms:

    **1. Lock File Mechanism (Prevents concurrent execution)**

    “`bash

    LOCK_FILE=”/var/run/diskencrypter.lock”

    **2. Processed Volumes Tracking (Prevents re-processing)**

    “`bash

    PROCESSED_VOLUMES_FILE=”/var/tmp/diskencrypter_processed.txt”

    COOLDOWN_SECONDS=30

    Chapter 9: The Spaces In Between – v2.4.5

    A few more big fixes happened in v2.4.4 and v2.4.5 which addresses spaces not allowed in the password field and the password hint field and suffice it to say that regex was the issue. And testing was required. And a second fix for the first fix when the installer was discovered to be setting an old default in the management preferences. Ooops!

    Chapter 10: Lessons Learned

    ### 1. Users Don’t Understand Technical Terms

    “Erase and encrypt” sounds like “protect my data” to non-technical users. The v2.4 solution of removing the option entirely was controversial but necessary.

    **Key Learning:** When data loss is possible, don’t rely on warnings—remove the dangerous option.

    ### 2. Edge Cases Are Real Cases

    The read-only field name bug (v2.2) seemed minor until users reported constant re-prompts. The duplicate dialog bug (v2.4.3) only appeared in production when LaunchDaemon unmount events triggered re-execution.

    **Key Learning:** Real-world testing reveals issues that synthetic tests miss.

    ### 3. Good UX Is Iterative

    v2.4’s dialogs had too much text. v2.4.1’s infobox solution reduced reading time by 66%. Sometimes the best improvement is reduction, not addition.

    **Key Learning:** Watch real users interact with your interface. Simplify ruthlessly.

    ### 4. Logging Saves Lives (and Debugging Time)

    The v2.1 four-level logging system with dual output (console + system logger) paid dividends in every subsequent version. Debug output that would have taken hours to add per-bug was already there.

    **Key Learning:** Invest in logging infrastructure early. Future you will thank present you.

    ### 5. Backward Compatibility Matters

    Every version maintained 100% backward compatibility with configuration files and user workflows. APFS/HFS+ encryption worked identically across all versions.

    **Key Learning:** Add features, don’t break existing deployments.

    ### 6. Concurrent Execution Is Harder Than It Looks

    The feedback loop bug (v2.4.3) required two complementary solutions: lock files for mutual exclusion AND processed volume tracking for cooldowns.

    **Key Learning:** Concurrent execution requires multiple layers of protection.

    Chapter 11: The Final Product

    ### What Disk Encrypter Enhanced v2.4.5 Delivers

    **For IT Administrators:**

    – Comprehensive logging with 4 verbosity levels

    – Dry-run mode for safe testing

    – Command-line arguments for flexibility

    – Automatic log rotation (30-day retention)

    – Lock file protection against race conditions

    – Processed volume tracking with configurable cooldown

    **For End Users:**

    – Auto read-only mounting (immediate protection)

    – Clear, friendly volume names in all dialogs

    – No risk of accidental data loss on camera cards

    – Clean, professional dialog layout (no scrolling)

    – One dialog per user decision (no duplicates)

    – Educational content explaining technical concepts

    **For Compliance Officers:**

    – Complete audit trail in system logs

    – Encryption enforcement for compatible volumes

    – Safe handling of non-compatible media

    – User acknowledgment tracking

    – Session-based encryption reporting

    Chapter 12: Looking Forward

    ### What’s Next?

    The evolution from v1.0 to v2.4.5 represents maturity, but there’s always room for improvement:

    **Potential Future Enhancements:**

    – Web-based dashboard for monitoring encryption across enterprise

    – Centralized reporting to MDM systems

    – Email notifications for IT admins

    – Custom encryption policies per volume type

    – Integration with company password managers

    – Support for FileVault-encrypted APFS containers on external drives

    ### The Philosophy Going Forward

    The journey from v1.0 to v2.4.5 taught us three guiding principles:

    1. **User safety over feature completeness** – Removing the ExFAT erase option protected users from themselves

    2. **Comprehensive logging over simplicity** – The debugging investment paid dividends

    3. **Iterative refinement over big-bang releases** – Each version solved real problems discovered in the field

    ## Conclusion

    What started as a 515-line utility script in October 2022 has evolved into a 1,325-line enterprise-grade security solution. Along the way, we learned that good software is never “done”—it evolves through real-world use, user feedback, and a commitment to continuous improvement.

    The DiskEncrypter journey demonstrates that the best solutions emerge from:

    – Listening to users (the read-only re-prompt problem)

    – Protecting users from themselves (the camera card protection)

    – Obsessive attention to detail (the dialog UX refinement)

    – Comprehensive testing (the feedback loop bug discovery)

    Today, DiskEncrypter_Enhanced.sh v2.4.5 stands as a cautionary tale to what iterative refinement can achieve: a tool that not only enforces security policy but actively prevents data loss, provides excellent user experience, and operates reliably in production environments.

    The code journey continues.

    **Technical Stats:**

    – **Total Development Time:** ~12 days of Xmas coding (December 3-15, 2025)

    – **Lines of Code:** 515 → 1,125 (+157%)

    – **Functions:** 2 → 25+ (+1,150%)

    – **Major Versions:** 9 (v2.0, v2.1, v2.2, v2.3, v2.4, v2.4.1, v2.4.3, v2.4.4, v2.4.5)

    – **Bug Fixes:** 4 critical issues resolved

    – **Compatibility:** macOS 15+ (Sequoia) and macOS 26+

    **Documentation:**

    – Evolution Guide: 1,844 lines

    – User Guide: 650+ lines

    **Acknowledgments:**

    – Original script by Thijs Xhaflaire (October 2022)

    swiftDialog by Bart Reardon

    – Testing and feedback from the MacAdmin community

    **License:**

    The DiskEncrypter_Enhanced.sh script is distributed for enterprise use. See individual script files for license details.

  • Community Projects: Part 1

    SetDefaultAppsX – A Community-Driven Evolution

    From Enterprise Lock-In to Universal macOS Tool

    When Scott Kendall released his SetDefaultApps script in December 2025, it solved a real problem: giving users a friendly GUI with swiftDialog to set their default applications using scriptingOSX’s utiluti for file types, URLs, and protocols on macOS. It worked beautifully—but only if you had Jamf Pro.

    That’s where the community stepped in.

    The MDM-specific Problem

    Scott’s original script was tightly coupled to Jamf Pro’s infrastructure. It relied on policy triggers for installing dependencies:


    jamf policy -trigger install_SwiftDialog
    jamf policy -trigger install_SymFiles
    jamf policy -trigger install_utiluti

    For enterprise Mac administrators already using Jamf, this was perfect. For everyone else—small businesses, education labs, home users, or shops using different MDM solutions—it was a non-starter.

    The X Factor: SetDefaultAppsX

    I took Scott’s excellent foundation and worked to make it a truly standalone tool. The “X” represents both the removal of dependencies and the cross-platform (MDM-agnostic) nature of the new version.

    Major Transformations

    1. Self-Contained Installation

    Instead of calling out to Jamf policies, SetDefaultAppsX now downloads swiftDialog directly from GitHub, verifies the package signature against Bart Reardon’s Team ID, and installs it automatically:


    expectedDialogTeamID="PWA5E9TQ59"
    LOCATION=$(curl -s https://api.github.com/repos/bartreardon/swiftDialog/releases/latest | awk -F '"' '/browser_download_url/ {print $4}')
    curl -L "$LOCATION" -o /tmp/swiftDialog.pkg
    # Verify signature before installation
    teamID=$(/usr/sbin/spctl -a -vv -t install "/tmp/swiftDialog.pkg" 2>&1 | awk '/origin=/ {print $NF}' | tr -d '()')

    No MDM required. No manual downloads. Just works.

    (Real time update: Writing this blog post made me add a feature to do the same with ScriptingOSX’s utiluti. Now the script checks and downloads both.)

    2. Hardware Detection That Actually Works

    Scott’s original used system_profiler, which sounds reasonable—until you run it in certain contexts where it returns “Unknown” due to , uh, issues. System_profiler cli is powerful, but it can time out and not always return the values I wanted. It could also be some script shenanigans but in any case.

    For my scripting needs the fix was simple but crucial: switch to sysctl queries that always work:


    # CPU Detection - Direct kernel query
    MAC_CPU=$(/usr/sbin/sysctl -n machdep.cpu.brand_string 2>/dev/null)

    # RAM Detection – Also via kernel
    MAC_RAM=$(/usr/sbin/sysctl -n hw.memsize 2>/dev/null | awk ‘{printf “%.0f GB”, $1/1024/1024/1024}’)

    The result? Instead of seeing “Unknown” or generic “chip_type”, I would see “Apple M3” on my MacBook Air or the full Intel CPU model for an Intel Mac. And it’s 20-30x faster.

    3. No Sudo Required

    The original required administrators to create directories in `/Library/Application Support` before users could run the script. Either management tools created this beforehand or users ran a script with sudo which was not ideal or workable for non-admins. So, SetDefaultAppsX includes automatic fallback:


    if [[ ! -d "${SUPPORT_DIR}" ]]; then
    echo "WARNING: Application Support directory not found"
    echo "Falling back to /Users/Shared/SetDefaultAppsX"
    SUPPORT_DIR="/Users/Shared/SetDefaultAppsX"
    # Automatically create writable directories
    /bin/mkdir -p "${SUPPORT_DIR}"
    fi

    Users can run the script immediately without any preparation. For enterprise deployments, there’s an optional `PrepareSetDefaultAppsX.sh` that sets up system-wide directories, but it’s truly optional.

    4. Modern Icon System

    Again, in my hacking of Scott’s perfectly working script, I ran into some required banner images and so instead of relying on file system icon resources that might not exist, SetDefaultAppsX uses SF Symbols:


    OVERLAY_ICON="SF=xmark.circle,weight=medium,colour1=#000000,colour2=#ffffff"

    Always available, always renders perfectly, and customizable.

    The X2 Portable Edition: Platypus-Ready

    But I didn’t stop there. I had an idea that users could run an app easily so SetDefaultAppsX2 takes portability even further—it’s designed for packaging as a standalone application using Platypus.

    The key difference is local binary detection:


    # Get the directory where the script is located
    SCRIPT_DIR="${0:a:h}"

    # Check for binaries in script directory first
    if [[ -x “${SCRIPT_DIR}/utiluti” ]]; then
    UTI_COMMAND=”${SCRIPT_DIR}/utiluti”
    elif [[ -x “/usr/local/bin/utiluti” ]]; then
    UTI_COMMAND=”/usr/local/bin/utiluti”
    fi

    This means you can package the script along with the `dialog` and `utiluti` binaries into a single app bundle with Platypus. Users double-click the app, and everything just works—no installation, no command line, no dependencies.

    Perfect for:

    • Quick distribution to non-technical users
    • Testing environments
    • Portable USB installations
    • Labs where users can’t install software system-wide

    Community Contributions Flow Both Ways

    The best part? Scott has been incorporating some of these improvements back into his Jamf-specific version. The hardware detection fixes and error handling enhancements benefit both the enterprise and standalone versions.

    This is open-source collaboration at its finest: Scott provided the excellent foundation and deep integration expertise, the community contributed cross-platform portability, and both versions improve together.

    The Technical Wins

    Let’s talk numbers:

    • Performance: 3-4x faster startup (sysctl vs system_profiler)
    • Reliability: 100% success rate for hardware detection (up from ~60%)
    • Portability: Works on any Mac, any MDM, or no MDM
    • Security: Package signature verification via Team ID
    • User Experience: No sudo required, automatic fallback, clear error messages

    What You Get

    Three versions for different needs:

    1. SetDefaultApps.sh – Scott’s original Jamf-integrated version
    2. SetDefaultAppsX.sh – MDM-agnostic standalone version
    3. SetDefaultAppsX2.sh – Portable version ready for Platypus packaging

    All three share the same excellent user interface powered by swiftDialog, the same UTI handling via utiluti, and the same goal: make setting default apps friendly and accessible.

    Getting Started

    The simplest possible workflow:

    # 1. Run the script
    ./SetDefaultAppsX.sh

    That’s it. The script downloads swiftDialog if needed, creates directories automatically, and presents users with a beautiful interface to set their default apps.

    For Platypus app building with X2:

    – Include dialog and utiluti binaries in your app bundle
    – Point Platypus to SetDefaultAppsX2.sh
    – Users get a double-clickable app with zero dependencies

    Credits Where Due

    – **Scott Kendall**: Original script author, Jamf integration expert
    – **Bart Reardon**: swiftDialog creator (the UI magic behind it all)
    – **scriptingOSX**: utiluti tool for UTI management
    – **The Community**: Testing, feedback, and collaborative improvements

    The Open Source Philosophy

    This is what makes the Mac admin community special. Scott could have kept his script locked down or enterprise-only. Instead, he shared it, accepted community modifications, and even pulled improvements back into his version.

    The result? Better tools for everyone—whether you’re managing 10,000 Macs with Jamf or helping your family set up their MacBooks.

    What’s Next?

    The scripts are stable and production-ready, but there’s always room for improvement:

    – Auto-installation of utiluti from GitHub releases (Done!)
    – Built-in default banner images
    – Dark mode support
    – Multi-language interface
    – Configuration file support for organizations

    But the foundation is solid: a truly portable, MDM-agnostic tool for one of macOS’s most user-requested features.

    Try it yourself: The full source code, documentation, and evolution guide are available in the project repository. Whether you need the Jamf version, the standalone version, or the portable Platypus version, there’s a SetDefaultApps that fits your workflow.

    Because good tools should be accessible to everyone, not just those with enterprise MDM budgets.

    *Special thanks to Scott Kendall for creating the original script and being open to community contributions, ScriptingOSX (Armin Briegel) for utiliti and to Bart Reardon for swiftDialog —the best thing to happen to Mac admin UIs in years. *

  • 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.

  • Hello Big Sur! See ya later Monterey

    I am so happy to install macOS Big Sur 11.5.1, now that it is a ready for production. Have fun with macOS Monterey those of you on the bleeding edge. For media professionals using Xsan in production storage environments August is a great month to update to the soon to be yesterday’s bad boy Mr. Big Sur.

    Server.app v.5.10 in macOS Catalina 10.15.7

    Upgrading to a new major version of macOS can be fraught with peril for a fleet of mac devices but it is potentially fatal for a production SAN environment. That is why we wait. We want a nice stable storage system for our Final Cut Pro editors and other media creatives so it is safe to be one version behind. Less drama that way. We prefer our dramas to be on AppleTV+

    Watch TV Upgrade Xsan

    It is not boring to watch AppleTV+ while upgrading Xsan

    The Xsan upgrade to Big Sur was pretty much not exciting except for one funny roadblock that I had set up myself last as a kind of booby trap for “future me”. More about that later. First the boring stuff. The last few weeks have been very busy updating and re-writing documentation in Pages.app and running multiple redundant full and incremental LTO backups with Archiware P5, syncing to nearline archives, and archiving finalized projects to the LTO shelf in paradise (sounds more exciting when you put it that way don’t you think?). Updating and re-writing documentation can sound like a waste of time but “future you” will appreciate what “past you” was doing today. And today I had fun updating Xsan to macOS Big Sur. Now I must write down all my thoughts before I each too much vegan vanilla ice cream and slip into a food coma.

    “Planning for disasters, while hoping for none” is the IT mantra. We planned hard and we were ready to restore Xsan from Time Machine, if we had to. Not a joke. The server is backed up by Time Machine. The data is backed up to LTO, nearline archives racked and stacked in a server room and on redundant thunderbolt RAIDs which are parked on electric trucks ready to blast off at the earliest sign of danger. Well, everything except for the last part. Would be nice. And cloud backups for those clients that want them. Plan for the worst, pay for what you can to keep your business operational and lessen the impact of mechanical failures, human oopsies, or ransomware. Sysadmins are indistinguishable from malware sometimes, but we mean well. More seriously, humans makes mistakes and break things (that, me!) but ransomware is real and my elaborate backup and archive planning has saved a few customers this year.

    Ok, now for the fun part. How to upgrade an Xsan to macOS Big Sur (11.5.1). Maybe go read last year’s blog post on upgrading the Xsan to macOS Catalina 10.15.6 which was detailed and thorough. Or read Apple’s new Xsan Management Guide. It’s got all the fundamentals explained.

    Xsan volumes are typically made of up fibre channel RAID arrays. Nice icon!

    Preparation is key. Be prepared. Get ready. Psych yourself up. I used Greg Neagle’s installinstallmacos.py to download macOS Big Sur as a disk image and had that and the App Store’s Server.app downloaded beforehand and not be dependent on internet access (production SANs are not always internet accessible). It is both true and not true that you can setup Xsan in Big Sur with the Server.app. It is true you need the Server.app for an upgrade from macOS Catalina 10.15.7 but if you’re starting from scratch in macOS 11 you will be building your Xsan in Terminal. Have fun! (We will cover this in a future post).

    Download macOS Big Sur and the Server.app. Keep old copies zipped up. Cvlabel is nice too

    Server.app manages only three (3) services for an Xsan upgrade: Profile Manager, Open Directory and Xsan. In macOS Big Sur new setups of Server.app Xsan is gone. Why they haven’t taken out Profile Manager and not kept Xsan instead made me scratch my head. No one in their right mind is using Profile Manager to install or manage profiles, they’re using commercial MDM vendors. But Xsan in macOS Big Sur (11) is not only production ready storage SAN awesome it has been upgraded to be compatible with Quantum’s Stornext 7 (previously it was only v.5)

    Profile Manager does not belong here. Long Live Xsan!!

    Installing macOS 11 Big Sur and upgrading Xsan to v7 is compatible (in my testing) with macOS 10.14 Mojave, 10.15 Catalina and of course macOS 11 Big Sur. If you don’t believe me check out this not updated in forever Apple’s compatibility chart.

    Ok, by this time you get the idea I’m an expert, right? I’m ready to upgrade. But I run into my first real road block. And I have only myself to blame. I can’t launch the macOS Big Sur install app. It is blocked. “Contact your administrator”?! I am the sysadmin. Oh, ok. That’s me. What have I done now? I installed Hannes Juutilainen’s Big Sur Blocker last year, that’s what.

    Of course I installed that. With Munki. On all my Mac clients that were upgraded to macOS Catalina. (And of course my Xsan controller has Munki!). But no worries, let me read up on my last year’s blog post about it to figure out how I installed it, there must be a launch daemon or something.

    this is not how I expected it to go

    Hmm, no didn’t mention there. And where is that pesky launch daemon that I can unload and get to this Big Sur install. Oh? It’s a launch agent. Unloaded. Hmm, still no. Ok, delete the app from /usr/local/bin, hmm, nope. ok kill the app process. Ok, now we can install macOS Big Sur. Sorry for the delay. I had told Munki to uninstall the bigsurblocker app and it did for every other Mac, I swear, really. It did.

    Please proceed with the macOS Big Sur install

    So ready for macOS Big Sur. Oh wait, we noticed that you’re running Server.app and well, we don’t do a lot of the same things anymore in the new Server.app so maybe this is a warning.

    Warning. We noticed that you’re running Server.app and we don’t do those fun things anymore.

    So a lot of progress bars and stuff. See my last upgrade blog post and it’s the same as installing macOS Big Sur on any Mac, except this Mac Mini is running an Xsan production SAN environment with a lot of RAID arrays in a server rack or two. Ok, yeah, just run the installer.

    We noticed that Server app is no longer server app.

    After macOS Big Sur is installed zip up your older server.app and drag in your new one (or use that fancy App Store app to do it for you if you’re lazy). Click a bunch of buttons (see all my old blog posts) and launch the new Server.app.

    Profile Manager is updating. No one cares.

    So we have to wait while the bag of scripts that is Profile Manager gets updated but no one uses it but it’s the most important app in Server.app now, no I am not bitter why do you ask. Xsan is awesome.

    Xsan is off. Don’t panic.

    Xsan is off. Don’t panic. Where’s my towel? Panic now!

    Time to restore from your old Xsan configuration. Wheee…..

    Xsan restore configuration.

    Activate your Xsan and carry on upgrading all your Mac clients. Note: I did test macOS Mojave 10.14, macOS 10.15 Catalina and of course macOS 11.5.1 Big Sur Xsan clients. All worked.

    Xsan on. Power up.

    Upgrading Xsan with macOS Big Sur is easy if you’re going from macOS Catalina. Starting from scratch is another story to be covered in another blog post. Also not covered is certificate issues from self-signed certs breaking when I upgraded my Munki and MunkiReport server. That’s definitely another blog post. It’s just a webserver. Just. A. Web. Server. What is so hard? haha

    Technical Errata:

    With more than one Xsan controller it used to be recommended to upgrade the secondary before the primary but it is now best practise to upgrade the primary first to maintain the sanity of the OD data.

    Xsan Upgrade Step by Step:

    Clone the controllers. (+ Time Machine backups)
    Turn off the clients.
    Stop the Xsan Volume.
    Run cvfsck on the volume.
    **Upgrade the primary.
    Confirm the secondary can see the primary.
    *Upgrade the secondary.
    Confirm the secondary can see the primary.
    Check SAN access on both controllers.

    Upgrade the clients as desired.

  • Thoughts on Documentation: What are we afraid of?

    People are afraid of documentation… But mostly people just hate it. They don’t like it. They don’t want it. It shouldn’t exist. Fingers in ears. I can’t hear you.

    This is about primal fear. And hate. I hate hate. But these are real emotions. Let’s deal with it. What is the reality? Why is documentation is ignored, abandoned, or resisted at all?

    As a Sysadmin perhaps you don’t care about documentation, that is, sharing information with others (co workers / bosses), you want to keep it to yourself. But you care very much about building systems. But there’s perhaps no attempt to explain any of this to anyone else. Who else is there really? No one cares. No one is around that would understand if you explained it.

    Lesson # 1 – Document for yourself.

    Paranoia makes us set up redundant systems for backups. Layers upon layers. Custom scripts and disparate apps. Where was this explained? Documented? Nowhere. Bin dir. Maybe.

    If you could replace all that now with one app that did it all then you would. Time is valuable. Easier to monitor. Easier for someone else to monitor and take over.

    Lesson # 2 – document for your replacement (job change, bus hit)

    Do it continuously. Automate. Or set up systems that work automatically.

    Lesson # 3. DevOps.

    Integrate systems. IT systems manage computer but maybe they also built Inventory. Automatically. Alert Systems report continuously. Living systems report on the state of everything. Documentation is easier when it is current and relevant.

    Lesson # 4. Sustainability

    Commercial vs OpenSource. Support vs excellent team, talent retention and documentation. Pro/Con. If your custom solution is not well documented that can be a big problem. If you code is not shared, peer-reviewed, or supported by anyone that could be an issue. If it makes sense to switch to commercial software that is supported then do it. If an OpenSource project or code is supported by a larger community perhaps that makes sense.

    Lesson # 5. Improve. Grow. Get better.

    Discovery and Documentation lead to suggestions for improvement. Make changes. Code and disparate systems that struggle to be documented make us think about how to replace them or better balance the risks vs cost.

    Lesson # 6. Human problems don’t always tech solutions.

    Code doesn’t fix broken workflows. Meetings are with people. Talking through systems helps people understand pain points. Don’t forget people want to do their job, meet deadlines, do stuff.

    Let’s make their world and our world better.

    Love not hate. Peace.

    Documentation-MatX

  • MacDevOps Manifesto

    I was explaining Munki (and autopkg) to some colleagues when I hit on the idea of the MacDevOps manifesto.

    Munki and friends (apps used to augment and extend Munki) are helpful automation tools. Setting up automation systems take time and must be maintained and grown but they pay big dividends.  Freeing us to do Dev work or other tasks they automate and iterate and repeat and build our systems in the way we want.

    No more 100 machines built in a hundred different ways (unless we want to). But now we can check at a glance in MunkiReport to verify that indeed the latest Adobe Flash patch is installed. That may make our lives better. Especially if we need to satisfy corporate IT or our bosses that we are up to date and patched as required.

    The MacDevOps Manifesto Part 1: Munki and friends

    Munki is at its core free software created by Greg Neagle at Disney Animation and used worldwide in many different ways but essentially to distribute apps and run scripts on client workstations. There are many ways to customize it and if fits many different workflows. The MacDevOps:YVR conference I ran last June turned out to be a Munki love-in and showed me the many awesome and varied ways organizations are using it.

    With AutoPkg, another free Mac open source project, Munki can get the latest updates to any software that it has recipes for and by extension install them on clients immediately. This fits the workflow of having Flash, Java and web browsers (Chrome or FireFox) updated as soon as possible for security patches. Exploits on the Mac are coming from these entry points and if you need to use these apps or plugins then having the latest versions helps. For this feature alone I use Munki. In a few months you will see that Munki with AutoPkg has downloaded dozens of versions of each app and keeping up with this takes time away from other tasks. Automation of simple tasks frees up our time so we can focus on other things. That is MacDevOps.

    I also use Munki for installation of any app that is needed everywhere. If I have to download or install one app for one client workstation I put it in Munki and it is ready for installation anywhere with a simple click by the user in a self service portal or automatically by choosing managed installs. Of course if there is an app you don’t want installed (flash or Skype or messenger, etc) add it to Munki and mark it as managed uninstall. Done.

    Scripts and files and config Profiles (replacement for mcx, managed preference settings for OS X) can be imported and used to configure workstations to make deployment easy and flexible. Put everything in Munki and then you don’t have to use golden master builds anymore. Buy a new Mac and install the Munki client. Done.

    Add to this Munki Report which gives an excellent dashboard for what is installed and a total inventory of your client Macs. Very useful info which will let you know if you 15 different versions of flash or Photoshop or any app you choose to look for.

    Last but least I always install Watchman Monitoring which reports to a secure cloud (web portal) to automatically monitor for bad drives, Ram, backups not running etc. It’s a great 50ft overview of all your installs and it can alert you immediately when a machine is having issues that you need to deal with (drives 90% full or Xsan volume not mounted, etc).

    I find this combination of Munki and Watchman great for helping me manage my clients and I want to share these ideas about MacDevOps inspired ways of automating systems with everyone. Jump in and get involved with all these projects. You’ll be writing recipes for AutoPkg and sharing cool Munki tips and tricks with all your friends. And maybe like me you will start writing plugins for Watchman to monitor your favourite apps (I’m working on Archiware P5 backup and archive monitoring scripts).

    Good luck to everyone and hope to see you at the next MacDevOps:YVR conference in June 2016. If you can’t make it go to your nearest Mac Dev / IT conference or start your own meet up somewhere local.