Handling macOS Software Updates with Jamf Pro

MARCH 31, 2021 EDIT: If you’re reading this, please note that I’m not longer working on this script mentioned in this blog post. I would recommend checking out a new script which I’ve blogged about here: https://babodee.wordpress.com/2021/03/30/handling-major-upgrades-and-minor-updates-for-macos-with-jamf/

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. Number of seconds dialog should remain up for Apple Silicon Macs. Provides opportunity for user to perform update via Software Update preference pane. Default: 1 hour
Parameter 7: Optional. Contact email, number, or department name used in messaging. Default: IT
Parameter 8: Optional. Set your own custom icon. Default is Apple Software Update icon.

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:

Update1.png

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

Update3.pngUpdate4.png

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

Update2.png

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:

Update5.png

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.

March 18, 2021 EDIT: The script has been updated to add support as best possible for Macs on Apple Silicon. Because software updates on Macs on Apple Silicon require user interaction, a command line install cannot be accomplished. The behavior as described above still follows for Macs on Apple Silicon, but diverges once the device has no more deferrals left. At this point, the user will get time (default of 1 hour; you can change it through Jamf script parameters) to perform the update through the Software Update preference pane. If the allowed time has elapsed, the  computer will be shutdown. The rationale here is that if a device cannot be kept up to date then it should not be online. Here is a screenshot of what the message looks like:

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

    Like

    1. Greats guide. Do you know if there is a script that I can execute if the OS installation files is already locally installed? If I’m correct doesn’t it take longer to run the update for user if it being directly downloaded that update screenshot?

      Like

  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.

    Like

    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.

      Like

  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.

    Like

    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?

      Like

    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?

      Like

    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.

      Like

  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!

    Like

  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.

    Like

    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.

      Like

  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.

    Like

    1. Have you checked that the OS requirements are set correctly in Jamf Pro? You’ll find the requirements in Computer Management > Scripts > Your Script > Limitations

      Like

    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/

      Like

      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?

        Like

      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.

        Like

  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

    Like

    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

      Like

    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.

      Like

  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.

    Like

  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.

    Like

    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.

      Like

  10. Really liking this script, thanks for your work on it.

    Have you used it before in conjunction with an Update Deferral profile? At my org, we’re currently using a 60 day deferral for macOS updates. With this setting, the user is blocked from installing the upgrade but running “softwareupdate -l” still picks up the latest 10.15.6 update. Because of this, the script still tells users that they have updates to install, and they go to the Software Update window and see that nothing is available.

    I know this is an Apple/MDM issue and not a problem with your script but do you have any experience dealing with this? Don’t want the script to bug users if they have no way to update.

    Thank you!

    Like

    1. That is a very interesting bug you’ve found. We do not manage the “defer updates” preference with configuration profiles software update payload. I think the appropriate course of action would be to to report this to Apple so that they can fix that behavior.

      Like

  11. I love the script and everything is working for me except the actual update part. After running out of deferrals and being forced to update, the clients seem to just restart without actually installing any updates. Going from 10.15.5 to 10.15.7 I get the following logs in Jamf:

    Script exit code: 0
    Script result: Jamf Helper Exit Code: 0
    Restart Action: Restart
    Shutdown NOW!

    System shutdown time has arrived
    The results of this policy were not logged at the time of execution.

    The machine restarts back to the login window without having run any updates.

    These machines are newer T2 with FV enabled.

    I’m sure I’m missing something but I’m not seeing it.

    Like

    1. Is this happening on more than one computer? What is the output when you run: “sudo softwareupdate -l”? Also do you by any chance have a configuration profile to delay updates? If so, I’ve been told that this might create problems because the command line tool doesn’t quite care about delays and will list any updates that are available.

      Like

  12. Hey, just wanted to say that this is fantastic and works great on all of our Catalina devices!

    Do you have an update that is compatible with Big Sur at all? I was doing some testing and it appears that an update on Big Sur requires accepting a licence agreement and i believe this is where it hangs when trying to force update. The update i was testing on is the 11.2.1 update. I just get a notification saying updates will be installed later tonight and nothing else, the force update screen just hangs on the screen in definently. I strangely also got a prompt to enter user credentials mid way through the process.

    Was wondering if you have experienced the same?

    Thanks!

    Like

    1. I just started doing testing in Big Sur. Not only does `softwareupdate` behave a bit differently in Big Sur. There are also changes to account for with Macs running Apple Silicon. No idea when I’ll finish that work, but I’ll update the script when it’s ready.

      Like

      1. Appreciate the update! I happened to also notice that on Big Sur now being 11.0 instead of what would be 10.16, a different message appears when informing users where to go to download & install updates when the script finds one available:

        ## Verbiage For Messages ##
        # Message to guide user to Software Update process
        if [[ “$OSMajorVersion” -ge 14 ]]; then
        #SUGuide=”by clicking on the Apple menu, clicking System Preferences and clicking Software Update to install any available updates.”
        SUGuide=”by navigating to:
         > System Preferences > Software Update”
        else
        #SUGuide=”by opening up the App Store located in the Applications folder and clicking on the Updates tab to install any available updates.”
        SUGuide=”by navigating to:
         > App Store > Updates tab”
        fi

        Appears that Big Sur hits the else statement of this code. While technically the path is valid, the goal to my knowledge is to lead users to System Preferences>Software Updates where applicable, and the else part of the statement is for any operating systems pre-mojave. Was going to snip this bit out as that wouldn’t apply for my environment, but curious how you would approach it. Thanks so much for your efforts!

        Like

      2. It doesn’t sound like you have the latest version of the script. You should download the latest version of the script. Check back periodically in case the script has been updated.

        Like

  13. If I run “/usr/sbin/softwareupdate -ia –verbose” on my Intel Mac running Big Sur 11.2, the available downloads are downloaded but never installed:

    admin@IMAC ~ % sudo /usr/sbin/softwareupdate -ia –verbose
    Password:
    Software Update Tool

    Finding available software
    Downloading macOS Big Sur 11.2.3

    Downloaded: macOS Big Sur 11.2.3

    To install the update I had to add the -R option (which off course reboots automatically the Mac); /usr/sbin/softwareupdate -ia -R –verbose

    Is there any downside to add this option to your script?
    Thank you for your great work!

    Like

    1. No there isn’t a downside to using the extra -R option for Big Sur on Intel. In fact, I’ve been working on an update that specifically incorporates that change. I just haven’t uploaded it to GitHub yet.

      Like

Leave a reply to babodee Cancel reply