Schedule Restart - Best Way?

betty02
New Contributor II

People talk about LaunchDeamons - Never touched them so no idea how the work or how to deploy one! Basically we have a static group of machines for our meetings rooms that we want to restart at 4am on a Sunday morning ready for Monday morning, how would I be best to script this and deploy it so the reboot then?

Thanks

18 REPLIES 18

thoule
Valued Contributor II

You can do this task with either a launchDaemon, or with a JSS task.

To use the JSS, create a policy and set some client side limitations - to run only on Sunday between 3 and 4 am. Then I would set Execution Frequency to once daily. Trigger should be 'check in'. Under Files and Processes, type 'reboot' in Execute Command. And obviously set your scope.

To use a LaunchDaemon, here is an example that will reboot the computer at 3:10am every Monday morning. Under Weekday, 0 and 7 are Sunday. Missing keys are wildcards. (https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/launchd.plist.5.html#//apple_ref/doc/man/5/launchd.plist). Change edu.company to your domain name and save the file as edu.company.reboot.plist

<?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>edu.company.reboot</string>
        <key>ProgramArguments</key>
        <array>
                <string>reboot</string>
        </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>3</integer>
        <key>Minute</key>
        <integer>10</integer>
        <key>Weekday</key>
        <integer>1</integer>
    </dict>
</dict>
</plist>

Put that file in /Library/LaunchDaemons and reboot. Make sure permissions are root:wheel (chown root:wheel /Library/LaunchDaemons/edu.company.reboot.plist. You should also do your saving with a text editor like TextWranger so no garbage characters are thrown in there (dont use TextEdit).

Good luck!

ShaunRMiller83
Contributor III

LaunchDaemons and scripts could certainly accomplish this task and depending no your environment maybe they are needed. I think the easiest way to accomplish what you described would be thru a policy in the JSS.

1) In the general tab set your trigger and frequency. I would probably set it to check in and once a week or ongoing since you'll be restricting this policy with client side limitations. 2) Then under client side limitations set the days and time that you don't want this policy to run. 3) Setup your reboot settings under restart options. 4) Then under scope select your static group.

Once you save the policy you should be good to go. I would recommend testing this on a subset of systems before rolling this out but it should be fairly easy and straight forward.

Araneta
New Contributor III
#!/bin/bash
echo "<?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>com.org.shutdown</string>
   <key>UserName</key>
   <string>root</string>
<key>Program</key>
<string>/sbin/shutdown</string>
<key>ProgramArguments</key>
<array>
    <string>/sbin/shutdown</string>
    <string>-r</string>
    <string>now</string>
</array>
<key>StartCalendarInterval</key>
<dict>
    <key>Weekday</key>
    <integer>7</integer>
    <key>Hour</key>
    <integer>4</integer>
    <key>Minute</key>
    <integer>00</integer>
</dict>
</dict>
</plist>" > /Library/LaunchDaemons/com.org.shutdown.plist

chown root "/Library/LaunchDaemons/com.org.shutdown.plist"
chmod 644 "/Library/LaunchDaemons/com.org.shutdown.plist"
launchctl load -w "/Library/LaunchDaemons/com.org.shutdown.plist"

Here's a complete script that will restart your machines every Sunday at 4:00am. You can deploy this as is.
Thanks to @Abdiaziz for helping me with this the last time I have the same query.

betty02
New Contributor II

@Araneta Is this a restart script or just a shutdown script? Looks like many shutdown works and no restart words to me haha!

Aziz
Valued Contributor

@betty02 The script @Araneta posted is a restart script.

betty02
New Contributor II

Excellent. Sent the script with a different time manually through casper remote, will this script now sit on the machine and run itself every Sunday? I don't need to send it each week do I?

Araneta
New Contributor III

Yes, that's correct. The machine will automatically restart itself every Sunday and no need to re-deploy.
You can check if the launchdeamon is running by "launchctl list" command, if you see com.org.shutdown in there then you're all good.

betty02
New Contributor II

Ok, tried it yesterday and it didn't work it just did;t restart! Will try and re-deploy it today and have a play for sure!!

bheitzig
New Contributor II

Does the restart script work if the machine is sleeping?

Nix4Life
Valued Contributor

Nope that is the catch, the machine has to be awake. Check out caffeinate to keep it awake so that you can shut it down (say what now)

LS

mm2270
Legendary Contributor III

Meant to post something regarding the above some days ago, but there is an issue with the script posted by @Araneta. The echo command won't work to create a valid plist file because its using double quotes for the echo, but the plist header itself contains double quotes that aren't being properly escaped.

To fix this, you can do one of two things. You can switch to single quotes for the open and close of the echo command like this:

#!/bin/bash
echo '<?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>
....... (rest of plist)
</plist>' > /Library/LaunchDaemons/com.org.shutdown.plist

Or, you can continue to use the double quotes with echo, but go through and escape any double quotes within the plist contents, like so:

#!/bin/bash
echo "<?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>
....... (rest of plist)
</plist>" > /Library/LaunchDaemons/com.org.shutdown.plist

Note the backslashes in front of any double quote marks.

Just a note. The way the script is posted, it will actually create a file, so it won't report an error, but all the double quotes in the header will be missing, which makes it an invalid launchd plist. You can verify an xml plist is valid a few different ways. Here's just one way:
xmllint --format /path/to/file.plist You'll see a list of parser errors when you run it if there are problems. If its OK it prints the formatted plist file.

Hope that helps.

Snickasaurus
Contributor

First off thanks for the post @betty02 and the script @Araneta and the headsup @mm2270 . My version is as follows. Any thoughts on using cat vs echo?

#!/bin/bash

# Variables
thePlist="/Library/LaunchDaemons/com.org.shutdown.plist"

# Begin script
cat > $thePlist <<EOF
<?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>com.org.shutdown</string>
   <key>UserName</key>
   <string>root</string>
<key>Program</key>
<string>/sbin/shutdown</string>
<key>ProgramArguments</key>
<array>
    <string>/sbin/shutdown</string>
    <string>-r</string>
    <string>now</string>
</array>
<key>StartCalendarInterval</key>
<dict>
    <key>Weekday</key>
    <integer>7</integer>
    <key>Hour</key>
    <integer>4</integer>
    <key>Minute</key>
    <integer>00</integer>
</dict>
</dict>
</plist>
EOF

chown root $thePlist
chmod 644 $thePlist
launchctl load -w $thePlist

luke_jaeger
Contributor

Here's my solution -- no LaunchDaemons required:

  1. Prepare two scripts -- both one-liners. (You could combine them, but there may be other situations where you want to use one and not the other.

(a) first script: call it "_log out current user instantly". And that's exactly what it does ... no user interaction, no dialog box, no chance for user to save their work, just blam, logout. Set the script's priority to "before". (I also put the underscore character in the name of the script, just to make extra-double-sure it runs first)

#!/bin/bash
/usr/bin/pkill loginwindow

(b) second script: call it "immediate reboot", set priority to "after"

#!/bin/bash
/sbin/reboot

2. Create a policy called "Nightly reboot" that runs both of these scripts
3. Scope the policy to run at check-in, once a day, on your target machines
4. Here's the important and slightly counter-intuitive part: click on General --> Client-Side Limitations
Do Not Run Between:
[4:30 am] to [4:00 am] .... or whenever you want your nightly reboot to happen, but make sure that:
(a) the later 'stop' time is in the first set of popups, the earlier 'start' time in the second set
(b) the time window between 'start' and 'stop' is longer than your check-in period, otherwise some of the clients may miss it. In this example I have a 30 minute window for reboots; my check-in period happens to be 20 minutes.

Remember that you're telling the JSS when not to run the policy. If you get (a) backwards, it will run all day except during the 4:00 to 4:30 am window. This is almost certainly not what you want.

This is better than a LaunchDaemon, because LaunchDaemons are a pain.
It's better than scheduling using pmset, because that only lets you schedule a shutdown OR a poweron, not both (and not a restart)
It's better than using Casper's 'restart options' because if you're using the Guest account, it always seems to hang at the "If you log out, your files will be deleted" dialog.

luke_jaeger
Contributor
 

luke_jaeger
Contributor

This has been working great, and it's the only reliable method I've found to make a nightly reboot happen all the time. Only problem is that it never shows up in the JSS as "Completed", because the hard reboot happens before the policy exits. Which means that the reboot may happen more than once a night, depending on how many check-in periods there are during the "Run Between" window. Probably nobody will ever notice this since I have it scheduled between 3 and 4 am.

While it's easy enough to check that it worked by sending the "uptime" command to the clients via ARD, it would be nice if the policy actually logged completion.

mm2270
Legendary Contributor III

@luke.jaeger Why not add a time delay for the reboot (using shutdown -r instead of reboot) and push it to the background, allowing the policy to "complete" and upload a log to Casper. For example:

/sbin/shutdown -r +3 &

This should allow the policy to finish up, sending a log back to Casper so it will show as "Complete" and then within 3 minutes, the Mac reboots. Just a thought.

mhollands
New Contributor II

Require a scheduled restart and certain applications wont close, this may help.

This worked with 2 lines only.

Scheduled Client-Side Limitations Do Not Run Between: (working hours).

This helped close force Google Chrome and a web page containing Javascript as this was preventing the mac to not shut down. I set the delay to 3 mins.

5b726741eb814b63ad6d7bd399faef5a

Client-Side Limitations
Do Not Run Between:
7:00 am] to [8:00 pm] ....

!/bin/bash

/usr/bin/pkill killall Google Chrome
/sbin/shutdown -r +3

msmith80
New Contributor III

I have found (especially in a lab environment) that policies tend to get stuck, more often than they should with JAMF. Therefore, new policies won't ever push out. Using a policy to reboot may never get completed if other policies are stuck. Scheduling it locally works a lot better for us, that way we aren't depending on JAMF to handle it.