Scheduled Reboot via plist and script

sanbornc
New Contributor III

I know this topic has been covered a few times before but I need to schedule a reboot to install updates once a month on a specific day and time and I was told the only way to do this was via a plist and script. I have written a plist via Lingon that I have in my Launch Agents that runs once a month on the 30th of every month at a specific time that references a reboot script that I have in the Users/Shared folder called forcereboot.sh. When I run the reboot script from Users/Shared on its own it runs fine. Right now the plist runs as it should, and reschedules itself for the next month, but doesn't seem to run the script. This is the plist located in Launch Agents. I have also tried running this as root in the Launch Deamons and issue persists. (This has a different time listed for testing purposes)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin</string> </dict> <key>Label</key> <string>com.local.forcereboot</string> <key>ProgramArguments</key> <array> <string>/Users/Shared/forcereboot.sh</string> </array> <key>RunAtLoad</key> <false/> <key>StartCalendarInterval</key> <array> <dict> <key>Day</key> <integer>9</integer> <key>Hour</key> <integer>9</integer> <key>Minute</key> <integer>30</integer> </dict> </array> <key>WorkingDirectory</key> <string>/Users/Shared/forcereboot.sh</string>
</dict>
</plist>

This is the script located in Users/Shared

!/bin/sh

/usr/local/jamf/bin/jamf displayMessage -message "Your Mac will reboot in 90 seconds to install necessary system updates."
sleep 90
softwareupdate --install --all
shutdown -r now

The plist runs fine, as its displayed in console and reschedules itself for next month, but nothing happens. The script doesn't run. No message comes up. The system doesn't reboot. Any idea what's going on?

11 REPLIES 11

sanbornc
New Contributor III

@stevewood I saw you spoke about this in an earlier post HERE. What Im doing is similar and bit less complex.

mm2270
Legendary Contributor III

I think the problem is using a LaunchAgent. The commands in your script, specifically the softwareupdate --install --all must be performed with root privileges, which a LaunchAgent can't do. Those run as the current user, so they don't have elevated privileges by default.

As for the message not showing up, its the same issue. The jamf binary has to be called as root, even when using the displayMessage flag believe it or not.

You'll likely have to move this all over to a LaunchDaemon and change the script a bit to get some things to work correctly.

stevewood
Honored Contributor II
Honored Contributor II

@sanbornc

Good gracious that was old. :-) I would check the script to make sure it is showing up with execute privs.

Also, I would change the softwareupdate call to use the --restart flag, especially for T2 systems as that will properly shutdown systems when a BridgeOS update is being applied. So use softwareupdate --install --all --restart or softwareupdate -iaR will do the same.

sanbornc
New Contributor III

Thanks Everyone! @mm2270 I moved the plist to Launch Daemons and ran it as root and now it's working. I now have got a mostly working script/plist combination! Just a few more questions I was hoping you could help me with. @stevewood The issue now is that the Reboot message is coming up for users who don't even have updates available to install. This causes confusion when users come back to their machines and see a strange message that doesn't apply to them, and it also causes the messages to stack so the users has to close tons of reboot messages if there hasn't been a reboot-able update recently. Any idea how I would be able to do a If-Then kind of script? Like, IF there are updates available for your Mac, THEN display the message, IF there are no updates available for your Mac then don't do anything.

stevewood
Honored Contributor II
Honored Contributor II

@sanbornc

You'll need to use some sort of logic (if...then for example) to test if the list of updates contains a reboot or shutdown. If it does, then do X, if it does not then do Y.

This post has some examples:

A Nicer Software Update Tool

The caution I would have is that for the restart/shutdown case, make sure you're letting the binary do the work: softwareupdate -iaR will do the trick.

sanbornc
New Contributor III

Thanks for the help @stevewood !
After some messing around and copying and pasting I came up with this script that checks to see if there are updates before it actually announces anything to the user or tries to do anything. If there are no updates it just quits and does nothing. This script is being called on by a plist I have in the Launch Daemons that launches on the 1st of every month. Im about to start testing now but wanted to get your thoughts

#!/bin/sh
#make sure log directory exists
if [ ! -d "/Library/Application Support/OCIO" ]; then
                mkdir "/Library/Application Support/OCIO"
fi
#set log file location to log outcome of operation and write the current time
logfile="/Library/Application Support/OCIO/forcereboot_`date +%Y-%m-%d`.log”
echo `date +%H:%M:%S` >> $logfile
#Check for updates
updatecheck=`softwareupdate -l`
if [[ $updatecheck == *"Software Update found the following new or updated software:"* ]];
then
                echo "Installing Updates." >> $logfile
                /usr/local/jamf/bin/jamf displayMessage -message "Your Mac will reboot in 90 seconds to install necessary system updates.  Please save all work and quit applications now."
                sleep 90
                softwareupdate -iaR >> $logfile
elif [[ $updatecheck == *"No new software available."* ]];
then
                echo "No updates found that require restart" >> $logfile
                exit 0
else
                echo “Script failed to match on any string” >> $logfile
                exit 0
fi

endor-moon
Contributor II

Interesting stuff... I do something similar to reboot my Mac lab machines and run a clean-up script once per week, but I have a launchdaemon and my script is in /Library/AdminToolBox and only root can execute or read it, which seems to work fine. (I used to use /Library/Management but some other software started using that path.)

sh-3.2# cat ca.mycollege.reboot-warn.plist (where you fill in your institution in place of ca.mycollege)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>ca.mycollege.reboot-warn</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/AdminToolBox/reboot-warn.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>5</integer>
        <key>Minute</key>
        <integer>55</integer>
    </dict>
</dict>
</plist>

#!/bin/sh

# Abort operation if no one is logged in.

    if [ `who | grep -c console` != "0" ]
    then
# Warn the logged in user.
# Play our audio file. Not sure this works anymore. We use High Sierra still.
/usr/bin/afplay /Library/AdminToolBox/wakeup2.aiff

result=`
osascript -e 'beep 2'`

result=`
osascript -e 'set volume 45'`
# Yes, and Zarvox is no longer installed by default, which is annoying. Not sure if this code works either.
say -v Zarvox "Alert. Restart will occur at 5:00 AM. Please save your work and log out."
sleep 1
result=`
osascript -e 'tell application "Finder"' -e "activate"
         -e "display alert "Automatic restart will occur at 5:00 AM."
        message "Please save your work and logout immediately to avoid loss of open documents. The automatic restart will happen even if you have open documents that have not been saved."
         buttons {"OK"} as warning giving up after 48" -e 'end tell'`

        exit 0        
    fi
exit 0

sh-3.2# cat /Library/AdminToolBox/reboot.sh 
#! /bin/sh
/bin/sync
/bin/sync
/sbin/shutdown -r now
exit 0

I know I need to do a lot of updating here. Please jump in and let me know of anything that may be blindingly obvious that I'm missing, folks, thanks.

Cheers...

stevewood
Honored Contributor II
Honored Contributor II

@sanbornc

Check the closing quote on the logfile= line. It's not a regular quote mark so it is causing the other lines to appear as comments. At least in the post it is.

Also, I would give your users longer than 90 seconds. What happens if they've stepped away from their computer and left documents open? You've now restarted their computer without giving them an opportunity to save their work. We give the users 90 minutes just in case they're at lunch when we pop the dialogs.

Otherwise it looks fine.

sanbornc
New Contributor III

Hello all! Does anyone know how I can find a complete list of all the possible responses from Software update when the

softwareupdate -l

command is run? Im trying to include all responses in a script with if then statements and need to find a list of all possible responses. So far I have:
"No new software available"
"Installing updates."

sanbornc
New Contributor III

@stevewood I seem to be having an issue with my script where even in situations where "No new software available." is returned, the script still skips to the end and writes "Script failed to match any string". Im not sure why this is happening. It should be writing "No new software available". I can't figure out where I went wrong in the script. Any idea's?

#!/bin/sh
#make sure log directory exists
if [ ! -d "/Library/Application Support/OCIO" ]; then
                mkdir "/Library/Application Support/OCIO"
fi
#set log file location to log outcome of operation and write the current time
logfile="/Library/Application Support/OCIO/forcereboot_`date +%Y-%m-%d`.log"
echo `date +%H:%M:%S` >> $logfile
#Check for updates
updatecheck=`softwareupdate -l`
if [[ $updatecheck == *"Software Update found the following new or updated software:"* ]];
then
                echo "Installing Updates." >> $logfile
                /usr/local/jamf/bin/jamf displayMessage -message "Your Mac will reboot in 5 minutes to install necessary system updates.  Please save all work and quit applications now."
                sleep 300
                softwareupdate -iaR >> $logfile
elif [[ $updatecheck == *"No new software available."* ]];
then
                echo "No updates found that require restart" >> $logfile
                exit 0
else
                echo "Script failed to match on any string" >> $logfile
                exit 0
fi

stevewood
Honored Contributor II
Honored Contributor II

@sanbornc

Take the spaces out between the string and the equal signs:

elif [[ $updatecheck=="No new software available." ]];

Also, the easiest way to test is to strip everything out and run just the list and the check for no software on a machine that has no updates waiting:

#!/bin/sh

updatecheck=`softwareupdate -l`
if [[ $updatecheck==*"No new software available."* ]];
then
                echo "No updates found that require restart"
                exit 0
else
                echo "Script failed to match on any string"
                exit 0
fi

That way you can mess around with the tests.