Using the xprotect command in macOS 15

This year, we set out to build a more stable Zoom Rooms environment at the office. We took the philosophy of treating Zoom Rooms Macs like servers. Software updates would be installed during maintenance windows when the conference rooms weren’t in use. All automatic software update features were disabled via a configuration profile. Rather, software updates are triggered on-demand, either in-person or remotely.

Disabling all macOS software update features, also disables updates to XProtect, the macOS built-in anti-malware tool. While we also have a third party EDR agent installed, it seems prudent to maintain XProtect as well.

macOS Sequoia 15 provides a new command, xprotect, that allows for the automation of updates to XProtect. xprotect has four sub-commands: version, check, update, and logs1.

xprotect version returns the locally installed version.
xprotect check returns the current update available. This subcommand requires root/sudo.
xprotect update also requires root/sudo and installs a pending update. If XProtect is already up to date, it will report that and exit cleanly.

Process in Jamf

Extension Attribute

An extension attribute called XProtect Update gathers the status of XProtect updates. It returns “Not eligible” for macOS 14 and earlier, “Not found” if XProtect is up to date, or “Update available” with a version number when there’s a pending update.

#!/bin/bash
result="Not found"
major_os=$(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}')

if [[ ${major_os} -lt 15 ]]; then
  result="Not eligible"
else
  installed_version=$(/usr/bin/xprotect version | awk '/Version/ {print $2}')
  update_version=$(/usr/bin/xprotect check | awk '/version/ {print $NF}')
  if [[ ${update_version} -gt ${installed_version} ]]; then
    result="Update available: ${update_version}"
  fi
fi

echo "<result>${result}</result>"

Smart Group

A smart named Update XProtect is used to scope policies. The criteria are as follows:

CriteriaOperatorValue
XProtect Update Statusmatches regex^Update available:

Script

A script named XProtectUpdate runs the update command and reports before and after versions.

#!/bin/bash

major_os=$(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}')

if [[ ${major_os} -lt 15 ]]; then
  echo "ERROR: Incompatible operating system version"
  exit 1
fi

echo "Before:"
/usr/bin/xprotect version

echo
echo "Updating..."
/usr/bin/xprotect update

echo
echo "After:"
/usr/bin/xprotect version

Policy

There are multiple ways to offer the above script in a policy. We have chosen to put it in Self Service.

Triggers: Self Service
Execution: Ongoing
Scope: Update XProtect group

Stages

Script: XProtectUpdate

Maintenance: Update Inventory


  1. The logs subcommand runs an XProtect-related log show command. It is out of scope for this post. ↩︎

Leave a comment