Skip to main content

Steal this script!

Posted in: Jamf Pro

As I speak with new customers, one of the first questions I ask is, “Are you a scripter?” Often, the answer is “no”, even when I’m meeting with several Mac admins. So, I begin my spiel.

Jamf Pro doesn’t require administrators to know a scripting language before they use it. Most of it is GUI-based, drag and drop, or pick and choose. It simplifies Mac administration. But knowing just a handful of Terminal commands and how to string them together will take an administrator’s effectiveness with Jamf from a 2 to a 10 — 11 if you’re into Spinal Tap.

Most scripters begin without knowing they’ve started. They steal scripts.

That’s OK! The culture of scripters is one of sharing and teaching. The idea behind sites like GitHub, Stack Overflow and Jamf Nation is that as people collaborate, a much larger group benefits from observing their exchange of knowledge. Those who write scripts and even script snippets expect their work to be stolen. Go ahead!

Adapting a script for Jamf
Scripts are very personal to the administrator writing them. That’s because they’re written to solve a very specific need. But many can easily solve 95 percent of someone else’s need with a little adaptation.

Paul Bowden with Microsoft is a developer for Office for Mac. He interacts with Mac admins in the #microsoft-office channel on Slack and has posted several scripts for managing Office. One of those scripts is Unlicense. Its purpose is to detect whether a Mac is using a volume or Office 365 license and, optionally, remove the license to change to the other.

He wrote Unlicense because organizations are transitioning to Office 365 licenses to enable additional features not included with volume licenses. They need a tool to help with the transition.

Deleting unneeded code
Paul has made Unlicense available for everyone on GitHub, but it requires interaction and only detects licensing for the current user. Let’s adapt it to work with Jamf as an extension attribute (EA). This EA will run during inventory and return license information back to the Jamf Software Server (JSS).

After downloading and opening the script, scroll to the bottom and note it has 264 lines of code. Eek!

Don’t panic. Many of those lines are just whitespace for readability. They’re useful not only for Paul when he’s reviewing his code but admins who are stealing and adapting his code. Let’s start at the beginning and pare this down to what’s needed.

Line 1 is the shebang (#!/bin/sh). The script needs this line to run. Keep it.

Lines 4-5 give the name and version of the script. They’re referenced elsewhere in the script in a function named “ShowUsage”. That function isn’t needed since the script won’t be interactive. These lines can go.

Lines 7-15 are Paul’s copyright. It’s OK to remove this information unless republishing the script in whole or in part somewhere else. Give the original author attribution in your script if you publish it. You may want to ask before republishing too.

Lines 17-22 begin with the hash or pound (#) symbol. These are comments (information for someone reading the script but doesn’t really do anything) and settings that have nothing to do with licensing. Delete them.

Lines 23-26 are specifically about Office licensing. Keep these.

Lines 28-36 are a function. That’s like a script within a script and it has its own name: “ShowUsage”. When the main script calls the “ShowUsage” function later, it runs the code inside the function. This function is only used when running the script interactively in Terminal. No need to keep it.

 function ShowUsage {
# Shows tool usage and parameters
echo "Purpose: Removes current Office 2016 for Mac activation license and returns apps to read-only mode"
echo "Usage: Unlicense [--all] [--detectonly] [--o365] [--volume]"
echo "Example: Unlicense --o365"
exit 0

Paul has done a nice job putting many parts of the script into functions and giving them informative names. For the EA, keep just two of the functions: DetectVolumeLicense and DetectO365License. Delete the rest.

Lines 166-200 are more of the script’s interactive code. Delete them.

Lines 202-222 are the meat of the script. These are worth keeping for now until simplifying them for the JSS.

Lines 224-261 deal with removing licenses. An EA is intended only to report information to the JSS, not make changes to the Mac. These can go.

Line 264 is the end of the script. Keep it.

After removing blank lines and unneeded code, the remainder of the script is only 27 lines (just 10 percent of the original number of lines). This should emphasize to any novice scripter that big scripts are often just full of air. They’re intimidating until all the extraneous code is removed.

Keeping what makes sense for the EA
The main part of the script doing the work (lines 202-222) is one large “if” statement. It effectively says, “run only if detecting the type of Office licensing.” Well, there’s no “if” about it. That’s the entire purpose of the script. Remove lines 204 and 222, which begin and end the “if” statement. That leaves the rest in between to definitely run.

Now, lines 205-221 contain a lot of “echo” commands reporting whether a license was found and, if so, what kind of license was found. The text is verbose, which is great when running the script in Terminal, but not so much when sending the information back to the JSS. Let’s shorten the responses and include the important “<result>” and “</result>” tags that are necessary for the EA to work.

Change lengthy statements like:

 echo "A volume license was detected."

to concise statements like this that won’t overrun the fields in the JSS:

 echo "<result>Volume license</result>"

Adding modifications
Does the script do everything needed? Not yet.

While a volume license activates Office for all users, an Office 365 license is per user. Paul’s original script only checks for the volume license and the current user. What about other user accounts?

Over time, scripters build a library of “snippets”. A snippet is a little piece of more complex code that’s easier to copy and paste than rewrite each time. Here’s a great example (all one line):

 userList=$( /usr/bin/dscl /Local/Default -list /Users uid | /usr/bin/awk '$2 >= 501 { print $1 }' )

An advanced Mac scripter may understand what this does just by looking at it, but many scripters won’t without pasting it into Terminal and hitting return. This snippet runs the commands between the parentheses first and then takes the result and puts it into a variable named “userList”. Specifically, this snippet creates a list of all user accounts on a Mac with UIDs over 500. (All system accounts have a UID under 500.)

With a list of account names, the script can use a command to evaluate each one, get the path to its home folder and look for the three files that indicate the user has an Office 365 activation.

Finalizing the script
After some additional coding (too much to cover here), the final steps are to test each scenario and ensure the script is returning the correct results:

  • A volume license is installed
  • One or more Office 365 licenses are installed
  • Both a volume license and Office 365 license is installed
  • No license is installed

Troubleshooting a script can sometimes take as long as writing the script itself, but seeing the final result run as intended is a great feeling of accomplishment.

Consider adding some polishing touches. Use the hash or pound ( # ) symbol to add comments about sections or commands in the script. Include a section near the beginning with information about the author, how to use the script and where to find newer versions of the script. Thank your mother and the academy.

Add the script to the JSS as an extension attribute and run “sudo jamf recon” on a test machine. Then view the results of the extension attribute in the computer’s record or add it as criteria for an Advanced Computer Search or Smart Computer Group. Optionally, enable the new Smart Computer Group to show in the JSS Dashboard or email notifications when membership changes.

New Year’s resolution?
Steal this script! Steal Paul’s script! Run them; see what they do. Read them and you may find you understand what they do even if you can’t write scripts yet. Click the “New From Template” button above your extension attributes list and try the code snippets you find there in Terminal. Make learning a language like BASH, AppleScript or Python your New Year’s resolution.

Scripting rewards you with exponential returns the more you learn. Each new command is a new tool in your toolbox. You can do a lot with a hammer and a saw. But consider what you can build by adding a sawhorse. And a tape measure. And a paintbrush...

View the complete script for the extension attribute on the Jamf Professional Services GitHub page. View Paul Bowden’s original script on his GitHub page.