top of page


“In order to understand the complexity of Teller’s life, you need to know the seven basic principles of magic.”

From the Penn and Teller routine entitled “Looks Simple.”[1]

In part one of our series on the magic on endpoint provisioning we started at the end, looking at the big reveal and showing how we create the illusion that we are doing a lot of work when, in fact, Jamf is doing the real work and we are just showing off for our users.

Today we are taking a step back and looking at the script that drives it. Not all of it, just the parts that help you make magic.

The entire script is available at our GitHub[2] page to use and modify to your needs.

I want to take a moment to credit Richard Purves (aka “franton”) in the Jamf Nation and MacAdmins communities as the source for much of this script. He had posted a very similar script to the #depnotify channel of the MacAdmins Slack server in December of 2018. I found it while I was looking for some good examples of DEP workflows and I’ve been tweaking it ever since. I am reminded of the quote, “If I have seen further, it is by standing on the shoulders of giants.”

Rather than paste the entire code, I’m just going to grab blocks and explain what they do and how they connect to the whole. I’m leaving out the comment blocks to save space since this article is meant to do a better job than they do.

We start with the section that begins…

###             ###
### Main Script ###
###             ###

## These next four lines execute functions above
coffee ## Uses 'caffeinate' to disable sleep and stores the PID for later
pauseJamfFramework ## Disables recurring Jamf check-ins to prevent overlaps
waitForUser ## Blocking loop; Waits until DEP is complete and user is logged in
startDEPNotify ## Initial setup and execution of DEPNotify as user

These four functions are a little bit of sleight of hand, if you will. The original script was a top-down shell script that was just copied/pasted as-is and then all unneeded parts were torn out and additional pieces added.

Starting with version 2.0, the script has become more modular. This script solely creates the user experience and makes calls to additional policies. All the original calls to the API for buildings and departments or to update user information have been moved into other scripts and policies that can be called from here. Same with the DEPNotify EULA and registration components.

In the book “Programming Perl” by Larry Wall, the creator of the language, he says that there are three virtues of a programmer: laziness, impatience and hubris.

It is in this spirit that I added two additional functions:

function DEPNotify {
   local NotifyCommand=$1
   /bin/echo "$NotifyCommand" >> /var/tmp/depnotify.log

function jamfCommand {
   local jamfTrigger=$1

   if [[ $jamfTrigger == "recon" ]]; then
      /usr/local/bin/jamf recon
   elif [[ $jamfTrigger == "policy" ]]; then
      /usr/local/bin/jamf policy
      /usr/local/bin/jamf policy -event $jamfTrigger

The first of these functions, DEPNotify, is just there so instead of having to type something like this over and over:

/bin/echo “Status: I am really sick of having to append another echo statement to the log file!” >> /var/tmp/depnotify.log

I can just write:

DEPNotify “Status: This is so much better. Thank you for writing this!”

Why? Laziness. That’s one down.

The second, jamfCommand, is meant to similarly reduce typing. Where the early applications of version 1.0 of this script were full of things like:

/usr/local/bin/jamf policy -event doSomething
/usr/local/bin/jamf recon
/usr/local/bin/jamf policy

The above can now be written as:

jamfCommand doSomething
jamfCommand recon
jamfCommand policy

If the argument is either “recon” or “policy” it just uses that verb with the binary. But as in the first examples, any other argument is turned into the “-event” argument of a policy call.

After that we have the main section with the following blocks. Each described separately below.

## Machine Configuration
DEPNotify "Command: MainText: Configuring Machine."
DEPNotify "Status: Setting Computer Name"
jamfCommand configureComputer

In addition to notifying the end user of what is happening, this calls for any policy with the “configureComputer” manual policy to run. Common uses for this are to rename the computer or configure DNS settings.

## Installers required for every Mac - Runs policies with 'deploy' manual trigger
DEPNotify "Status: Starting Deployment"
DEPNotify "Command: MainText: Starting software deployment.\n\nThis process can take some time to complete."
jamfCommand deploy
sleep 3

Like above, we update the user of our status, and this time we call for any policies with the “deploy” trigger. These are the policies we want/need to have before any others. This might include installing security software or mapping printers. This is also where we might call a script to leverage DEPNotify’s registration or EULA functions.

## Add Departmental Apps - Run polices with "installDepartmentalApps" manual and scoped to departments
DEPNotify "Command: MainText: Adding Departmental Components."
DEPNotify "Status: Adding Departmental Applications. This WILL take a while."
jamfCommand recon 
sleep 1
jamfCommand installDepartmentalApps

Again we keep our people in the loop on what we are doing. But now we run two commands. First we submit a new inventory to make sure our smart groups are updated, but also to take into account any changes to the user and location fields we made with the registration scripts. Then we call for any policies with “installDepartmentApps” triggers.

## Send updated inventory for Smart Groups and check for any remaining scoped policies
DEPNotify "Command: MainText: Final install checks."
DEPNotify "Status: Update inventory record."
jamfCommand recon 
sleep 1
DEPNotify "Status: Final policy check."
jamfCommand policy

Now after our display changes, we run another inventory and look for any additional policies for which this computer is in scope.

I’ve probably demonstrated Larry Wall’s virtue of laziness[3] by now, but what about “hubris?” Come back for part three in our series and we’ll take a look at the kinds of policies and the way we drive the rest of the workflow within Jamf Pro and it should be pretty clear.


  1. If you search for “Penn and Teller” and either “looks simple” or “principles of magic” on YouTube you’ll find the routine in question. Since none of them are from the artists’ official channels, I’ll refrain from giving a direct link.


  3. According to Larry Wall, the original author of the Perl programming language, there are three great virtues of a programmer; Laziness, Impatience, and Hubris.

In my next trick, I will go over the Jamf policies that make this entire workflow magically work:

1,127 views0 comments


bottom of page