Policy Execution Order

kadams
Contributor

Hello everyone, hope you all are well. I would like to get policies to execute in order. I would like one policy to run last no matter what. I have been working on this huge project with DEP Notify. I made a post about it a little while ago. Do you guys know how to get policies to run in a specific order?.

21 REPLIES 21

alexjdale
Valued Contributor III

They are executed in alphabetical order (when all else is equal), so name them appropriately.

ryan_ball
Valued Contributor

Call each policy individually based on a custom trigger, this way you can run the policies in whatever order you'd like.

ryan_ball
Valued Contributor

kadams
Contributor

I just want the policies I have to run in the order that I want. They are running during enrollment. Is it necessary to make scripts and costume triggers?. I would like to avoid that if possible.

el2493
Contributor III

Agree with both @alexjdale and @ryan.ball. Any policy I absolutely need to run last I name something like "zzzRestart Computer", or for policies that run on Enrollment I name "001 - Do first thing", "002 - Do second thing." I also have scripts I use for provisioning (to install a bunch of different apps) that call policies based on custom triggers (install_adobeacrobatreaderdc, install_firefoxesr), and that works really well since in the script you write down the order in which you're triggering them.

kadams
Contributor

@el2493 I tried the numbering system and it didn't work. I have policies that run on enrollment. I want them to run in a specific order. I tried putting things like 1-Policy Name, 2- Policy Name, and so on. That didn't work. The policies seemed to have run in alphabetical order

ryan_ball
Valued Contributor

By process of elimination you are left with this naming scheme:
"e01 - Policy One"
"e02 - Policy Two"
"e03 - Policy Three"

el2493
Contributor III

@kadams can you give an example of how they run (in what specific order, and with at least an estimation of what the Policy names are)? Adding 001, 002, etc. to the names of my Policies does run them in alphabetical order, starting with the numbered Policies. So, for example, on enrollment the Policies that run for me are:

001 NTP and Location Service 002 CocoaDialog 003 Department Assignment 004 Prompt for Hostname and Bind to AD DockUtil Enable SSH

The ones that are numbered run first, then the ones that aren't numbered run alphabetically.

mm2270
Legendary Contributor III

I wouldn't rely on the naming convention. You may get inconsistent results that way. It should always work in theory, but in the real world, it may not do what you want. The most reliable way is to use a script to call the policies in the order you want them to run in.
And BTW, it's not strictly necessary to use custom triggers (though it should work better that way) You can also use the policy IDs. Just remember not to have any triggers selected.
Also remember that scope overalls all. Even with custom triggers or calling a policy directly by the ID, if the machine isn't in scope for the policy, it won't run.

kadams
Contributor

@el2493 Here are my policies after putting alphabets next to them. I originally had them with numbers 1 and so on before them.4f882a99cb624cf2ab6fc56ca387f392

el2493
Contributor III

@mm2270 has helped me out a lot in the past (both answering my personal questions and also just seeing his answers to other questions all over this website), so I would usually go with what he recommends. Alphabetical works consistently for me, but scripting is definitely foolproof when it comes to running things in a specific order. It could be something as simple as using a script like this in a Policy and having this be the only Policy that runs on enrollment:

#!/bin/bash -v

# Inspired by rtrouton's custom trigger script
# https://derflounder.wordpress.com/2017/04/08/running-multiple-jamf-pro-policies-via-custom-trigger/

# This script manually executes policies by id numbers or custom triggers

CheckBinary (){

# Identify location of jamf binary.

jamf_binary=`/usr/bin/which jamf`

 if [[ "$jamf_binary" == "" ]] && [[ -x "/usr/sbin/jamf" ]] && [[ ! -x "/usr/local/bin/jamf" ]]; then
    jamf_binary="/usr/sbin/jamf"
 elif [[ "$jamf_binary" == "" ]] && [[ ! -x "/usr/sbin/jamf" ]] && [[ -x "/usr/local/bin/jamf" ]]; then
    jamf_binary="/usr/local/bin/jamf"
 elif [[ "$jamf_binary" == "" ]] && [[ -x "/usr/sbin/jamf" ]] && [[ -x "/usr/local/bin/jamf" ]]; then
    jamf_binary="/usr/local/bin/jamf"
 fi
}

# Run the CheckBinary function to identify the location
# of the jamf binary for the jamf_binary variable.

CheckBinary

# Install software
# $jamf_binary policy -id [policy id number] or -trigger [trigger] for each

#First Policy
$jamf_binary policy -id [ID number of first Policy]
#Second Policy
$jamf_binary policy -trigger [custom trigger of second Policy, if you want to use custom triggers]
#Third Policy
$jamf_binary policy -id 12
#Fourth Policy
$jamf_binary policy -trigger installadobe
#Fifth Policy [etc.]

exit 0

You can use all -id, all -trigger, or mix them if you want. You can get the ID number of the Policy by opening it in the JSS and looking at the URL, which should end in something like "policies.html?id=577&o=r" (so the ID number of that Policy is 577)

mm2270
Legendary Contributor III

Here's a script that can take a string of either policy IDs or the custom triggers, separated by spaces, pass them to the script and run them in the order received. The script determines if it received an ID or custom trigger and runs the appropriate command. Using a script like this means you don't have to modify the script, just the parameter you pass to it. The same script can be used for different types of setups.

#!/bin/bash

## Populate parameter 4 with the policy IDs or their custom triggers
## Add them in the exact order (first to last) that you want them to run in

## Check to make sure we received at least one item in parameter 4
if [ -z "$4" ]; then
    echo "No items were passed to parameter 4. Add at least one or more policy ids and/or custom triggers to it for this script to work."
    exit 1
fi

## Add Param 4 to a POLICY_IDS array
POLICY_IDS=($4)

## Establish a pattern to check for integer or standard string
patt='^[0-9]+$'

## Loop over the IDS/triggers and...
while read POLICY_ID; do
    ## check each to see if it's an integer or a string
    if [[ "$POLICY_ID" =~ $patt ]]; then
        ## If an integer, set the trigger to -id
        TRIG="-id"
    else
        ## If a string, set the trigger to -event
        TRIG="-event"
    fi
    ## Run the policy
    /usr/local/bin/jamf policy $TRIG $POLICY_ID
done < <(printf '%s
' "${POLICY_IDS[@]}")

exit 0

The only possible issue with the above is if you have a lot of policies to run, you could run into the parameter string limit. But it's 256 characters (See here), so in most cases that probably won't happen. Just something to keep in mind though.

kadams
Contributor

@mm2270 Can you give me an example of how I would string those Policy ID's together in parameter 4. I have about 16 policies that I want to call during enrollment. Secondly, which execution frequency should i be using for this policies that i'll be calling. i want them all to run during enrollment. So right now, i have one policy with your script in it. The script should be calling all of the other 16 policies in the order that I specify. At first I had them all execute after enrollment completes. If i keep it that way, those policies will run before the one that has the script to call them in. Should i completely uncheck execution frequency on those 16 policies? To sum this up, your one script should run in a policy. That policy runs and calls all the other 16 policies that I want to run in order.

mm2270
Legendary Contributor III

@kadams

Can you give me an example of how I would string those Policy ID's together in parameter 4. I have about 16 policies that I want to call during enrollment.

Sure, what you'd do is set up each of the 16 policies you need to run on the Mac with an appropriate scope. You could in theory set the scope to All computers, but that might depend on the triggers. In a new policy, add the script. When added, populate Parameter 4 with your policy IDs or their custom triggers, with spaces between each. Like:

20 setCompName joinAD installOffice 47 120 121 123 etc etc

As you can see, it's a mix of custom triggers, which should have no spaces in them (not even sure if it's possible to have spaces in custom triggers?) and policy IDs. The script figures out which is which, and runs them in order from left to right,

Secondly, which execution frequency should i be using for this policies that i'll be calling. i want them all to run during enrollment. So right now, i have one policy with your script in it. The script should be calling all of the other 16 policies in the order that I specify. At first I had them all execute after enrollment completes. If i keep it that way, those policies will run before the one that has the script to call them in. Should i completely uncheck execution frequency on those 16 policies?

You could turn off any triggers and simply call them in the script using the IDs, or a custom trigger, if those are set up. But you do want to turn off the enrollment complete trigger on those. The point is to let the script call them, not the enrollment trigger. Or really even the check-in trigger since that could interfere with it as well.

To sum this up, your one script should run in a policy. That policy runs and calls all the other 16 policies that I want to run in order.

Yes, you can set up one policy that uses Enrollment Complete as the trigger, that uses the script with the parameter populated. You definitely don't want to have the other policies also set up with the enrollment trigger enabled, or it will cause problems with execution order. Just let the one policy + script run on enrollment and subsequently call the other policies by their ID and/or custom triggers.

If you need more info, let me know and I can probably show an example. But it looks like you have the idea.

eric_johnson
New Contributor II
New Contributor II

Small, probably inconsequential note - Policies actually execute in ASCII order, not strictly alphabetic. As such, characters will execute first, followed by numbers and finally letters. This allows you to use the same event for multiple policies (custom, check-in, etc) and have them to execute procedurally.

It should be noted that calling a policy from within another policy will create multiple Jamf processes - worst-case scenario is using one policy to call another, which calls another; each of these will have a separate Jamf process running.

kadams
Contributor

@mm2270 So I have the 16 policies without any execution triggers now. How would I setup the string in parameter 4 for them to execute in order. I also dont have any custom triggers set to them either. I want the policy that has the script to run first during enrollment. Afterward it should call all of the other policies in order by policy ID. Some of this might sound like i'm asking the same question. Not sure how I should be asking this. I removed the execution triggers from all 16 policies. The example you gave shows custom trigger names in the parameter 4 section. I dont have any custom trigger or execution triggers. How would i now write the string in parameter 4?

mm2270
Legendary Contributor III

@kadams Yes, you just put all the IDs in the order you want them to run, left to right in the param 4 field, like

1 2 5 10 20 25 55

@eric.johnson Thanks for mentioning the issue of spawning multiple jamf processes. I assume what you're saying is that if Policy A runs, calls Policy B to run, then Policy B calls Policy C, and so on, that this is not recommended. Correct? That is sometimes referred to as chaining policies, so I'm glad you brought up the potential to have multiple jamf processes all running at the same time.
However, In the case of my script above, I don't think it would spawn multiple processes, but that's something I'll need to check on. It should just be the main policy running the script, and then Policy A is called, finish/close Policy A, then Policy B is called, finish/close Policy B, then Policy C, etc.
Again though, something I will need to look at.

el2493
Contributor III

915906394df44b26bd4a93b1b379a6fe

eric_johnson
New Contributor II
New Contributor II

@mm2270 You're absolutely right - I believe that the main policy which contains the script would be running in one jamf process, which would then start a second process when it calls the first policy (as the main policy will not exit until all called policies exit) - at most, we would have two simultaneous jamf processes running at any time. I also checked (out of sheer curiosity) what the policy logging looked like with these nested policy operations - if Policy A calls Policy B, C, and D, we will see policy logs complete for B, C, D and A - in that order, oldest to most recent.

duncan_wright
New Contributor II

Would using & in the jamf policy trigger commands alleviate the process spawning issue by running the second policy as background so first policy can complete before second policy does? e.g.

jamf policy -event firstRun &

duncan_wright
New Contributor II

My testing shows that yes, running a policy from a script with & will allow the parent policy to complete before the child does.