Handling macOS Software Updates with Jamf Pro

Jamf Pro has not handled software updates successfully on all Mac hardware since Apple introduced the T2 processor with the iMac Pro back in December 2017. It’s been requested that they address this issue in a feature request, but it’s gone completely unacknowledged (Edit: As of November 11, 2019, the feature request is now marked as Under Review).

The problem with the software update process on Macs with T2 processors is that sometimes there is a bridgeOS update (the OS on the T2 processor) which requires a shutdown instead of a restart. The Mac will read the shutdown and automatically power back on to apply the bridgeOS update. However, not all software updates have a bridegeOS update which would mean a shutdown in those situations would actually leave the computer powered down. Unfortunately, Jamf Pro does not know how to handle this situation. Apple did introduce the --restart option for softwareupdate but that also comes with its own problems in that it hasn’t worked reliably in all scenarios. Since the solution to this isn’t particularly difficult to work around, I created a script to address this workflow in our environment.

Before continuing, I’d like to mention that we do leverage macOS’s ability to do automatic updates. This has one benefit of doing automated authenticated restarts which is important on Macs with FileVault enabled. However, we’ve found in our environment that after a month only 60% of computers running macOS 10.14 are up to date on the latest version. It’s a bit of a black box as to how macOS determines when to do automatic updates. Needless to say, the rate of updates is unacceptable.

This script is meant to be used with Jamf Pro and makes use of Jamf Helper. The idea behind this script is that it alerts the user that there are required OS updates that need to be installed. Rather than forcing updates to take place through the command line using “softwareupdate”, the user is encouraged to use the macOS GUI to update. When I say macOS GUI, I’m referring to the Software Update mechanism that Apple refers consumers to: https://support.apple.com/en-us/HT201541

In recent OS versions, Apple has done a poor job of testing command line-based workflows of updates and failed to account for scenarios where an end-user may or may not be logged in. The update process through the GUI has not suffered from these kind of issues. The script will allow end users to postpone/defer updates X amount of times and then will give them one last chance to postpone. We run this script using the Once A Day policy frequency which means the user will get this once a day so long as it checks in.

This script should work rather reliably going back to 10.12 and maybe further, but at
this point the real testing has only been done on 10.14. Please note, that this script does NOT cache updates in advance. Sometimes Apple releases updates that get superseded in a short time frame. This can result in downloaded updates that are in the /Library/Updates path that cannot be removed in 10.14+ due to System Integrity Protection.

This script does make use of Jamf Pro Script Parameters:
Parameter 4: Optional. Number of postponements allowed. Default: 3
Parameter 5: Optional. Number of seconds dialog should remain up. Default: 900 seconds
Parameter 6: Optional. Contact email, number, or department name used in messaging. Default: IT

Here is the expected workflow with this script:

  1. If no user is logged in, the script will install updates through the command line and
    shutdown/restart as required.
  2. If a user is logged in and there are updates that require a restart, the user will get
    prompted to update or to postpone.
  3. If a user is logged in and there are no updates that require a restart, the updates will get installed in the background (unless either Safari or iTunes are running.)

There are a few exit codes in this script that may indicate points of failure:
11: No power source detected while doing CLI update.
12: Software Update failed.
13: FV encryption is still in progress.
14: Incorrect deferral type used.

Below are some screenshots for what you will see on macOS Mojave. However the text is aware of at least 10.8 and higher where the instructions to get to Software Update might differ.

This is the initial message you will see when prompted to update:


When you click Continue, you will be taken to Apple’s Software Update:


This is the final message you will get when you’ve postponed the maximum number times:


Note: “Please make selection in HH:MM:SS” is not text I can modify. It serves as a countdown for the end user to know how much time they have before they are forced to update.

And lastly when the forced update is taking place, a headsup display window pops up:


The script is easy to modify if you don’t like the verbiage or if you want to use it for inspiration on other workflows. The script can be found here on my Github page.

33 thoughts on “Handling macOS Software Updates with Jamf Pro

  1. Excellent work and well thought out, I can’t find anything i wanted to change. This is a good light touch management approach to macOS updates.


  2. nice script but I’ve come across an interesting edge case in my first test. In testing on a 10.14.5 machine there was an iTunes restart update available. installed this and restarted. next time it ran 10.14.6 update was available but the defer count hadn’t gone down. Tried this using interactive install and forced install. I’m not sure of a way round this as the interactive install can always be cancelled by the user thus avoiding any way to clear the counter in the script. In the automated method it could be set to clear the deferral count.


    1. The latest version of my script should account for this. I previously did not reset the deferral counter prior to restarting under the rationale that somehow a user could game the restart process to avoid the update. But that seems very unlikely.


  3. Hi, I’m evaluating this script but it just does not seem to run on my Jamf. it errors with no information. Do I need to amend it in anyway? I inserted parameters in 4&5.


    1. What’s the output you get in the policy log? Is this happening with every computer or just one? Can you try modifying the first line in the script to `#!/bin/bash -x` to see what is getting executed?


    1. I was doing some testing in Catalina with this script a week or two ago. Testing was mostly just around the changes in the text output which has changed slightly in Catalina versus previous versions of macOS. It seemed at least in my brief testing that the script seems to handle these changes fine. Did you have problems running this script in Catalina?


    2. Just wanted to let you know that I did some more testing today on Catalina. I made some updates to the script with some other bug fixes. I can confirm that it works in Catalina.


  4. Great work! Would you mind sharing your Software Update settings as well? Do you use a configuration profile in conjunction with this script? Specifically, I’m interested if you are setting or disabling ‘Download new updates when available’. Thanks!


  5. Thanks for making this available. I’ve just been reviewing this to see if it could work in our environment.
    Please correct me if I’m wrong but it would appear that if the prompt occurs when a user isn’t at their machine, or they simply ignore it, there is a 15 minute timeout (default). During which time the jamf policy process is blocked waiting for the script to finish running. That doesn’t seem ideal as it could prevent other important actions from being completed.


    1. This is a fair point and one I thought of when making the script. In our environment we actually do not use the default value of 15 minutes to time out. We have it set to 90 minutes. At least in our experience, it does not seem to have stopped jamf from running other policies. I believe that jamf will get into a state where it will simply launch another jamf process when it’s supposed to check in again (even if there’s already a jamf process running). You can test this out yourself of course and let me know what your experience is.

      And naturally, if you don’t particularly like the logic for this part of the script, you can change the default time out value so that it’s less than your jamf check-in period. Alternatively, you can make your own modifications to the script as well to fit your company’s needs.


  6. I am new to Jamf and this process, I tried the run this script AppleSoftwareUpdate.sh from self service, but it fails “Error: This computer does not meet the OS Requirements for the script AppleSoftwareUpdate.sh.” when run under Mojave and Catalina. Has anyone gotten this error? Does anyone have the a screenshot of the policy settings? I did not make any changes to the script and i am not seeing any of the above verbiage as the screenshots above.


    1. No. This script is meant specifically for macOS software updates (10.14.1 to 10.14.2); it is not meant for OS upgrades (e.g. 10.14 to 10.15). For OS upgrades, the best I can offer you is a Self Service-based workflow: https://babodee.wordpress.com/2019/11/05/revisiting-a-macos-upgrade-method-using-jamf-pro-self-service/

      I also have another script to nag end users to upgrade: https://babodee.wordpress.com/2019/09/19/jamf-pro-os-deprecator/


      1. thanks. one last q. Do we need the restart options to be enabled as well. after 3 postpones how much time do users have before the machine reboots?


      2. You don’t need to enable restart options in the policy payload. The script handles all that. The default for dialogs to stay up is 900 seconds. You can change that as mentioned in the blog post. Hope that helps.


  7. Hi there, Thanks for the brilliant workflow. I have been testing with pilot groups and working very well especially remote users who can’t access internal SUS.

    One question. We will most likely use this on a monthly schedule and was wondering how the com.custom.deferrals.plist was reset for the next round? Or do we need to build that into a pre-script to reset the count integer?

    In testing I chose to update manually after one postponement but noticed a 10.14.5 system was updated to 10.14.6 and as a result of that the Security Update 2020-002 was detected soon after and when the script ran again there was only 2 deferrals left.

    Thanks again


    1. The com.custom.deferrals.plist is reset whenever the script runs and softwareupdate reports that there are no updates available. The situation where yet another update is available after you’ve already updated has not been addressed. However in the current situation ideally the end-user will take the opportunity to just apply the follow-up update


    2. If you’ve setup the policy as described in the post, then the script will typically try to run every day. Once the updates are performed, when the script runs again it will detect that no further updates are available and would reset the counter. The situation you describe is not one I’ve been able to quite address.

      On the one hand, it is quite inconvenient to do an OS update and then have to do a second OS update since. That just happens to be the nature of Security Updates where they rely on the last minor OS update that Apple released for that OS so that they can install successfully.

      But on the other hand, as an IT admin we do want our users to perform all the OS updates possible. And if that means they need to potentially perform OS updates twice in one sitting then that’s just something they may need to deal with. One argument to be made is that if most users keep up to date they should hopefully not run into the situation where they need to perform multiple OS updates like that.


  8. Thank you for this!! I just started testing this and it has been working well. I even used your logic for deferrals, and applied it to a Chrome and Firefox update script as well.


  9. Hi There thank you for the script and pointing us in the right direction. We are getting great results from a logged-in user. However, when testing with no logged-in users the policy never seems to hit the computer.


    1. What’s your policy trigger set to? If the policy is not running at all when no user is logged in, I would make sure your computer has internet connectivity and that the policy is scoped properly to that computer.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s