Bit of a n00b question for you. Can someone give me an explanation for custom triggers in layman's terms? How they're used, how to create them, etc.? It's a concept I've never really grasped, and I would like to try using it for creating Self Service policies to install OS X Mavericks on users' computers (one policy to cache and enter a smart group, then a second to install the cached copy, once it enters the smart group).
There are a bunch of different ways custom triggers can be used with policies. I'll just highlight one or two ways we use them.
If you want to have a policy that you can run on any Mac at any given time on demand, a custom trigger for the policy in conjunction with a Frequency set to "Ongoing" and scope set to "All managed Macs" will be your friend. Basically the "trigger" for the policy would not be Check-In or Login, etc, but instead would be either a tech running it manually on the Mac by issuing something like
sudo jamf policy -trigger <custom trigger>
Or you could call it from another script using the same syntax as above. In a way its like a Self Service policy except it doesn't need to appear there. Call it the advanced "Self Service policy" if you will.
With this type of setup, Scope/Smart Groups becomes somewhat irrelevant since you can scope it to all systems, but not have it run until and if you want it to.
Of course, the usual stuff will still apply, in that you have to be careful that said policy can actually run on those systems. If you're installing something like a specific OS X update, you will not want that set as a custom trigger. Smart Groups would be more appropriate in that case.
We use custom triggers to test out policies, since I can just run it whenever I want and as often as I want (if applicable) on a test box without needing to build a Smart Group or flush the policy log, etc.
One other thing to know is that its easy to string multiple policies together using custom triggers. One policy can run and at the end call the next policy by its custom trigger name, either in a script, or just the Advanced > Run Command field. And then that policy can call the next one, etc, etc. Instead of creating one huge policy that would try to do everything imaginable, you could create several smaller ones and have each one call the next in a specific order.
While you could also achieve the above with Smart Groups, you'd have to run a full recon at the end of each policy to update the JSS, and therefore update the Smart Groups to do that. With the triggers, its not always necessary to have all those Smart Groups.
There are definitely many other ways people use them and so hopefully you'll get a few other points of view.
@mm2270 - So, to see if I understand properly, in my situation, I would use a policy to cache the OS X installer on a user's Mac, and use the Run command option to do something like:
jamf policy -trigger InstallOSX
and create a second policy to install the cached OS X installer with the custom trigger box checked and "InstallOSX" in the text field, correct?
Mike answered the how they're used portion, so I'll take a stab at the how to create them portion.
In any policy on the General tab, underneath the list of triggers, the last item you'll see is "Custom". Place a check mark in that box and a new text field opens up, Custom Event. Just give your Custom Event any name you want and you can then use that to call your policy from the terminal or from a script or from another policy.
Like @mm2270 mentioned, custom triggers (events) are great for testing policies or for cascading policies in a script. I use them in my first boot script to install all of my software.
Yes, you could use it that way. But for your caching policy you will need to use logic in the Smart Groups or some other way to make sure the update is being cached to machines that require it. But yes, once its there, you could probably trigger it that way. I would test that out though. Not sure if you'd run into a timing issue or not with caching + trigger for the install all in one policy. I don't think so since the stuff in the Run Command runs at the end, so meaning, after the cache has happened. The installer should be there by then, assuming it didn't fail.
One thing to note - anything in the Run Command field runs regardless of whether any other portion of the policy failed in my experience. For example, we once set up a policy that used Run Command to send up a jamfHelper message about Java being updated to the user. Problem was, if the actual Java install failed, it still popped up the message that Java was updated, but it wasn't. So you need to be careful about using that.
If that turns out to be a possible issue, there are other ways to do this.
Well, now, that's a whole 'nother discussion.... :-) I think if you lined up 100 admins and asked them all to explain why they do imaging via script or imaging via CI, you'd get 100 different reasons. A lot of it depends on if you are erasing your systems and putting down a fresh OS, or whether you are leaving the OS in place and just adding software/settings. And obviously, it also depends on if you are using a "fat", or monolithic, image or if you are going more modular.
If you are erasing and putting a new OS on, then Casper Imaging is probably the tool you would use (although the same can be done via script and ASR). If you are leaving the stock OS on the machine, you can do modular imaging through Casper Imaging, or you could use the script method.
I like the script method because then I am not relying on a NetBoot set to deploy my software and I have a little bit more control over things. Granted, I can swap out items in a Casper configuration just as easily as doing so with a script, but with the script I can do all of my configuration in one place and then install the software.
I also know that a lot of people switched to script based deployment back in the late ver 8 days when Casper Imaging was having troubles.
So, really, I think it's a matter of preference more than it is anything else.
I didn't really 'get' custom triggers the first year or two I was here either, but then I started paying attention to what others were doing with them. Now it's just another cool trick and added flexibility to get the job done.
First, you don't need a custom trigger to get your Mavericks upgrades out. Use one policy to cache the installer, then use another policy to 'installed cached' from a smart group that is looking for that cached package (receipt info, cached packages…)
For custom triggers though, here are two that I'm running now if you need some inspiration.
New machine deployment (don't call it imaging anymore). Under certain circumstances, my field techs can't use Casper Imaging to prep a new machine. We don't erase it, we just lay down our packages and scripts to a standard (like @stevewood mentions). So I created one custom triggered policy that contains all our standard applications and a few scripts. The field tech unboxes the new machine, boots to the desktop, and enrolls with Casper via QuickAdd package. Then they run a payload free package that only contains a postflight script of the custom trigger. Policy kicks off, all our stuff installs, 20 minutes later the machine's ready to go.
Here's another. Sometimes I want to install application updates, but only when the target application is not running. That's easier than trying to engage the user to quit or reboot etc.. With help from this group, I wrote a script that will check the running processes. If my target application is running, the script quits quietly. If my target application is not running, then a custom trigger is run which kicks off a policy to install the update package. Making that even cooler, it's a generic script that uses the $4 and $5 script parameters to define the process and trigger name right in the policy. Nice.
Food for thought!
I too am trying to figure out how to use custom triggers. What I am looking to accomplish is the following:
I have a policy to upgrade a piece of software. Once this policy installs successfully, I would like to call another policy. Would this be a good scenario for custom triggers, or should I be looking elsewhere? IF this is a good use of custom triggers, how to set up the trigger so it only calls the second policy when the fist is successful, but not if the fist is unsuccessful?
@donparfet that would be a good use of custom triggers. You can check the exit code of the last command and only run the second policy if it was successful. You would wrap your second command in an
if statement, something like:
if [ $? -ne 0 ]; then exit else jamf policy -trigger <nameofsecondtrigger> fi
$? is the exit code of the last command that ran.
Hi @donparfet. Yes, its possible to use a policy with a custom trigger for the scenario you described.
As far as only calling that trigger upon success of the main policy, well, ah, that's the holy grail right there. Since policy items or payloads don't really rely on each other's exit codes right now, its a little tricky to get this just right, but certainly possible.
What I would say is you may want to put together a script that can run in an After state in the main policy that would do some kind of check to ensure the first policy ran to completion. How you would do such a check is very dependent on what your first policy is doing.
A few simple examples on what might work:
If the first policy is installing a known version of an application, your After script could check the version on disk for the application in question and compare it to what it should be after the update. If its the same (meaning the app was updated) then call the 2nd policy with the custom trigger. If not, exit without calling the custom policy trigger.
Something like described above could be made pretty flexible with the use of script parameters. For example, set $4 to the path of the application, and $5 to the version you expect it should be at. Then pass those to the script to have it run a defaults read on the application path to get the version information. Capture that version in a variable and then do a simple comparison, like
if [[ "$installedVersion" == "$expectedVersion" ]]; then jamf policy -trigger <sometrigger> else exit 1 fi
Where $installedVersion would be the variable populated earlier in the script where it gets the installed version of the application. $expectedVersion would get populated from the $5 script parameter.
Another way you might be able to do this is to look for a package receipt in the location where Casper Suite stores them (/Library/Application Support/JAMF/Receipts/ by default) If the receipt is there, you can reasonably make the assumption that the installation worked, although this might not be as accurate as checking a version on disk truthfully. You would still need to pass the script a parameter to know which receipt to look for, or just hardcode it if you don't plan on using it for more than one policy.
Hope the above helps get you moving in the right direction. Post back if anything is unclear or if you have more questions.
@davidacland Hmm. I'm not sure if you can use the exit code of the last command in a script to determine if the main portion of a policy, like the main package installation, failed or succeeded. Have you found that this works? If so, I've been missing out on using that. I've not been able to get a script to determine that in the past, but in all seriousness, its been a while since I've tried it now.
Now you mention it, I think you're right. The exit code will be from the policy which will always be 0 as it technically finished.
Other options would probably be too messy, but if its an app installer, I like the if/else you've put up there ($installedVersion vs $expectedVersion).