Archive

Posts Tagged ‘jamf’

Using Postman for Jamf Pro API Testing – Part 2: Creating And Updating Policies

April 22, 2020 Leave a comment

In my previous post I walked through the basic steps necessary to get Postman ready to do API requests to your Jamf Pro server. In this post we’ll get into using Postman and the API to create and update policies, including saving our API requests so we can use them again.

Before we get started I feel like I need to re-iterate my disclaimer:

Prod is NOT test. Be careful with your updates, deletes, and creates. I highly suggest practicing in a dev environment first if you can. If you do not have a dev environment, then use test items like test policies and test computers. The API is a powerful tool.

Ok, now that the disclaimer is out of the way, let’s get to it!

Create a New Policy

You can create a policy with as little information as the name of the policy, or with as much information as the packages to install, scripts to run, and just about anything else you can do in the GUI. One thing I know you cannot do is remove the Restart options from a policy you create. Even if you do not set anything in the Restart section of XML, the policy will still create with that “tab” added to the policy.

The Jamf Pro API takes XML code blocks to create pieces. If we were to open the POST request for creating a policy (title: “Creates a new policy by ID”) we would see a basic representation of some of the information we can send using this request to create a policy.

Let’s say we wanted to just create a shell of a policy that had a name, a trigger, and a frequency. That XML would look something like this.

<policy>
	<general>
		<name>Our Cool Policy</name>
		<enabled>false</enabled>
		<trigger_checkin>true</trigger_checkin>
		<frequency>Ongoing</frequency>
	</general>
</policy>

We would put that block of XML into the Body section of our API request.

If we were to run that by clicking the Send button we would now have a policy named “Our Cool Policy” that was not enabled with a trigger of Recurring Check-in and a frequency of Ongoing. Pretty cool. The Jamf Pro API returns the ID of our new policy and Postman displays that for us.

We can go open up our JPS web interface to look up that policy, but why not just use Postman to look at it. Go find the GET request named “Finds policies by ID” and enter that new policy ID into the “id” Key under Path Variables. Just replace {{id}} with the ID number returned after we ran our POST request.

Example

Now if we run that GET request we’ll get a bunch of XML back showing our new policy, even though we only entered a few items.

Look at all that info! Now, if you’re more of a visual person and need to see it in the web interface, by all means go pull up the policy. We’ll wait until you come back.

Sidebar: When you close out the GET request where we wrote over the {{id}} variable, do not save the request. We want the variable to be there for later use. I’ll show you later in this post a better way to put the ID value in.

That was all neat and all, but what about installing a package as part of the policy? For us to do that we would need a little bit of information about the package. We will need to add the ID of the package and we will need to add the action we want to take (install or cache).

You can grab the package information straight from the web interface, from Jamf Admin, or even better, right from the API here in Postman. This time I’ll let you figure it out on your own. Go find the GET request to list packages and then locate the ID of the package you want to install in our policy.

For my demo I’ll be using a policy ID of 1265 and an action of Install. Here’s what the XML looks like.

<policy>
    <general>
	<name>Our Cool Policy</name>
	<enabled>false</enabled>
	<trigger_checkin>true</trigger_checkin>
	<frequency>Ongoing</frequency>
    </general>
    <package_configuration>
        <packages>
            <size>1</size>
            <package>
                <id>1265</id>
                <action>Install</action>
            </package>
        </packages>
    </package_configuration>
</policy>

If we replace our XML in our POST request and run this in Postman, we will get error because there is already a policy named “Our Cool Policy”. We’re going to pretend like we didn’t already create that policy since we’re talking about creating new policies. I’ll discuss updating an existing policy later. (Of course we could just use Postman to delete the test policy we created above)

After running the POST we now have a policy in Jamf Pro that is disabled but has a package attached to it.

There you have it, we’ve created our very first policy that actually does something. Of course we would still need to put a scope on the policy and enable it, so why don’t we do that now.

Updating A Policy

Let’s continue building on the policy we were creating above. The ultimate goal of this policy is to be an installer policy that can be used on any computer and triggered via a Custom Trigger. This is one of the methods many Mac admins use for doing installs: have an install policy and call that install policy from other policies or scripts. Go watch Bill Smith’s (@meck or Talking Moose) JNUC presentation from 2017 titled “Moving Beyond “Once Per Computer” Workflows” for more info behind this.

We already have the framework of our policy created we just need to make a few changes and additions. We’ll need to do the following to make this into a true installer policy:

  1. Change the trigger to a custom trigger
  2. Add an inventory update
  3. Add a scope
  4. Add a category

We will want to use the PUT request named “Updates an existing policy by ID” to do these updates. Once again, we only need to put in the XML for items we need to change or add to the policy.

<policy>
    <general>
        <trigger_other>install-our-cool-app</trigger_other>
        <trigger_checkin>false</trigger_checkin>
        <category>
            <id>14</id>
        </category>
    </general>
    <scope>
        <all_computers>true</all_computers>
    </scope>
    <maintenance>
        <recon>false</recon>
    </maintenance>
</policy>

Those are all the XML keys that we’ll need to update in our policy (category ID 14 is the cateogry where I put installers). We’re going to drop that XML into the body section of our API request and we’re going to set the ID variable again like we did above. Just put the ID number of our cool policy.

Change ID variable

After running that API request, our installer policy should be all set and ready to be enabled.

Collecting Our Requests

Now that we’ve used a couple of different API requests, let’s put those into a collection that we can re-use later when we need to do the same thing. Let’s create a collection of requests for manipulating our policies.

Click on the down arrow next to the Save button next to the Send button and choose Save As.

In the window that opens, go ahead and give your request a descriptive name, you can even give it a description. Since this is the first request we’re saving, we’ll want to create a collection for it. Click on the “+Create Collection” link towards the bottom of the window. Give your collection a good name and click the orange check mark.

Finally, click the big orange Save button at the bottom.

Continue saving all of the requests that you want to use when creating these installer policies, or whatever type of policy. Just remember, if you have changed the ID key from {{id}} to a number, change it back to {{id}} before saving. You’ll see why in a minute.

Now that we have all of these requests in one location, it makes it easier for us in the future when we need to create or update the policy. If we set all of the XML in the POST, then in the future we just have to edit those values in the XML for the new policy.

One more thing you’ll need to do. The Classic API collection from Jamf comes with the authentication variables username and password already configured. We’ll need to do that to our new Installer Policies collection.

Click on the elipses, the three dots, to the right of our collection name and choose Edit.

In the window that opens, click on the Authorization tab. Now click on the drop down box on the left and choose Basic Auth. Fill in the username and password boxes with the variables that we need. Once you have done that click on the orange Update button at the bottom.

In a future post we’ll go over a method for converting those values into variables that we can feed with a JSON file or CSV file so that we do not have to edit our request.

Using Variables

I told you I’d show you how to use variables, like the {{id}} variable we’ve already seen. We’re going to use the “Pre-request Script” section of our request window to fill those variables. We use this method rather than directly editing the “Path Variables” on the Param tab so that we can re-use our API request in a more automated fashion later.

On the “Pre-request Script” tab you’ll notice some snippets on the far right. Click on the “Set an environment variable” snippet to add the code to the window.

I’ll bet you can figure out what we’re going to do, right? Yep, go ahead and replace “variable_key” with the variable “id”. Now anytime you want to do an PUT (update) or a GET (retrieve) for a specific policy, you can simply put the policy ID in the “variable_value” field.

For example, if we wanted to update (PUT) our cool installer policy, id = 3338, we would simply add that ID.

When we send that request, the ID variable on the Params tab will get switched out with the ID we placed here in our Pre-request script. That will in turn replace the “:id” in the URL of our request. Clear as mud, right?

Wrap Up

We covered a lot here, a lot more than I expected. Postman is a pretty powerful tool for learning about the Jamf Pro API and how to use it to manipulate your environment. I would suggest doing some Google searches and watching some YouTube videos on how to use Postman to get more advanced.

In our next post we’ll talk about creating and editing computer groups.

Until next time!

Categories: Jamf Pro, Tech Tags: , ,

How To Quickly Open a Policy in Jamf Pro

January 9, 2019 Leave a comment

We have a lot of policies. I mean over 1,000 policies in our Jamf Pro Server. Don’t ask. Part of it is out of necessity, but I’ll bet some of it is just because we were running so fast in 2018 to get systems enrolled and agencies under management, that we didn’t have time to, as Mike Levenick (@levenimc) recently put it, “trim the fat”. That’s what 2019 is all about. But I’m missing the point of this post: how to quickly open a policy. You can imagine how long it takes to load the list of policies when you have over 1,000 of them.

There are a couple of tools you’ll need. First up you’ll want a tool like Text Expander to create snippets or macros. I’m sure there are some free alternatives out there that will expand a text shortcut into something but Text Expander is what I’ve been using for many years, of course I’m using version 5 which is a perpetual license version and not the current subscription model. (Here’s an article about text expansion apps)

The second tool you’ll need is jss_helper from Shea Craig (@shea_craig). This will help us pull a list of the policies in our system, including the ID of the policy.

Now that you have your tools in place, the first thing you want to do is grab the URL of one of your policies. Just open a policy and copy the URL. Now go into Text Expander (or whatever tool you chose) and create a new snippet from the contents of the clipboard. Edit the URL removing everything after the equals (=) sign in the URL. Give your new snippet a shortcut and voila! You now have an easy way to get 90% of the way to quickly opening policies. Your URL snippet should look similar to this:

https://jss.yourcompany.com/policies.html?id=

Now let’s turn our attention to jss_helper. Once you have it installed and configured to talk to your JPS, you’re going to want to pull a list of the policies in your system. Open up Terminal (if it isn’t already) and run jss_helper with the following options:

jss_helper policies > ~/Desktop/policy_list.txt

Obviously you want to name that file whatever you want, but the cool thing is that you now have a list of every policy in your JPS along with its ID. If you open that file up in Excel or a text editor, you’ll see something like this:

ID: 2034 NAME: Installer Adobe Acrobat DC 19

ID: 1214 NAME: Installer Adobe Acrobat DC Reader

ID: 2030 NAME: Installer Adobe After Effects CC 2019

ID: 2031 NAME: Installer Adobe Animate CC 2019

ID: 2032 NAME: Installer Adobe Audition CC 2019

ID: 2033 NAME: Installer Adobe Bridge CC 2019

ID:  638 NAME: Installer Adobe Codecs

ID:  532 NAME: Installer Adobe Creative Cloud Desktop elevated App

ID:  314 NAME: Installer Adobe Creative Cloud Desktop Non elevated App

Now let’s put it together. Open up your web browser and in the address bar type whatever shortcut you created for the policy URL above. Once the URL expands, before pressing enter, type in the ID number of the policy you want to open and then press enter. The policy should open up without having to wait for the list of policies to load or having to search the web interface for the specific policy.

Hopefully this will help speed up your game and help you become quicker and getting stuff done.

Categories: Jamf Pro, Tech Tags: , ,

Using AWS Lambda To Relay Jamf Pro Webhooks to Slack

January 8, 2019 Leave a comment

I recently got interested in utilizing webhooks in Jamf Pro but had no idea where to start. I went and watched Bryson Tyrrell’s (https://twitter.com/bryson3gps) presentation from JNUC 2017 Webhooks Part Deaux! and then went over to take a peek at Jackalope on the Jamf Marketplace. I read the docs, I tried to figure out how to do this in AWS ElasticBeanstalk, but I just couldn’t get it going. Just too much going on to devote enough time to it. So, I went over to Zapier and signed up for their free account so I could get this going. I got it working, but I quickly got throttled because I decided to enable the “ComputerCheckIn” webhook to make sure it worked. I think we flooded the 100 connection limit within 30 seconds and wound up having thousands of items in Zapier.

Well, that wasn’t going to work, so I changed it to “ComputerAdded” and waited for my month of Zapier to renew so I’d get 100 new “zaps”. That worked, until we went over the 100 limit again and had to wait. There had to be a better way that wasn’t going to cost me a ton of money. So I went Googling and came across an article on how to use AWS Lambda to do what I wanted to do: AWS Lambda For Forwarding Webhook To Slack.

I walked through the steps outlined on the page to setup the function in Lambda and everything worked great until I got to the part where I was making requests out to Slack. Lambda had a problem with the request method. Specifically this line of code:

 var post_req = https.request(post_options, function(res) {

So another round of Googling and I came up with the Node.js docs page on HTTPS and I figured out how to properly make the call:

const req = https.request(post_options,
(res) => res.on("data", () => callback(null, "OK")))
req.on("error", (error) => callback(JSON.stringify(error)));
req.write(post_data);
req.end();
view raw gistfile1.txt hosted with ❤ by GitHub

Once I was able to get past the https connection issues, I was able to utilize the rest of Patrick’s example to get my webhook from Jamf feeding into a Slack channel. We uploaded a custom emoji to our Slack channel and used the Slack documentation on basic message formatting and on attachments to get the notification to look how we wanted.

Ultimately we created two Lambda functions, one for ComputerAdded and another for ComputerInventoryComplete, each feeding into their own channel in our Slack. This was fairly easy to accomplish, the next step is to find a way to feed DataDog, or some other service, the ComputerCheckIn webhook so I can get a count of how many check-ins we have each day.

The code we used is below, but I wanted to point out one or two things. Where I got hung up the most was how to pull things like Computer Name or Serial Number from the JSON we were getting from the Jamf Pro server. Since the JSON contains two arrays, “webhook” and “event”, it took me a little bit to understand how to grab that data. To be honest, my skills here are lacking considerably so it took me longer than it should. Ultimately I figured out that you just have to dot walk to get the data you want. So to get the Computer Name it’s:

body.event.deviceName

“body” is the JSON object that we parse the webhook into. Once I figured that out I was all set to grab whatever data from the event, or webhook, array that I needed. Hopefully my head banging will help others not stumble quite so much.

Here’s the Node.js code we used as the template:

var https = require('https');
exports.handler = (event, context, callback) => {
console.log("MYLOG" + JSON.stringify(event))
var body = JSON.parse(event.body);
var name = body.event.deviceName;
var sernum = body.event.serialNumber;
var user_name = body.event.username;
var building = body.event.building;
var curr_time = Math.floor(new Date() / 1000);
var post_data = JSON.stringify({
"username": "Jamf Pro Server",
"icon_emoji": ":balloon:",
"channel": "#<yourslackchannelname>",
"text": "Computer Enrolled",
"attachments": [
{
"color": "good",
"fields": [
{
"title": "Computer: " + name,
"value": "Serial number: " + sernum
+ "\nUser name: " + user_name
+ "\nBuilding: " + building,
"short": false
}
],
"footer": "Jamf Webhook",
"footer_icon": ":balloon:",
"ts": curr_time
}
]
});
var post_options = {
host: 'hooks.slack.com',
port: '443',
path: '/services/YOURWEBHOOK',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(post_data)
}
};
const req = https.request(post_options,
(res) => res.on("data", () => callback(null, "OK")))
req.on("error", (error) => callback(JSON.stringify(error)));
req.write(post_data);
req.end();
var details = {
"status": "OK"
}
var response = {
'statusCode': 200,
'headers': { 'Content-Type': 'application/json' },
'body': JSON.stringify(details)
}
console.log("LOG:: " + JSON.stringify(response))
callback(null, response);
};
view raw gistfile1.txt hosted with ❤ by GitHub

 

 

Categories: Jamf Pro, Tech Tags: , ,

JNUC 2018 – Slides And Scripts

October 24, 2018 Leave a comment

The slides, scripts, images, and video from my presentation “10 Things Not To Do in a Large Scale Deployment” are available on GitHub now:

JNUC 2018

Categories: Casper, Jamf Pro Tags: ,

Using lpoptions To Identify Printer Options

October 20, 2018 1 comment

In my previous post on adding printers via script I mentioned using lpoptions to identify the different option settings for a printer. Let’s open up Terminal and get started with identifying the options. You’ll need to have the printer already installed on the system, so if it isn’t installed go follow my previous post and get it installed.

First, let’s find the name of the printer. For that we will use lpstat -a:

Screen Shot 2018-10-20 at 3.46.45 PM

Now that we know the name, Wayne_HOLD, let’s figure out what the options are that we can set. For that we’ll use lpoptions -p Wayne_HOLD -l. Now this list is way too much information to post here, so I’ll just cut it off at a few lines:

Screen Shot 2018-10-20 at 3.48.56 PM

Wow, and there’s plenty more information beyond this. This part of setting the options can be a bit trial and error. We probably aren’t going to want to set everything,  but we will want to add any options like the “Fiery Graphic Arts Package” that is installed, or the “Output option”, or perhaps the “Xerox high capacity feeder”.

One way we can figure out what option we need to set is by using grep along with the lpoptions command. For example, to know which option sets the “Fiery Graphic Arts Package” we might try this:

lpoptions -p Wayne_HOLD -l | grep -i "graphic arts"

This gives us the following:

Screen Shot 2018-10-20 at 3.53.52 PM

That’s great, but what does “GA2” and “GA1” mean? Open up the Options & Supplies window for the printer by going to System Preferences -> Printers & Scanners -> click on the printer and then click on the Options & Supplies button. For this printer, we can see that “GA1” is the “Fiery Graphics Arts Package”.

Screen Shot 2018-10-20 at 3.55.54 PM

What happens when we change that in the GUI to:

Screen Shot 2018-10-20 at 3.57.26 PM

This is what we see from Terminal:

Screen Shot 2018-10-20 at 3.57.41 PM

So now we know that the “GA2” option is the “Fiery Graphics Arts Package, Premium Edition”.

For other settings we need to do some investigation in the Print pane when printing a document. For most printers we’ll want to see what the default view is in the Print dialog window and then make the change in the Terminal using lpoptions and finally go back to the Print dialog window to see what that change did.

In our case we want to set the Output option and the High Capacity Feeder option from their default settings:

Screen Shot 2018-10-20 at 4.09.10 PM

To use a high capacity paper source, and to put the output in a different tray:

Screen Shot 2018-10-20 at 4.09.41 PM

Notice that in the second screen shot we now have Tray 6 available to us. We can acheive this using the lpadmin command to set the settings (note: the lpoptions command works most of the time, but I have far more success using lpadmin).

Screen Shot 2018-10-20 at 4.12.46 PM

By figuring out which settings we want to use, we can now configure all of the options for a printer from a script. One more example would be setting a color printer to default to B&W and duplex print. This is often done as a cost savings measure.

lpa='/usr/sbin/lpadmin'
${lpa} -p CopyThat -E -o printer-is-shared=false -v lpd://10.89.170.5 \
-P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 7855.gz"
${lpa} -p CopyThat -o Duplex=DuplexNoTumble -o XROutputColor=PrintAsGrayscale
view raw gistfile1.txt hosted with ❤ by GitHub

I hope this has inspired you to dive further into setting up printers via script.

Categories: Casper, Jamf Pro, Tech Tags: , ,

Identify EFI Fiery Driver

October 20, 2018 1 comment

In this post I talked about how we can use the lpadmin command to add a printer via script. In this post we will cover how we can identify the driver for an EFI Fiery RIP. Note: all Fiery RIPs do not use the same driver, so you will want to follow this process for any Fiery you may have in your environment.

Open your favorite web browser and enter the IP address (or DNS name) for the printer. This should take you to the Fiery RIP webpage.

Screen Shot 2018-10-20 at 3.22.16 PM

Now, click on the Configure tab, then on the “Check for product updates” link.

Screen Shot 2018-10-20 at 3.22.30 PM

This will open up a new tab in your browser that will take you to the EFI Fiery live update page. From here you’ll want to click on the Printer Drivers tab and then scroll to locate the latest printer driver.

Screen Shot 2018-10-20 at 3.23.07 PM

We’ve scrolled down to locate the latest driver that handles macOS 10.14 Mojave.

Screen Shot 2018-10-20 at 3.23.16 PM

We can then click the Download link to download the latest version of the Fiery driver for our specific model of Fiery.

One Last Thing

Now that you have your driver downloaded, I would strongly suggest heading over to Foigus’ post, Trial By Fiery, to find out how to use AutoPKG to create a driver package that will install via a management tool, and not have update dialogs popping up.

Categories: Casper, Jamf Pro, Tech Tags: , , ,

Deploying Printers via Script

October 20, 2018 2 comments

Deploying printers on the Mac in an enterprise environment, or heck, just in a small office environment, can be done in multiple ways. If you don’t have a management tool, or ARD, you’re going to be running around doing it by hand. If you have a management tool, like Munki or Jamf, then you can deploy printers in a more automated fashion. My preferred method is to use a Bash script to deploy printers because it provides me a little more flexibility

Identify The Driver

The first thing to do is to identify the printer and the driver that is required. For most printers this is pretty simple, just navigate to the IP address of the printer to verify the make and model, then head over to the vendor’s website to download the latest driver. Once you have the driver, install it on your machine and then go find the driver file on your system. On the Mac, most printer drivers are stored in:

/Library/Printers/PPDs/Contents/Resources

If your printer has a “RIP”, or “Raster Image Processor“, identifying those drivers can be a little trickier. Head over to this post on how to identify the driver, and download it, on an EFI Fiery RIP. Drivers for an EFI Fiery or other RIP are usually stored in:

/Library/Printers/PPDs/Contents/Resources/<localization folder>

For us here in North America, that folder path would be:

/Library/Printers/PPDs/Contents/Resources/en.lproj

Once you have identified the driver, copy the full path of the driver file (Option-Command-C, or hold down Command then Edit->Copy as Pathname, or right click while holding Command) to your clipboard.

Build The Command

The next thing we need to do is figure out the command to run to add the printer. Fire up Terminal and let’s figure out the commands to use. We will utilize the lpadmin command to get the printer on the system. For this post this is what our command will look like:

sudo lpadmin -p <name> -E -o printer-is-shared=false -v ipp://1.1.1.1 -D "<name>" -P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz"

That looks a little daunting, so let’s break it down a little bit.

-p <name>  This flag sets the name of the printer as seen by the cups process. Use a name with no spaces, or substitute underscores for the space.

-E  This flag enables the printer to accept jobs

-o printer-is-shared=false  The -o flag allows us to pass options to the printer. In this case we are making sure the printer is not shared on the network.

-v ipp://1.1.1.1  The -v flag sets the URI of the printer.

-D <name>  Where -p set the name the cups process saw, the -D flag sets what I call the “friendly” name, the name that is visible in the GUI.

-P <driver path>  Pretty self explanatory, the -P flag sets the path to the driver.

Now that we have everything, run the command in Terminal to add the printer. You can verify the printer added by using the lpstat -a command. With the printer added, open up a program and send a test print to the printer. It is important for us to do this step so that we know our handy work is working properly.

Put It In A Script

Let’s get to the script to add the printer. Open your favorite code editor (TextMate or Sublime Text for me) and start a new script. I utilize Bash, but you could just as easily do this in Python if you prefer. First we want to make sure the proper driver is on the system, and if it isn’t we want to install it.

if [[ ! -f "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz" ]]; then
/usr/local/bin/jamf policy -trigger xeroxGenericDriver
fi
view raw gistfile1.txt hosted with ❤ by GitHub

If the driver file is not on the system, we call the jamf binary to trigger our install policy. Adjust this to fit your management toolset.

Now with the driver check complete, we use a case statement to choose the printer (or printers) to install. We pass the choice to the script using Script Parameters in our Jamf Pro server policy. Here’s an example showing how we can install one printer, or multiple printers in an office.

lpa='/usr/sbin/lpadmin'
case $printer in
Printer1)
${lpa} -p Printer1 -E -o printer-is-shared=false -v ipp://10.1.1.1/ipp/print \
-D "Printer1" -P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz"
;;
Printer2)
${lpa} -p Printer2 -E -o printer-is-shared=false -v ipp://10.1.1.2/ipp/print \
-D "Printer2" -P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz"
;;
OfficePrinters)
${lpa} -p Printer1 -E -o printer-is-shared=false -v ipp://10.1.1.1/ipp/print \
-D "Printer1" -P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz"
${lpa} -p Printer2 -E -o printer-is-shared=false -v ipp://10.1.1.2/ipp/print \
-D "Printer2" -P "/Library/Printers/PPDs/Contents/Resources/Xerox WorkCentre 5955.gz"
;;
esac
view raw gistfile1.txt hosted with ❤ by GitHub

You can hopefully see the flexibility this provides us for using one script to install multiple printers. Sure, we still have multiple policies in the JPS, but rather than have multiple printers or multiple scripts as well, we can do this with just the one. And, when a printer needs to change, we just edit the script.

Bonus Round

What about adding printer options, like paper trays or output trays or setting a printer to B&W instead of color? We can use lpoptions to figure out what those options are and to set them. Since that can be a daunting task, head over to this post about using lpoptions to identify the settings.

Hopefully this post has helped you evaluate the use of a script to add printers and has given you a new tool for your toolbox.

Categories: Jamf Pro, Tech Tags: , , ,

Custom CrashPlan Install With Casper

February 12, 2016 Leave a comment

I’m a fanboy. There, I said it and I’m proud of it. I’m a fanboy of JAMF Software’s Casper Suite. I’m also a fanboy of Code42 and their CrashPlan software. Put them together and it’s like when the two teens discovered peanut butter and chocolate as an amazing combination.

I am all about trying to minimize the amount of time my users need to be interrupted due to IT needs. That’s a large part of the reason we use Casper, so that my users do not have to be inconvenienced. Let’s face it, the more time I take performing IT tasks on their computer that cause them to not be able to work, the less money they are making for our agency. It’s one of my primary tenets of customer support: make every reasonable effort to not disturb the end user, period. So when I discovered several of my end user machines were not backing up via CrashPlan, I needed to find a way to deploy CrashPlan with as little interruption as possible. In steps Casper and CrashPlan together.

Our original setup of CrashPlan that has been running for several years, was setup using local logins. At the time when we first deployed, we were not on a single LDAP implementation, so I didn’t want to deploy an LDAP integrated CrashPlan. Fast forward to now, and we have a single LDAP (AD) and I want to take advantage of that implementation to provide “same password” logins for my users.

Fortunately JAMF has a technical paper outlining how to do this, titled Administering CrashPlan PROe with The Casper Suite. This paper was written back when CrashPlan PROe was still a thing. With the release of version 5 of CrashPlan, it has now become simply Code42 CrashPlan. This document still works for the newer version of the software.

Get The Template

The first step is to get ahold of CrashPlan custom template for the installer. Following the paper, you can download the custom template by navigating to this URL:

http://YourServerAddress:4280/download/CrashPlanPROe_Custom.zip

NOTE: If you are deploying version 5 or higher of CrashPlan, you can use this URL to download a newer version of the kit:

http://YourServerAddress:4280/download/Code42CrashPlan_Custom.zip

While there are two different URLs, you can use either one to customize your install.

Edit Away

After downloading and expanding the zip file, you will need to edit the userInfo.sh file to set some settings. First of which is to hide the application from your users during installation. Simply set the following line:

startDesktop=false
view raw gistfile1.txt hosted with ❤ by GitHub

The next thing you will want to edit are the user variables. CrashPlan uses these variables to grab the user’s short name and their home folder location. An assumption is made when it comes to the user’s home folder, and that is the assumption that the home folder lives in /Users. If your home folders do not live there, or you want to script the generation using dscl, you can. I’m lazy and so I simply went with the /Users setting.

Also, the method to grab the user short name is based on the user that is logged in currently. Now, we didn’t discuss before how you were deploying this via Casper (login, logout, Self Service, etc), but suffice it to say, it is preferable to deploy this when a user is logged in to the computer. There have been many discussions on JAMF Nation about CrashPlan and how to grab the user, I used the information found in this post to grab the info I needed:

user=`/usr/bin/defaults read /Library/Preferences/com.apple.loginwindow lastUserName`
CP_USER_HOME="/Users/$user"
userGroup=`id -gn "$user"`
CP_USER_NAME="$user"
view raw gistfile1.txt hosted with ❤ by GitHub

Now that you have the edits done, keep going through the technical paper, running the custom.sh script next to build the Custom folder we will need in a minute, and to download the installers. The custom.sh script will download the installers for Windows, Mac, and Linux, and slipstream the Custom folder into the installer package for us. In our case, since we are only concerned with the Mac installer, it places a hidden .Custom folder at the root of the DMG. We want that folder. So follow along in the tech paper to mount the Mac installer DMG and copy the .Custom folder out somewhere.

Package It All Up

We are going to need to deploy these custom settings alongside the CrashPlan installer. The tech paper has you using Composer (no surprise since it is their product), but I personally like to use Packages for my packaging fun. I’m not going to get into a discussion about what the best packaging method is, because that’s like debating which Star Trek movie was the best.

Using your method of packaging, create a package that drops that Custom folder (notice we are dropping the period so it is not hidden) into the following location:

/Library/Application Support/CrashPlan

Now that we’ve got our custom settings, we can move over to the JSS to work on our deployment. I’m going to skip discussing how to do this via Self Service, and instead stick with either a Login trigger or Recurring Check-In trigger. But first things first, go ahead and upload that custom settings package you just created into the JSS. Once it’s uploaded set the priority to something low, like 8:

 

Screen Shot 2016-02-12 at 12.05.44 PM

Create Your Policies

The tech paper discusses uploading the CrashPlan installer along with the custom properties, but I like the method that is discussed in this JAMF Nation post. It’s towards the bottom, and basically it uses curl to download the installer from the CrashPlan server. This method insures you have the latest version for your server. Of course, if you are trying to deploy to end users around the globe that may not have curl access to your CrashPlan server, uploading the installer to Casper may be your only option. For me, however, it was not.

First step is to create a new script in the JSS (or upload a script if your scripts are not stored in the database). The script itself is nothing special, it checks for the presence of the CrashPlan launch daemon, and if it is there unloads it and removes CrashPlan. Then the script continues on to install the custom properties (via a second policy) and finally installs CrashPlan:

Screen Shot 2016-02-12 at 12.14.24 PM.png

Screen_Shot_2016-02-12_at_12_28_13_PM.png

#!/bin/sh
# unload CrashPlan LaunchDaem if it exists
if [[ -e /Library/LaunchDaemons/com.crashplan.engine.plist ]]; then
launchctl unload /Library/LaunchDaemons/com.crashplan.engine.plist
/Library/Application\ Support/CrashPlan/Uninstall.app/Contents/Resources/uninstall.sh
rm -rf /Library/Application\ Support/CrashPlan
fi
# install the custom properties folder
jamf policy -event CrashInstall
# now install CrashPlan
curl http://yourserveraddress:4280/download/Code42CrashPlan_Mac.dmg > /var/tmp/CP.dmg
hdiutil attach /var/tmp/CP.dmg
installer -pkg /Volumes/Code42CrashPlan/Install\ Code42\ CrashPlan.pkg -target /
hdiutil detach /Volumes/Code42CrashPlan
rm -rf /var/tmp/CP.dmg
view raw gistfile1.txt hosted with ❤ by GitHub

As you can see, I’m using a second policy to install the custom properties. You could do everything with one policy and two scripts, or one policy and curl the custom properties from another location. The key point is that if you are removing an existing installation (like I was), you cannot install the custom properties until you are done removing the existing. Make sense?

Now that we have all of our pieces and parts up there, you will create your two policies, one to install the custom properties and the other to run the script.

To Trigger Or Not To Trigger

With your policies created, you now need to determine how you want to trigger these policies. Obviously you will need to trigger one from within the script, but what about the main policy that kicks it all off? Well, I would probably do this via a recurring check-in trigger. It keeps the user from having to wait for the policy to complete before their login completes.

Of course, you could use the login trigger and throw up a nice notification using jamfHelper, Notification Center, or CocoaDialog. That sounds like a nice post for another day.

I Didn’t Do It

I cannot take the credit for this process. It was people like Bob Gendler and Kevin Cecil on JAMF Nation, along with the folks at JAMF and Code42, that did the heavy lifting. I just put it all into one location for me to remember later.

Upgrading Adobe Flash Player

December 18, 2015 1 comment

Recently on JAMF Nation there was a discussion about the Adobe Flash Player Distribution site going away. This site is where admins can go to get a copy of Flash that can then be legally distributed to their fleet of machines. The discussion started out to be about the change Adobe recently made to the URL for this site, but quickly turned to a discussion around distribution of Flash via Casper.

While I have signed up for the Adobe distribution site, I currently utilize a PKG file that comes from AutoPKGr (I replaced my Jenkins install with AutoPKGr last year sometime). Utilizing AutoPKGr makes my life easier, because I do not have to do anything except update my policy to replace the actual PKG file. I’m not going to go into setting up AutoPKGr for use with Casper, there have been plenty of discussions on that, but rather I am going to list out my procedures for processing Flash upgrades.

It’s Upgrade Day

I typically find out that there is a Flash upgrade from JAMF Nation. Someone typically posts that there is a Flash update almost immediately upon release. Once I’ve verified that the update has been uploaded to my JSS by AutoPKGr, I will go update my policy, changing out the PKG file.

As you will see, the policy is set to trigger on “Recurring Check-In” because I don’t care if a web browser is open or not. Flash can be installed while browsers are open, the users just have to restart the browsers that are open after the update. We’ll handle letting them know via a CocoaDialog script.

There are a few pre-requisite items we need to have in place for this process to work. First, we need to have a way to grab the Flash version off of the machines in our fleet. Second, we need to have a Smart Group that will capture all of the machines that are out of spec. This will allow us to scope our policy to those machines.

Grab the Version

I utilize an Extension Attribute to grab the version of Flash and store it in the database. While it can be argued that utilizing an EA to grab the version is not efficient, since the EA will run every time a Recon runs, there really isn’t another reliable method for grabbing the version.

So, setup an EA to grab the version of Flash. My EA is named “AdobeFlashVersion” and utilizes the following BASH script:

#!/bin/bash
FlashVersion=$(defaults read /Library/Internet\ Plug-Ins/Flash\ Player.plugin/Contents/Info.plist CFBundleShortVersionString)
echo "<result>$FlashVersion</result>"
exit 0
view raw gistfile1.txt hosted with ❤ by GitHub

That’s pretty straight forward. Now that we have the version, we can build our Smart Group.

Screen Shot 2015-12-18 at 5.38.04 PM.png

As you can see, just pick your EA name out of the list of criteria to search for, and enter the version you are searching for using the “is not” operator.

Policy Time

Now that we’ve got our Smart Group collecting machines that are out of date, we can build our policy to install the update. We will name our policy “Update Flash Player” and place it in whichever category makes sense to your deployment of Casper.

I have my update policy set to run at “Recurring Check-in”, which means that machines will update as soon as they contact the JSS. The frequency is set to “Once per computer”, since we only need it to run one time.

General

We’ll click on Packages next so that we can add our Flash package. Click on Configure to get a list of all packages in the JSS:

 

Screen Shot 2015-12-18 at 5.32.24 PM.png

We should now have a list of all packages that the JSS knows about. Locate our latest Flash Player package and click Add to add it to the policy:

Screen_Shot_2015-12-18_at_5_32_29_PM.png

I utilize a script that runs after Flash has been installed to notify end users to restart any open web browsers. My script uses CocoaDialog to make these notifications, but you can use the built in notification process that Casper has. The script I utilize is below:

#!/bin/sh
CD="/path/to/cocoaDialog.app/Contents/MacOS/cocoaDialog"
# pass the title, text, and Icon via $4, $5, $6, and timeout via $7
cdTitle=$4
cdText=$5
# what icon to use
# if no icon is given, set a default
if [[ -z "$6" ]]; then
cdIcon="/private/var/inte/icons/globeDownload.icns"
else
cdIcon=$6
fi
if [[ -z "$7" ]]; then
cdTimeout="--no-timeout"
else
cdTimeout="--timeout $7"
fi
bubble=`$CD bubble --title "$cdTitle" $cdTimeout --text "$cdText" --icon-file $cdIcon`
exit 0
view raw gistfile1.txt hosted with ❤ by GitHub

Now that we’ve added that script to our policy, we will add a line to the Files & Processes tab to set Flash to not auto update.

FilesAndProcesses.png

That line of information in the Execute Command box simply adds a line to a file called mms.cfg to tell Flash Player to not try to auto update. The line is:

touch /Library/Application\ Support/Macromedia/mms.cfg | echo "AutoUpdateDisable=1" > /Library/Application\ Support/Macromedia/mms.cfg
view raw gistfile1.txt hosted with ❤ by GitHub

The final thing for us to do is to add our Scope. Just click on the Scope tab at the top and add our Update Flash Smart Group:

Screen Shot 2015-12-18 at 6.01.26 PM.png

 

That’s all there is. Now that we have our update policy in place, each time there’s a new version we just have a few simple steps to update our end users:

  1. Get the new Flash package into the JSS
  2. Change our Smart Group to look for the new version number
  3. Change our policy to remove the old version and add the new version
  4. Finally, Flush All on the policy logs so everyone in the Smart Group gets the update.

 

I have been utilizing this method for updating Flash for well over a year now, and I have not had any troubles at all.

I hope this quick article has helped you out.

 

Categories: Tech Tags: , , ,

JAMF Nation User Conference 2014

October 28, 2014 Leave a comment

Wells Fargo BuildingEvery year as October gets closer, I get anxious. I know that at some point, usually toward the end of the month, I will be traveling up to Minneapolis for the JAMF Nation User Conference, JNUC. The conference is located at the Guthrie Theater in downtown, in the Mill district of Minneapolis, right on the Mississippi river. It’s one of my favorite locations to go to.

The JNUC is one of my favorite conferences to attend. Not just for the great content, but for the relationships that get formed and strengthened there. There are friends at JNUC that I’ve known for well over 10 years now, just from attending different conferences in the past. It’s great to catch up with these friends.IMG_0839

This year was also special because I was presenting there. I had the opportunity to present on imaging in a session titled “Unwrap the Imaging Enigma”.  It was a wonderful experience, and one that I will repeat again. Giving back to the community by presenting is important for any admin. If you’re interested in the slides, you can find them on my GitHub repository.

Now that I’ve called more attention to this blog, and to myself, I will try to post more relevant content regularly. If there is a topic you’d like to see, just post it in the comments and I’ll see if I can come up with something. Or reach out to me on Twitter: @stevewood_tx

Categories: Tech Tags: , , , ,