Skip to main content

While this is, arguably, a feature that Jamf should be able to handle at its core, what is the best method in 2021, across the gamut of supported OS's and architectures, to enforce Apple software updates?



I understand that theres resistance to using any terminal commands for software updates. As stated in the Nudge channel, Since 2018 this has been a problem since Apple doesn't test softwareupdate commands that are triggered by a script. In addition to that, this requires a password if the computer is Apple Silicon.



I recently rolled out the UEX-Tool-For-Jamf, and two of the components in it are no longer developed and throw gatekeeper issues in Big Sur.



I would like to use Nudge, but, my confidence in my users is low enough to not expect Nudge to work fine on its own. Nudge cannot force the update to happen.



What is the best way to handle software updates? Is there MDM magic I am missing? What is the downside to having the checkbox "keep my mac up to date" checked via a config profile?

Not going to lie, I really like the new Mass action command with deferment:

 On Machine:

A way to Schedule this would be amazing, however this is a really great start!


The only issue is that this kills my network during the day and you can not schedule it. 



@dmichels wrote:

The only issue is that this kills my network during the day and you can not schedule it. 


Sounds like a good use case for a caching server?


The only issue is that this kills my network during the day and you can not schedule it. 


I am absolutely with you on that one for sure, cause who wants to be there after hours to hit the button. We are all just trying to keep our weekends right!?!? Limiting the traffic from the app store and other apple servers might be a good route to explore.

Depending what your needs are (ios and macOS, like if one is more heavy than others) the answers are likely here, to get over to the network team, or if you are the network team, if you wanted to do things like limit how much total bandwidth macOS updates take etc:

https://support.apple.com/en-us/HT210060


This is exactly what I was looking for! Thank you. My only issue is, how are you waking up the sleeping machines? I have a few conference rooms and classrooms machines that I would like to update automatically (atleast minor software updates) and the biggest issue I am running into is waking them up remotely. Any suggestions? Also do you have your script shared on github? 


I actually had to abandon the strategy.  Most of it worked except sometimes they got stuck in a loop and were never able to remove the automatic login, even though it had been scripted.  I'm a novice at scripting and ran out of time to get it working without causing class disruptions so I backed out of the policies.

That being said, someone with more advanced scripting skills than myself could most likely get this to work reliably.  When the scripts did work the systems did download and install Big Sur updates on their own and then restart to complete them.


If you don't want to prompt the user at all, you can make a bash or python script that runs the Download and Install Updates management command for you. Add the script to a user interaction policy  to give the user the option to defer the update. 

 

apiUsername="apiaccount"
apiPassword="apipassword"
jamfProURL="https://yourorg.jamfcloud.com"
macSerial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
jamfProCompID=$(curl -s -u $apiUsername:$apiPassword -H "Accept: text/xml" "$jamfProURL"/JSSResource/computers/serialnumber/"$macSerial" | xmllint --xpath '/computer/general/id/text()' -)


/usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfProCompID}

 


Been going round in circles with this for ages now but finally got something working.

https://github.com/PezzaD84/macOS-Patching

Made a script to prompt the user to available updates with the option to postpone the update for 4 days. Used to use this script before M1's ruined everything but added a nice function to run the MDM command via an API post if the device is M1.


Been going round in circles with this for ages now but finally got something working.

https://github.com/PezzaD84/macOS-Patching

Made a script to prompt the user to available updates with the option to postpone the update for 4 days. Used to use this script before M1's ruined everything but added a nice function to run the MDM command via an API post if the device is M1.


This is a good looking script, I really hate how people are having to resort to API commands to shore up JAMFs inability or lack of desire to do anything with software update MDM commands in any reasonable amount of time.

 

This will still have problems if the Mac is having issues with OS updates via MDM commands. Which is unfortunately fairly common. As far as I can tell JAMF is still not using the StatusUpdate MDM command, so JAMF has no idea what is going on with updates once the MDM command goes out.


This is a good looking script, I really hate how people are having to resort to API commands to shore up JAMFs inability or lack of desire to do anything with software update MDM commands in any reasonable amount of time.

 

This will still have problems if the Mac is having issues with OS updates via MDM commands. Which is unfortunately fairly common. As far as I can tell JAMF is still not using the StatusUpdate MDM command, so JAMF has no idea what is going on with updates once the MDM command goes out.


Agreed this script looks like a winner for us.  As we need something that works sometimes with Catalina, Big Sur, Monterey and then M1/Intel.

Has this been tested on all of the above in your environments?  We've looked at Nudge but it has some issues sometimes were not a fan of.


Agreed this script looks like a winner for us.  As we need something that works sometimes with Catalina, Big Sur, Monterey and then M1/Intel.

Has this been tested on all of the above in your environments?  We've looked at Nudge but it has some issues sometimes were not a fan of.


@daniel_ross This was mainly used for patching Catalina and Big sur as it basically just triggers the softwareupdate command. It was only when we got some M1 devices in that we noticed the issue that no reboots and installations were happening. So it should be all good for Catalina, big sur and monterey.

Feel free to reach out if you have trouble with it or find things to tweak I'm open to improvements. We all need to work together on this as patch management is a burden we all have to carry!😂🙊


@daniel_ross This was mainly used for patching Catalina and Big sur as it basically just triggers the softwareupdate command. It was only when we got some M1 devices in that we noticed the issue that no reboots and installations were happening. So it should be all good for Catalina, big sur and monterey.

Feel free to reach out if you have trouble with it or find things to tweak I'm open to improvements. We all need to work together on this as patch management is a burden we all have to carry!😂🙊


@perryd84 Thanks for sharing this script! Can I ask what has your experience been running this on M1 Macs? I have just tested this on an M1 MacBook but keeps sticking at the prompt to 'Free up Disk Space' requiring 15gb of space but the MacBook has about 400GB free currently.


@perryd84 Thanks for sharing this script! Can I ask what has your experience been running this on M1 Macs? I have just tested this on an M1 MacBook but keeps sticking at the prompt to 'Free up Disk Space' requiring 15gb of space but the MacBook has about 400GB free currently.


Hi @jamfjosh21 I've changed the logic for the disk space now so it should work ok. The logic I had in the script was reliant on the main OS disk being disk1s1 but I have seen a few instances where it isn't. I've updated the script on git hub so it should work around this now. Let me know how you get on.


@perryd84 Thanks for sharing this script! Can I ask what has your experience been running this on M1 Macs? I have just tested this on an M1 MacBook but keeps sticking at the prompt to 'Free up Disk Space' requiring 15gb of space but the MacBook has about 400GB free currently.


My experience on M1 machines is that the only way to get the software updates to install is using the mass action or management commands in Jamf.  I had no luck at all trying to use policies, scripts, etc and it sounds like that is by design.  Jamf has improved the MDM mass action commands by allowing you to select a version of the OS that you want to patch to.  The problem currently is that there is no scheduling capability.  This is a big issue for us in an education setup where we cannot tell it to update the OS overnight when machines are not in use.  I'm hoping to see some scheduling options soon, but won't hold my breath so far!


My experience on M1 machines is that the only way to get the software updates to install is using the mass action or management commands in Jamf.  I had no luck at all trying to use policies, scripts, etc and it sounds like that is by design.  Jamf has improved the MDM mass action commands by allowing you to select a version of the OS that you want to patch to.  The problem currently is that there is no scheduling capability.  This is a big issue for us in an education setup where we cannot tell it to update the OS overnight when machines are not in use.  I'm hoping to see some scheduling options soon, but won't hold my breath so far!


@bbarciz you can schedule them with a combination of running the MDM mass action command via API and a user interaction or jamf helper policy. Take a look at @perryd84 's script above. Using the following API command will allow you to do this.

user=APIUSER
passwd=APIPASSWORD
serial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
ID=$(curl -u $user:$passwd -X GET "https://YOUR.JAMFSERVER.COM/JSSResource/computers/serialnumber/$serial" | tr '<' '\\n' | grep -m 1 id | tr -d 'id>')
curl -u $user:$passwd -X POST "https://YOUR.JAMFSERVER.COM/JSSResource/computercommands/command/ScheduleOSUpdate/action/InstallForceRestart/id/$ID"
}

Just wanted to let folks in this thread know about Friday's Virtual Mac Admin Meetup from @rocketman .  The topic for this meeting is "going over the latest way to send macOS updates, with deferrals, through purely an MDM command that works on both Intel and M1 Macs."  Certainly worth a look!  (and for those reading this after the fact, they're typically recorded for later viewing.)

Details here: https://community.jamf.com/t5/virtual-mac-admins-meetup/february-virtual-mac-admin-meetup/ec-p/257144#M10


@bbarciz you can schedule them with a combination of running the MDM mass action command via API and a user interaction or jamf helper policy. Take a look at @perryd84 's script above. Using the following API command will allow you to do this.

user=APIUSER
passwd=APIPASSWORD
serial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
ID=$(curl -u $user:$passwd -X GET "https://YOUR.JAMFSERVER.COM/JSSResource/computers/serialnumber/$serial" | tr '<' '\\n' | grep -m 1 id | tr -d 'id>')
curl -u $user:$passwd -X POST "https://YOUR.JAMFSERVER.COM/JSSResource/computercommands/command/ScheduleOSUpdate/action/InstallForceRestart/id/$ID"
}

Thanks for sharing.  Is the scheduling component done with the Jamf policy triggers than?


If you don't want to prompt the user at all, you can make a bash or python script that runs the Download and Install Updates management command for you. Add the script to a user interaction policy  to give the user the option to defer the update. 

 

apiUsername="apiaccount"
apiPassword="apipassword"
jamfProURL="https://yourorg.jamfcloud.com"
macSerial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
jamfProCompID=$(curl -s -u $apiUsername:$apiPassword -H "Accept: text/xml" "$jamfProURL"/JSSResource/computers/serialnumber/"$macSerial" | xmllint --xpath '/computer/general/id/text()' -)


/usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfProCompID}

 


This looks very promising, but I was wondering what kind of rights do you need to give the API user account and is there any concern about it passing that username and password in plaintext?


Thanks for sharing.  Is the scheduling component done with the Jamf policy triggers than?


If you use user interaction or the jamf helper (in a policy), the user can defer the update until you want it to force install. @perryd84 's script has a max deferral limit of 4 days. 


For anyone sending MDM commands, either via GUI or API, how are you handling the delay from when it is sent to when it actually happens?  Using the softwareupdate binary in the past was far more predictable and easy to give on screen feedback.  Deploying updates via MDM is mixed bag of instant to 2 hours from my experience.


For anyone sending MDM commands, either via GUI or API, how are you handling the delay from when it is sent to when it actually happens?  Using the softwareupdate binary in the past was far more predictable and easy to give on screen feedback.  Deploying updates via MDM is mixed bag of instant to 2 hours from my experience.


For me it's between 20-40 minutes, but I haven't pushed this to production yet. More testing to do. I can just let the user know that the update can happen within that timespan with Jamfhelper.


@bbarciz you can schedule them with a combination of running the MDM mass action command via API and a user interaction or jamf helper policy. Take a look at @perryd84 's script above. Using the following API command will allow you to do this.

user=APIUSER
passwd=APIPASSWORD
serial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
ID=$(curl -u $user:$passwd -X GET "https://YOUR.JAMFSERVER.COM/JSSResource/computers/serialnumber/$serial" | tr '<' '\\n' | grep -m 1 id | tr -d 'id>')
curl -u $user:$passwd -X POST "https://YOUR.JAMFSERVER.COM/JSSResource/computercommands/command/ScheduleOSUpdate/action/InstallForceRestart/id/$ID"
}

FYI if @perryd84 's command doesn't work for you try using the one below.

apiUsername="apiaccount"
apiPassword="apipassword"
jamfProURL="https://yourorg.jamfcloud.com"
macSerial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
jamfProCompID=$(curl -s -u $apiUsername:$apiPassword -H "Accept: text/xml" "$jamfProURL"/JSSResource/computers/serialnumber/"$macSerial" | xmllint --xpath '/computer/general/id/text()' -)


/usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfProCompID}

For anyone sending MDM commands, either via GUI or API, how are you handling the delay from when it is sent to when it actually happens?  Using the softwareupdate binary in the past was far more predictable and easy to give on screen feedback.  Deploying updates via MDM is mixed bag of instant to 2 hours from my experience.


I am sending the commands through the Jamf GUI and just planning for a delay.  So far, it appears that the commands start with in maybe 10 or 15 minutes for me, and the download time can be a factor depending on the number of machines that I tell it to update at the same time (we have our bandwidth for updates limited as not to take everything else to its knees at the same time).  To get a feel for when it starts, I will be logged into a system and watch activity monitor and wait for network traffic to start, that is how I have gauged the delay in my environment.  I find that I can do roughly 20 systems in about 2 hours for an OS upgrade (MacOS11 to MacOS12).


FYI if @perryd84 's command doesn't work for you try using the one below.

apiUsername="apiaccount"
apiPassword="apipassword"
jamfProURL="https://yourorg.jamfcloud.com"
macSerial=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')
jamfProCompID=$(curl -s -u $apiUsername:$apiPassword -H "Accept: text/xml" "$jamfProURL"/JSSResource/computers/serialnumber/"$macSerial" | xmllint --xpath '/computer/general/id/text()' -)


/usr/bin/curl -s -X POST -H "Content-Type: text/xml" -u ${apiUsername}:${apiPassword} ${jamfProURL}/JSSResource/computercommands/command/ScheduleOSUpdate/action/install/id/${jamfProCompID}

@bwoods and @perryd84 thank you for those commands/scripts. With a bit of work I've gotten them to pretty reliably trigger updates on Intel machines.
However I still can't get our M1 machines to actually install any system updates. While the MDM command is issued and received by the client, in the end the install fails to initiate.

What I keep seeing in /var/log/install.log are entries like this:

2022-02-09 14:40:47+01 TestMBA softwareupdated[575]: SoftwareUpdate: request for status for unknown product MSU_UPDATE_20G415_patch_11.6.3

2022-02-09 14:40:47+01 TestMBA SoftwareUpdateNotificationManager[983]: (null):softwareupdated: Service connection invalidated!


@bwoods and @perryd84 thank you for those commands/scripts. With a bit of work I've gotten them to pretty reliably trigger updates on Intel machines.
However I still can't get our M1 machines to actually install any system updates. While the MDM command is issued and received by the client, in the end the install fails to initiate.

What I keep seeing in /var/log/install.log are entries like this:

2022-02-09 14:40:47+01 TestMBA softwareupdated[575]: SoftwareUpdate: request for status for unknown product MSU_UPDATE_20G415_patch_11.6.3

2022-02-09 14:40:47+01 TestMBA SoftwareUpdateNotificationManager[983]: (null):softwareupdated: Service connection invalidated!


@emilh That error looks like it's not finding the 11.6.3 patch for some reason. I've seen this error on intel macs in the past going from Catalina to Big Sur, the MDM command gave that error and we had to upgrade them a different way by pushing the pkg to upgrade them.


I am sending the commands through the Jamf GUI and just planning for a delay.  So far, it appears that the commands start with in maybe 10 or 15 minutes for me, and the download time can be a factor depending on the number of machines that I tell it to update at the same time (we have our bandwidth for updates limited as not to take everything else to its knees at the same time).  To get a feel for when it starts, I will be logged into a system and watch activity monitor and wait for network traffic to start, that is how I have gauged the delay in my environment.  I find that I can do roughly 20 systems in about 2 hours for an OS upgrade (MacOS11 to MacOS12).


@bbarciz do you know if it's possible to chain the "download updates" and "download and install updates" commands? that would simulate an install cached workflow and speed things up a bit.


@bbarciz do you know if it's possible to chain the "download updates" and "download and install updates" commands? that would simulate an install cached workflow and speed things up a bit.


@bwoods  I do not know the answer to that.  It seems like a good logic and when I would deploy an install macos full installer in the past, I would pre-cache the installer on the machines for this exact logic.

I just looked at my jamf instance (version 10.35) and see 3 options for install action now:

  • Download the update for users to install
    • I seem to recall reading that this one required users to have admin rights or for their accounts to have something set with them.  I don't recall the details and I also assume the user would get notified which may not be what you want.
  • Download and allow macOS to install later
    • This has a setting for "max user deferrals" to allow users to defer a certain number of times.
    • This seems to imply the user will be notified since it could be deferred as well.  Not sure if that would be ok in your concept to cache the installer.
  • Download and install the update, and restart computers after installation
    • This is the do it now type action with no warning that the computer will restart.

 

Not sure if that really helps you out at all or not.