Deferral for rebooting?

valkyrie
New Contributor III

Hi guys

I'm trying to get our Macs a bit more up to date and uniform, since they've gone virtually unmanaged for quite a while.

I made a policy to install software updates from Apple's software update server. The restart option is selected to restart if a package or update requires it, and the user gets a restart message with the specified delay before the restart.

Is it possible to give the user the option to delay this restart? For example giving them a message with the choice between 'restart now' and 'restart later' (with a later time specified).
I know I can allow users to defer the policy, but is this possible for the restart as well?

Thanks!

1 ACCEPTED SOLUTION

ChrisCox
New Contributor III

I think it might be better to check if updates require a restart before installing them. If the updates require a restart and there is a user logged in, you could prompt the user to make a choice:

  1. Agree to the restart and install updates
  2. Decline the restart and not install updates

This would also allow you to install updates that do not require a restart without bothering the user. It may require some tweaking depending on exactly what/when/how you want things to happen in your environment. You could install updates, then present the user with a jamfHelper with a timer. You could follow-up on systems after a certain point with a version of this script that does not give them an option to cancel/decline but instead just waits for them to acknowledge that a restart will occur once they click OK. Lots of possibilities.

#!/bin/bash

#---VARIABLES---------------------------------------------------------------------------

JAMFHELPER="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
ICON="/System/Library/CoreServices/Software Update.app/Contents/Resources/SoftwareUpdate.icns"

#---FUNCTIONS---------------------------------------------------------------------------

#---------------------------------------------------------------
# getConsoleUsername
# Returns the current console user. An empty return means no one
# is logged in.
#---------------------------------------------------------------
getConsoleUsername()
{
/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser
user = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]
user = [user,""][user in [u"loginwindow", None, u""]]
print(user)'
}

#---------------------------------------------------------------
# promptRestartMessage
# Prompts user to acknowledge that a restart is required to
# finish installing software updates
#---------------------------------------------------------------
promptRestartMessage()
{
    local _window_type _title _heading _description _button1 _default_button

    _window_type="utility"
    _title="Apple Software Updates"
    _heading="Restart Required"
    _description="Your computer needs to install Apple software updates that require a restart to complete. Please save all work and click Restart."
    _button1="Restart"
    _button2="Cancel"
    _default_button="1"
    _cancel_button="2"

    echo "Prompting user to restart"
    "$JAMFHELPER" 
        -windowType "$_window_type" 
        -title "$_title" 
        -icon "$ICON" 
        -heading "$_heading" 
        -description "$_description" 
        -button1 "$_button1" 
        -button2 "$_button2" 
        -defaultButton "$_default_button" 
        -cancelButton "$_cancel_button"
}

#---------------------------------------------------------------
# displayRestartReminder
# Displays a persistent dialog as a reminder to the user that
# their system will be restarting to install updates soon
#---------------------------------------------------------------
displayRestartReminder()
{
    local _window_type _window_position _title _description

    _window_type="hud"
    _window_position="ur"
    _title="Restart Pending"
    _description="Apple software updates are being installed and your system will restart soon."

    echo "Displaying restart reminder"
    "$JAMFHELPER" 
        -windowType "$_window_type" 
        -windowPosition "$_window_position" 
        -lockHUD 
        -icon "$ICON" 
        -title "$_title" 
        -description "$_description" &
}

#---START SCRIPT------------------------------------------------------------------------

echo "Checking if a restart is required"

# Check if any updates require a restart to complete. The '[restart]' string exists on
# lines for updates that require a restart. The redirect 2>&1 is used to ensure all
# output from the softwareupdate command is sent the same way for the if evaluation
# because softwareupdate uses stderr for some reason for non errors (Don't ask me why).
# If no updates require a restart, all updates will install without user approval.
if [[ "$(/usr/sbin/softwareupdate --list 2>&1)" =~ '[restart]' ]]; then

    echo "Restart is required"

    # Check if a user is logged in to be able to accept or decline the restart.
    # If no user is logged in, the updates will install without user approval.
    if [ -n "$(getConsoleUsername)" ]; then

        echo "A user is logged in"

        # Prompt the user to accept the restart or cancel the updates
        if promptRestartMessage; then

            echo "User accepted restart"

            # Display a window reminding the user that a restart will occur soon
            displayRestartReminder

        # Exit clean if the user chose to not accept the restart
        else
            echo "User did not accept restart"
            exit 0
        fi

    # Log the fact that no user is logged in
    else
        echo "No one is logged in"
    fi

# Log the fact that no updates require a restart
else
    echo "No updates require a restart"
fi

# Install all updates with the --restart flag which will
# restart the system if any updates require a restart
/usr/sbin/softwareupdate --install --all --restart

exit 0

View solution in original post

12 REPLIES 12

davidacland
Honored Contributor II

There is an option to allow the user to defer the policy from running, but I don't think they can defer the reboot once the update is installed.

On an other note, if you have T2 Macs, be careful not to have the Jamf policy send a reboot command. The Mac gets stuck in a loop and won't boot. T2 Macs need to have a shutdown command instead, and they power back on by themselves.

valkyrie
New Contributor III

Good to know! That's mostly the newer Macs, right?
So using the restart option Jamf provides isn't really an option? How bad would it be to have the restart option in the policy set to 'do not reboot', so the user can reboot when possible (but then having to rely on their goodwill). For example after installing a security update, which requires a reboot, but not having the policy reboot.
I've only recently switched to having to manage Mac instead of Windows, so a lot of things I'm still figuring out.

ChrisCox
New Contributor III

I think it might be better to check if updates require a restart before installing them. If the updates require a restart and there is a user logged in, you could prompt the user to make a choice:

  1. Agree to the restart and install updates
  2. Decline the restart and not install updates

This would also allow you to install updates that do not require a restart without bothering the user. It may require some tweaking depending on exactly what/when/how you want things to happen in your environment. You could install updates, then present the user with a jamfHelper with a timer. You could follow-up on systems after a certain point with a version of this script that does not give them an option to cancel/decline but instead just waits for them to acknowledge that a restart will occur once they click OK. Lots of possibilities.

#!/bin/bash

#---VARIABLES---------------------------------------------------------------------------

JAMFHELPER="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
ICON="/System/Library/CoreServices/Software Update.app/Contents/Resources/SoftwareUpdate.icns"

#---FUNCTIONS---------------------------------------------------------------------------

#---------------------------------------------------------------
# getConsoleUsername
# Returns the current console user. An empty return means no one
# is logged in.
#---------------------------------------------------------------
getConsoleUsername()
{
/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser
user = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]
user = [user,""][user in [u"loginwindow", None, u""]]
print(user)'
}

#---------------------------------------------------------------
# promptRestartMessage
# Prompts user to acknowledge that a restart is required to
# finish installing software updates
#---------------------------------------------------------------
promptRestartMessage()
{
    local _window_type _title _heading _description _button1 _default_button

    _window_type="utility"
    _title="Apple Software Updates"
    _heading="Restart Required"
    _description="Your computer needs to install Apple software updates that require a restart to complete. Please save all work and click Restart."
    _button1="Restart"
    _button2="Cancel"
    _default_button="1"
    _cancel_button="2"

    echo "Prompting user to restart"
    "$JAMFHELPER" 
        -windowType "$_window_type" 
        -title "$_title" 
        -icon "$ICON" 
        -heading "$_heading" 
        -description "$_description" 
        -button1 "$_button1" 
        -button2 "$_button2" 
        -defaultButton "$_default_button" 
        -cancelButton "$_cancel_button"
}

#---------------------------------------------------------------
# displayRestartReminder
# Displays a persistent dialog as a reminder to the user that
# their system will be restarting to install updates soon
#---------------------------------------------------------------
displayRestartReminder()
{
    local _window_type _window_position _title _description

    _window_type="hud"
    _window_position="ur"
    _title="Restart Pending"
    _description="Apple software updates are being installed and your system will restart soon."

    echo "Displaying restart reminder"
    "$JAMFHELPER" 
        -windowType "$_window_type" 
        -windowPosition "$_window_position" 
        -lockHUD 
        -icon "$ICON" 
        -title "$_title" 
        -description "$_description" &
}

#---START SCRIPT------------------------------------------------------------------------

echo "Checking if a restart is required"

# Check if any updates require a restart to complete. The '[restart]' string exists on
# lines for updates that require a restart. The redirect 2>&1 is used to ensure all
# output from the softwareupdate command is sent the same way for the if evaluation
# because softwareupdate uses stderr for some reason for non errors (Don't ask me why).
# If no updates require a restart, all updates will install without user approval.
if [[ "$(/usr/sbin/softwareupdate --list 2>&1)" =~ '[restart]' ]]; then

    echo "Restart is required"

    # Check if a user is logged in to be able to accept or decline the restart.
    # If no user is logged in, the updates will install without user approval.
    if [ -n "$(getConsoleUsername)" ]; then

        echo "A user is logged in"

        # Prompt the user to accept the restart or cancel the updates
        if promptRestartMessage; then

            echo "User accepted restart"

            # Display a window reminding the user that a restart will occur soon
            displayRestartReminder

        # Exit clean if the user chose to not accept the restart
        else
            echo "User did not accept restart"
            exit 0
        fi

    # Log the fact that no user is logged in
    else
        echo "No one is logged in"
    fi

# Log the fact that no updates require a restart
else
    echo "No updates require a restart"
fi

# Install all updates with the --restart flag which will
# restart the system if any updates require a restart
/usr/sbin/softwareupdate --install --all --restart

exit 0

valkyrie
New Contributor III

Oh wow, thanks so much for the script! I'll be testing it out next week, but from what I read, it's exactly what I need!

valkyrie
New Contributor III

@ChrisCox I've been testing the script, and it seems to work fine, thanks!
Just one more question about it:

If the software update requires rebooting, it gives the user the prompt informing them. After they agree to the reboot, the update starts downloading and installing. For a bigger update, this can take quite some time. Is there any way to download first, and then prompt the user for installation/reboot?

ChrisCox
New Contributor III

Yes, you could just add the following line before prompting.

/usr/sbin/softwareupdate --download --all

valkyrie
New Contributor III

Oh wow yes, silly I didn't think of that myself. Thanks for the help!

ChrisCox
New Contributor III

I thought I should update this with something I just discovered. In Catalina, updates that require a reboot no longer have the [] surrounding them. In the if regex evaluation, [restart] should be changed to just restart to be compatible with Mojave and Catalina.

valkyrie
New Contributor III

Thanks @ChrisCox ! I'd been seeing some issues with this policy in Catalina.
I have changed the if regex evaluation, but the main issue still exists. On the Catalina devices however, the prompt to reboot now/later doesn't appear anymore and the device just starts rebooting. I haven't had time to look into this properly, but I'm hoping to find some time for it this week.

jameson
Contributor II

Exact what I am looking for - but any support for Catalina at the moment ?

igarcia
New Contributor II

@ChrisCox
I tried it on Big Sur, and it did run but didn't notice any of the prompts. Thoughts?

Thanks for the awesome script though!

pete_c
Contributor III

You might want to take a look at: https://github.com/mpanighetti/install-or-defer