Managing macOS updates in 2022

Honored Contributor III

Here we go again. Just a discussion on Software updates in 2022 rather than necroing an old post.

How are you guys keeping up with OS updates and figuring out if devices failed patching or still processing? I'm over here still needing to manually check each device that is not running the OS build I am expecting and digging through the install.log if the MDM commands are showing as completed.

JAMF still has not given us a way to deploy software update MDM commands via policy. Even after saying it was a possibility 10 months ago. Checking status requires going device by device and checking inventory records and if OS updates fail you get nothing as JAMF is not using the StatusUpdate key.


Managed Software Updates - using deferrals via a m... - Jamf Nation Community - 249821

Example mass action/remote command workflows moving forward:

(Existing) Admins can issue a remote command to a set of devices to download and install to an upgraded version of macOS ASAP, restarting end-user machines as necessary
(Existing) Admins can issue a remote command to a set of devices to download to an upgraded version of macOS and notify the end user
(Upcoming, net new) Admins can issue a remote command to a set of devices to download to an upgraded version of macOS and notify the end user, and input a MaxUserDeferrals integer between 1-90, which will allow the end users to snooze a software between 1-90 days
Potential future functionality:
~ Ability to issue these commands via API
~ Ability to schedule these commands
~ Ability to issue these commands via policy



Honored Contributor

I'm encountering a bunch of problems staying on top of updates. One is that many Macs in our environment absolutely DO need updates, but Software update says there are none available. If we flush system caches, that seems to enable the computer to see the updates, but that's a step users have to manually perform since a restart is necessary. Another problem we have is if we setup a policy in jamf that uses the Software Update payload, it doesn't work at all.... never .... under any circumstances. MDM commands to update the OS are hit or miss.

Honored Contributor III

I have seen very similar with Macs saying they don't have updates available when they should. There was an argument I have used with softwareupdate in the past to force it to download a specific update even if the Mac could not see it. The experience was not good, but it worked (for intel Macs). 


We are seeing anywhere from a 60-70% success rate with OS updates via MDM command. Of course figuring out which devices failed and why is totally manual.

Valued Contributor

But you are aware that the softwareupdated gets stuck on many versions of macOS 10.15, 11 and 12, do you? When that happens the available updates are not shown, the command "softwareupdate -l" would not finish. When that happens you have to run "sudo /bin/launchctl kickstart -k system/" or reboot the Mac. The daemon will get stick again after a while.

Contributor III

Are you suggesting creating a policy to deploy sudo /bin/launchctl kickstart -k system/ to the devices that are having issues updating?

Valued Contributor

In fact I did create a policy, but I only made it available in the Self-Service, as I considered it too tricky to properly identify the Macs that are suffering from this condition.


I posted most of this in another thread or two, but basically it's a nightmare currently to get compliant with software updates.

The softwareupdate binary command doesn't work the same with ARM based Mac computers (or apparently Monterey I was told, I guess, I'm not 100% sure on that). Apple changed the -iar part of the softwareupdate binary foir M1's. As a result Jamf policies running that command no longer work, nor do policies with the software update payload either. Apple recommends using MDM commands. However that is extremely flaky, and you lack a real good way to schedule or notify users. It seems like something that in a few years might be good, but it's just not good or reliable currently. 

You really have 2 options for reliable updates in my opinion. Option 1 is to use a 3rd party tool to help gain compliance. Nudge works great, is widely used, and is extremely well documented. Another option is utilizing SUPER which is also pretty well documented. Both essentially bug users to install updates themselves. Home users are the demographic Apple has primarily developed their product for, while the enterprise Mac environments are a languishing thought in the back of their heads often times. Thus modern versions of macOS/Mac hardware essentially require user interaction to complete, until MDM commands improve/are fixed. 

Option 2 is to download the full macOS Monterey 12.5.1 installer (which you can do with the link here), and then make a policy that just installs that over top of the OS. This is non-destructive, it will just take longer. There are multiple methods for that. I believe these two are the most popular ways to do so: 1 2. This generally also require some level of user interaction on modern macOS's/Mac hardware. If you can script a known local user password on the machine you can fully automate it though. 

On top of all of that, in general there's been issues on Big Sur & Monterey with timely fetching software updates, even with the "keep my mac up to date" button checked. It's an issue with the softwareupdate binary again. Many people haven't seen the 12.5 or 12.5.1 updates available to them yet because of this. The general fix is to manually check for updates a few times, reboot, or run the "sudo launchctl kickstart -k system/" command and then check for updates again. I'm not sure if this effects MDM commands, but it seems likely it does. 

I did also look into doing updates via the MDM commands, but they’re just so unreliable. They’re only available for Big Sur, Monterey, and above. And different versions of macOS has different features, so you’d see different behavior (when it actually worked) between computers in your enviorment. Eventually I think that this will be the way to go, but right now I wouldn’t advise it. When this finally works well, initiating updates via a script using the API is probably the way I will go. I started going down this route, and had a working prototype script. My idea was to either deploy the script to run automatically via policy at a specific time or make available in Self Service for user initiation. Below is my prototype.





function DecryptString() {
  echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"


username="jss api account"
password=$(DecryptString $4 'salt' 'passphrase')
#please don't hardcode a password

 serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
 echo "serial number is $serialNumber"
     # Generate new auth token
token_json=$(curl --silent --user "${username}":"${password}" --request POST "${jssURL}/api/v1/auth/token")

token=$(echo ${token_json} | /usr/bin/awk -F \" 'NR==2{print $4}')
    # Determine Jamf Pro device id
    deviceID=$(curl -s -H "Accept: text/xml" -H "Authorization: Bearer ${token}" ${URL}/JSSResource/computers/serialnumber/"$serialNumber" | xmllint --xpath '/computer/general/id/text()' -)
    echo "device id is ${deviceID}"

        # Execute software update
    curl -X POST "${URL}/api/v1/macos-managed-software-updates/send-updates" -H "accept: application/json" -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" -d "{\"deviceIds\":[\"${deviceID}\"],\"maxDeferrals\":3,\"skipVersionVerification\":false,\"applyMajorUpdate\":false,\"updateAction\":\"DOWNLOAD_AND_INSTALL\",\"forceRestart\":true}"



Honored Contributor III

I tried nudge but did not really care for it. It is just politely asking users to do the thing. I can get equally as aggressive with Jamf Helper and not need a 3rd party tool to annoy people. Beyond that I agree its absurd that in an enterprise environment apple expects admins to coordinate with users to enforce updates rather than being able to reliably dictate when a device runs updates. OS updates as a whole, MDM commands aside are very unreliable from what I have seen.


I am working on getting restrictions in place to start blocking core applications for devices that are out of OS update compliance. In addition to pestering people with JAMF helper, then using MDM Commands (which have about a 70% success rate) I am also planning on blocking applications for users who refuse to update. Basically make the users come to me.


Unfortunately I don't have hope for things getting better with these software update MDM commands. They first popped up in macOS 10.12 and really have not been improved since. Apple has added more commands like deferrals, but has not improved reliability. Honestly I am a bit worried, they are trying to make this work like iOS. and with iOS you cannot install updates at all without a user entering a password. You can prevent logging in to the iPad until the user approves the updates, but it still requires user approval. 


I have been meaning to work on a JAMF API script to try updates. Thanks for that script, I am stealing it :).

According to Jamf developer documentation, (if I'm reading correctly) 'maxDeferrals' is ignored if 'forceRestart' is defined or set to 'true'. Has that been your experience?

I'm trying to figure it out myself because it seems like I have a lot of machines that aren't getting restarted with 'maxDeferrals' defined and 'forceRestart' set to 'false'. Wondering if I need to remove 'forceRestart' entirely in order for the 'maxDeferrals' portion to work.

Contributor III

I was just going to post something this morning about the OS Updates and then I see this thread. @dennisnardi Does your script work? I found one on here that looks similar, but it's hit and miss. I'll have it kickoff at 8pm on the device, the policy completes within 10min, but the update will install like 6-7 hours later or just won't install. We're trying to have it install with no user interaction. I have tried the scripts that were posted by bwoods. I've been trying the mass action update the last few days on different Mac's and it's hit and miss.

My script works as good as it can. The problem is with MDM commands. I see similar behavior to what you described sometimes whether I use my script or click the buttons manually in Jamf Pro. Sometimes thing work in 2-30 minutes, other times hours, other times not at all. Sometimes the deferrals work, sometimes they don't. The highest percentage I've seen someone estimate that MDM commands work is 70%, and in my testing it was closer to 50% for me. Unfortunately MDM commands are just not stable or reliable enough to be used in production currently in my opinion. Apple still has a decent amount of work to do to improve that. MDM OS update commands on iOS haven't been great, and that's been out for years, so who knows when/if it'll get better for macOS. 

New Contributor II

How do you get it to kick off at a specific time?

My script is designed to run on an endpoint, so you would deploy via policy. I would schedule the activation to be at a specific time and the next time the computer checked in, it would in theory begin updating via MDM commands. 

Another option is to modify that script to run from a local machine/server and send the MDM command to machines in your enviorment. That is the more secure way to do things. You'd need to figure out additional logic, and add a loop into the script. 

If you are ok with manual things, you can just make an advanced search for out of date computers, and issue the MDM command via the mass actions that way. 

Contributor III

Here is one of the scripts we're using that is also hit and miss.


# Server connection information

# Determine Serial Number
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')

echo "Serial number: ${serialNumber}"

# create base64-encoded credentials
encodedCredentials=$( printf "${username}:${password}" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - )

# Generate new auth token
authToken=$( curl -X POST "${URL}/api/v1/auth/token" -H "accept: application/json" -H "Authorization: Basic ${encodedCredentials}" )

echo "Auth Token: $authToken"

# parse authToken for token, omit expiration
token=$(/usr/bin/awk -F \" 'NR==2{print $4}' <<< "$authToken" | /usr/bin/xargs)

echo "Token: $token"

# Determine Jamf Pro device id
deviceID=$(curl -s -H "Accept: text/xml" -H "Authorization: Bearer ${token}" ${URL}/JSSResource/computers/serialnumber/"$serialNumber" | xmllint --xpath '/computer/general/id/text()' -)

echo "Device ID: ${deviceID}"

# Execute software update
curl -X POST "${URL}/api/v1/macos-managed-software-updates/send-updates" -H "accept: application/json" -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" -d "{\"deviceIds\":[\"${deviceID}\"],\"maxDeferrals\":0,\"version\":\"12.5.1\",\"skipVersionVerification\":true,\"applyMajorUpdate\":true,\"updateAction\":\"DOWNLOAD_AND_INSTALL\",\"forceRestart\":true}"

# Invalidate existing token and generate new token
curl -X POST "${URL}/api/v1/auth/keep-alive" -H "accept: application/json" -H "Authorization: Bearer ${token}"