Reboot script with defferal

kadams
Contributor

Hello, and happy new year everyone. Reaching out to you guys about a good reboot script with deferral. Our users here never restart their computers. As of now, its gotten to a point where its horrible.Updates get installed and they need machines to be rebooted. Some people go over a month without a machine reboot. Im looking for a script that will allow a user at least two deferrals. After that it should manually enforce a restart on their machines. So basically, the script runs apple updates etc. After that it checks for updates that require a reboot. If any of those updates are found, it gives a prompt allowing users two deferrals. I know i bug you guys a lot haha. Im really in need of a good linux boot camp.

32 REPLIES 32

lee_smith
Contributor

Looking for something similar.

mm2270
Legendary Contributor III

How often do you want/need to prompt the users to reboot their Mac? You mentioned wanting 2 deferrals, but are those deferrals a day apart? A week apart? A few hours apart? If you plan on using a regular policy to run this, you could use a daily run policy on recurring check-in. That would give them 2 days before the forced reboot. if you needed something more specific, you should mention that since it's relevant. Not all available scripts that do this will be able to accommodate a custom timeframe for the prompt, at least not without some modifications.

As an aside, I worked on a script a long time back that prompted the end user to choose from a few available options to "schedule" the reboot. Meaning they could choose from things like 'immediately' or 4 hours or 8 hours, or whatever you wanted to give them as a few options. It was customizable. When the reboot was imminent, it would show a dialog giving them a final warning that the reboot had been scheduled, and for what time exactly, so they had a final heads up to save any work before the reboot was forced.

In case that's something you'd like to look at, you can find that script here. Just a fair warning - I haven't updated it in some time, so it may not work as originally designed, plus, it uses cocoaDialog to present the options using the "radio button" window style. Since the last beta of cocoaDialog is hard to find now, it may not be best suited for your needs. But it may at least help give you some ideas.

robmorton
Contributor

As I am working on quitting applications now as nicely as possible, this little snippet of code may help you work on something similar. This will basically do a friendly restart allowing the user to save work. If they do not save their work in a time you set in timeout as seconds, a force restart occurs. Technically, it gives each app that time amount and then the actual restart command that timeout amount.

#!/bin/sh

timeout=20 # seconds until restart

niceRestart(){
        osascript -e "tell application "System Events" to set quitapps to name of every application process whose visible is true and name is not "Finder"" -e "repeat with closeall in quitapps" -e "try" -e "with timeout of ${timeout} seconds" -e "quit application closeall" -e "end timeout" -e "end try" -e "end repeat" -e "with timeout of ${timeout} seconds" -e "tell application "Finder" to restart" -e "end timeout"
shutdown -r now
}

niceRestart

So basically, you could prompt the user for a restart. If they say no, put a marker in place. Prompt the for a restart in x days after that. Eventually if the user either clicks the restart button or a max deferral has been hit, your the niceRestart and it will attempt a nice friendly restart for the users willing to help.

If someone knows a way to cleanly quit apps using the shell only, I would love to hear it.

kadams
Contributor

@mm2270 , I just need them to have a deferral that give them x amount of time to perform the reboot. After that time has passed it should force a reboot.

znilsson
Contributor II

I like this deferral script: Better Jamf Policy Deferral

It handles the deferral part really well IMO, and then you can just add whatever reboot method you want via a script, or a files & processes line, or whatever. You kind of have to decide how nice you want to be about quitting the apps for the reboot. If you want to be nice about it, then apps will be asking you if you want to save and that will stall the process. To avoid that, I take a more heavy handed approach and just run a script that quits active processes, and then you can just add

sudo shutdown -r now

to the end of it, or however you want to do it. I feel like it's ok to force quit their apps after giving them the option to defer to a specific time.

#!/bin/sh

# Force quit all non-essential applications

declare -a killPIDs

killPIDs=$(ps axww -o pid,command | grep -v bash | grep [A]pplications/ | grep -v /bin/sh | grep -v [C]asper | grep -v [J]amf | grep -v [S]elf Service | grep -v grep | awk '{print $1}')

# Kill said processes.

for i in ${killPIDs[@]}
do
    echo "Killing PID $i"
    kill -9 $i
done

exit 0

Captainamerica
Contributor II

I am also using this Better Jamf Policy Deferral.
However, the issue is that if the deadline passes, like if the computer has gone to standby etc, and they start the mac again, the launchdeamon will not launch and ask for a restart

kadams
Contributor

@znilsson , for some reason I cant set that up better jamf policy up properly.

znilsson
Contributor II

@kadams Did you go through the instructions here?

  1. Customize variables in the script
  2. Add script to your JSS, set to "Before", and change label for parameter 4 to "Mode (prompt or cleanup)"
  3. Create two policies, one for the initial prompt, one for cleanup, add the script to both
  4. In the prompt policy, set script to Before and put "prompt" in parameter 4 of the script
  5. in the cleanup policy, set script to After and put "cleanup" in parameter 4 of the script
  6. Add whatever actions you want to take as payloads in the cleanup policy.

kadams
Contributor

@znilsson , which policy should run first?. How do i get them to run in the order that they should? Also which policy should have the my install updates or reboot script?

znilsson
Contributor II

@kadams Everything is answered in the read me here: https://github.com/haircut/better-jamf-policy-deferral/blob/master/README.md

The prompt policy should run first. You set a custom trigger for the second policy in the variables section of the script. When the launchagent runs after the deferral, it triggers the second policy using the custom trigger. The second (cleanup) policy should have the payloads for anything you want to do, like install updates or reboot.

jameson
Contributor II

But what happens if the user delay 4 hours and then hibernate the mac and go home from office. The launchdeamon is time has passed when he arrives next morning, so guess it will not start updating ?

NickAn
New Contributor II
New Contributor II

I wrote this script as a deferral replacement, it's definitely not perfect and was written as a one-off. LaunchAgents don't behave the way one would want for this task as jameson pointed out, so they went unused in the final iteration. The script runs as an Ongoing / Recurring Check-In policy scoped to a smart group that needs software updates, while the separate software update policy specified in target_policy_id should be configured ongoing without any set triggers.

kadams
Contributor

@znilsson I have everything set up the way the document describes. When I run the prompt policy, nothing happens. Shouldnt the custom trigger allow the cleanup policy to run after?

dgreening
Valued Contributor II

Man, it would be really nice if built in Jamf functionality worked correctly for policy deferrals....

znilsson
Contributor II

@kadams The prompt policy should run the script with the "prompt" modifier (set in parameter 4 of the script) which should bring up the defer dialog box allowing the user to choose the deferral time.

The custom trigger set in the script is so the script knows which policy to call when the launchdaemon hits the end of the deferral time as specified by the user.

The only thing you should have set in your prompt policy is that script. So if you're not seeing the deferral box when you run that policy, that either means you don't have the script set to run in that policy, or the script isn't running when you run the policy, or you didn't type "prompt" into parameter 4, or something like that.

kadams
Contributor

@znilsson I see the deferral prompt just fine. Once i select an option, nothing else happens. When x amount of time passes, I check logs for policies that ran. I cannot find any logs of the cleanup policy. As of right now, I run the prompt policy and get a defferal prompt. I select the time and nothing happens after that.

znilsson
Contributor II

@kadams OK when you select the option, is it creating the launchdaemon? Should be something like this: /Library/LaunchDaemons/com.contoso.deferred-policy.plist

Did you set all the variables in the Configuration section of the script? Or at least all the ones you want to modify? At the very least, you have to add the name of the custom trigger for the DEFAULT_LD_JAMF_TRIGGER key so it knows which policy to call. And then you also have to make sure that the policy itself (the second "cleanup" one) has that custom trigger set.

kadams
Contributor

@znilsson The launch daemon gets created and its removed after i manually run the second policy. The second policy does not run on its own. Here are some screen shots608f65de39354fd6a25bc7ee97026488
5e978bb475a94d2bb280f102d1711faf
cc7b491fc0884f77b72cf4ca8bc07082
4caca995f4384704810d3bd49c065bcc

stevewood
Honored Contributor II
Honored Contributor II

@kadams Try removing the quotes from the "Custom" trigger in your second policy. Where you have: "execute_install_software_updates" try execute_install_software_updates. The quotes are just for the variable in the script and are not necessary for the custom trigger.

kadams
Contributor

@stevewood , I actually tried that once, I'll do it again and see what happens.

cucaracha
New Contributor III

@kadams , Did you ever get this to work? If so, what were your final settings for both policies?

stevewood
Honored Contributor II
Honored Contributor II

@kadams Ok, I'll admit, I've not played around with @haircut 's script yet, it looks like you might not have to put the trigger under "Jamf_Trigger" (Parameter 6) of your Execution Policy (Install All Software Updates). And, you have an extra quote at the end of that line too even if you did need that.

Have you tried running with that parameter blank?

znilsson
Contributor II

@kadams Yep, no quotes in the trigger field itself. From my script:

DEFAULT_LD_JAMF_TRIGGER = "softwareupdate"

0576210e66f849cf97686d0d3155faec

Everything else looks good based on your other screenshots though, as far as I can tell.

edit - I just noticed you filled out the parameter 6 in the script. Not necessary if you hard code the trigger into the script, like you (and I) did. You would only use that parameter 6 if you are planning to override the hard coded trigger with a different trigger. So since you put the trigger in the script I would say clear out parameter 6, remove the quotes from the trigger name in the policy, and it should work.

gda
Contributor

There is another interesting project "Jamf-Interaction-Toolkit" https://github.com/cubandave/Jamf-Interaction-Toolkit to get deferral, app blocking and all that stuff.

You may ask @cubandave for more details.

Cheers

kdean
New Contributor III

@gda this is awesome, have you played with this?

akamenev47
Contributor II

I have a silly question as I am still pretty new to Python... I am talking about the Better Jamf Policy Deferral script, by the way it's an awesome concept and is working like a charm!

How can I change "Start now" selection prompt to "Restart now" or something different?

The GUI_DEFER_OPTIONS = ["0", "300", "1800", "3600", "14400", "43200", "259200"] takes numbers which determine the amount of seconds it will take before the policy is triggered, but I can't find where it is switched to human readable format and how does "0" become "Start now" lol, anybody knows anything on this?

Ahoy!

mm2270
Legendary Contributor III

@akamenev47 

The reason "0" becomes Start now is because you are telling jamfHelper to "start" after 0 seconds of a delay, which is essentially "Start now" As for why it becomes Start Now, that's just because that's how Jamf coded the application to interpret that 0 seconds option.

As far as switching out that wording as you asked, I'm not sure there's any way to, unfortunately. There are a few things in jamfHelper that are not customizable and hardcoded, and I believe this is one of those items. I also don't like how the wording that shows up in a dialog when you use a timeout option and choose to show the countdown is always "Please make a selection in <time remaining>" I'd like to be able to use that countdown more often, but the wording is not always appropriate to what I'd like to use it for, and it can just cause confusion about what's really going on.

In general, it would be nice if Jamf actually took some time to update jamfHelper with some additional options and refresh it. But given they've not touched it in years now, I'm not sure they ever will issue an update.

I see, that is unfortunate... I wonder if there is already a feature request for jamfHelper in terms of how flexible it is + customization options, if not we should definitely create it.

Ahoy!

mm2270
Legendary Contributor III

I think if you search in the Feature Requests / Ideas section, you'll see there are several requests into Jamf to beef up the capabilities of jamfHelper. Especially when some of the tools we were all using started to be left behind, like cocoaDialog (which amazingly still mostly works on Big Sur today).

Thankfully there are a few up and coming open source tools out there that are starting to fill the gap, but for those people and organizations that shy away from using any open source tools for messaging, it would really be nice if Jamf gave jamfHelper some love. Unfortunately it just doesn't look like they're interested in doing it.

I see. That is unfortunate 😞

Ahoy!

cucaracha
New Contributor III

Hi,

How do I create or find the LD? Thx.

LaunchDaemon label: reverse-domain-formatted organization identifier.
# Do not include '.plist'!
DEFAULT_LD_LABEL = "com.contoso.deferred-policy"
 

cucaracha
New Contributor III

I figured it out with help from JAMF support. I missed inserting the info. in the LaunchDaemon Label field.

Screen Shot 2022-01-27 at 1.39.47 PM.png