macOS Monterey 12.3 removes the Python 2 runtime historically bundled with the operating system. Better Jamf Policy Deferral previously relied on that "system" Python installation.
You must now install your own Python 3 runtime. I strongly recommend the "macadmins Python" distribution.
Better Jamf Policy Deferral has been updated for Python 3 compatibility, and
expects that you're using macadmins Python. The shebang points to
/usr/local/bin/managed_python3
. If you're installing your own Python 3 runtime
elsewhere, be sure to update the script accordingly.
Sometimes, with Jamf Pro, you need to give your users the option to delay the execution of a policy until a more convenient time. Typically, this policy might involve a reboot or some system change that would interrupt a user and present an annoyance during their work day.
The JSS provides built-in policy deferall options under the "User Interaction" tab in a policy's configuration (see the docs on "User Interaction in JSS v9.9x).
In use, it looks like this:
Maybe your users understand what a "management task" is or can somehow divine what "id:264" might do to their Mac, or why they might choose a time to start the task. Mine cannot. No options are available to customize the verbiage or presentation.
Further, you must specify a hard deadline date by which the policy must run; there's no way to specify a "floating" deadline. If a computer falls into the scope of a deferral-enabled policy after the deferral deadline, the user is never presented the choice to delay execution.
Long story short, the built-in deferral is inflexible.
Enter Better Jamf Policy Deferral.
As an important consideration, be aware that if the system is off (i.e. the Mac is shut down) at the time a deferred action is scheduled to run, the action will not run when the system is turned back on.
This is a limitation of launchd
jobs.
If you schedule a
launchd
job by setting theStartCalendarInterval
key and the computer is asleep when the job should have run, your job will run when the computer wakes up. However, if the machine is off when the job should have run, the job does not execute until the next designated time occurs.
I am aware of the potential issue this creates but have not yet developed a suitable workaround. I am open to any suggestions, though! Open an issue or better yet, a pull request if you have ideas.
Why do you want to allow a policy's action(s) to be postponed?
The only acceptable answer is "because those actions present a burdensome interruption for the user, but are required."
Some examples are:
You should not bloat the user's experience by presenting them the option to delay every management action you perform. That's an illusion of choice. Instead, design your management strategy to be as non-invasive as possible, reserving policy deferrals for very, very few situations.
Limit yourself to only a couple policies with deferrals enabled. Do not set every policy to allow deferral because it looks – on the surface – to provide your users with "control" or autonomy.
Better Jamf Policy Deferral (BJPD) is a Python script that uses the built-in
jamfHelper
tool to present your user a customizable GUI allowing them to
postpone execution of a policy to a more convenient time.
Behind the scenes, BJPD writes an on-the-fly LaunchDaemon configured to call a custom policy trigger at the time selected by the user.
To better illustrate the workflow, this guide explains requiring a user to install all available Software Updates.
better-jamf-policy-deferral.py
, modifying the variables as you
require for your environment. Variables are well-commented so I won't rehash
them here.better-jamf-policy-deferral.py
to your JSS under Settings > Computer
Management > Scripts. The script should have a Priority of "Before." Set the
Parameter Label for Parameter 4 to "Mode (prompt or cleanup). Configure the
Parameter Label for Parameter 5 as "LaunchDaemon Label." Set the Parameter
Label for Parameter 6 to "Jamf Trigger." These optional parameters will allow
you to override the defaults you set in the script at runtime.BJPD requires two separate policies. A "prompt" policy presents the GUI and handles creating a LaunchDaemon to execute your desired actions at a later time. An "execution" policy actually executes your actions, then cleans up after itself.
LD_JAMF_TRIGGER
variable you set in better-jamf-policy-deferral.py
(or
that you specify as a parameter value in your "prompt" policy).better-jamf-policy-deferral.py
script, set to run "After" policy actions. Set Parameter 4 – the "Mode"
parameter – to "cleanup". If you've used a custom LaunchDaemon label be sure
to pass that value as parameter 5 of the script.better-jamf-policy-deferral.py
script. Set the script to run "Before" other policy items, and configure the
parameters to your needs. The default "Mode" is "prompt" but you can set it
here for completeness.Even if your user chooses to start the policy "now," BJPD will still write a
LaunchDaemon. In this case, the LaunchDaemon is written with the RunAtLoad
key
instead of a future-dated StartCalendarInterval
key. This ensures the
"execution policy" called by the custom trigger is properly queued up, and the
"prompt policy" can complete its execution.
The BJPD workflow allows you to specify a list of "blocking apps" – a la Munki – that, if running, will cause the process to exit silently.
This is useful for...not angering your users. For instance, if a professor or sales rep is doing a Keynote presentation, you don't want to interrupt by throwing your GUI on screen.
App names listed in the BLOCKING_APPS
list in better-jamf-policy-deferral.py
will be checked to see if they're running prior to any GUI elements appearing
on screen.
The default list contains the two most common slide presentation apps:
BLOCKING_APPS = ['Keynote', 'Microsoft PowerPoint']
Edit the list to remove apps, or add apps that should additionally halt the display of GUI elements.
Be sure to test any new blocking apps you add to ensure they work as expected.
Note: This is a "rough" check that cannot detect if, for instance, Keynote is in full-screen presentation mode vs. simply open and running. A user could indefinitely delay execution of the policy if they leave a blocking app open all the time. In my environment, I'd rather be safe than receive the angry phone call. If you know a better way, fix it and send a pull request!
For deferral "Prompt" policies, I set the policy frequency to "Ongoing." This will cause the script policy to execute multiple times if a user chooses to defer it past the next recurring check-in. BJPD does, however, check for the existence of a deferral LaunchDaemon on the client prior to displaying any GUI elements, so the user will not see the GUI multiple times.
Please open an issue on this repository if you have questions.