Solving Problems With python-jss: Finding the Printers in the Policies

I wanted to start showing some short examples of easy and quick python scripts that I have used in my day-to-day admin job. Today I got around to working on a broken printer installation. One of our printers had a driver that was not working, and needed to be switched out.

Adding the package to the JSS and creating an update policy was no big deal, but I wanted to know exactly which policies distributed that printer. If you need to change a printer’s PPD file, you have to remove and then re-add a printer; and when you remove a printer from Casper Admin, that printer gets silently dropped from all policies as well. We have a large number of policies, and I don’t like to make mistakes, so I wanted to get this right the first time.

python-jss to the rescue!

I of course already have my python-jss preferences set up (see the Wiki!), so we can start with:

    import jss
    jss_prefs = jss.JSSPrefs()
    j = jss.JSS(jss_prefs)

and we have a functioning JSS object.

Next, we are interested in looking at Policies, so let’s grab them:

    all_policies = j.Policy().retrieve_all()

Notice that I skip the intermediary step of assigning the results of j.Policy() to a variable. This would just give us a list of policy ID’s and names, which isn’t enough information. We want the entire XML for the policies.

Speaking of which, we need to know a little bit about the structure of a policy to be able to find the data that we’re interested in (we can’t just “Find”) through the whole text, since this is XML, and structure is important! So, doing a little research, I pulled up one of my printer-installer policies and looked at the relevant data. Here’s how to do it, and what it looks like (I trimmed out all of the unimportant stuff):

    >>> j.Policy(287)
            <name>Install PS Classroom  and Faculty Printers</name>

So we can see that a policy has a “printers” section, with a list of “printer”s. Each “printer” has its user-facing name in a subelement named “name”. Also, the policy has an ID and a name which I’m interested in because I want to make sure I know how to identify them later. Fortunately, pretty much all JSSObject subclasses have a convenience accessor for .id and .name.

Now, we just loop through all of the policies looking for a printer with the name we’re looking for; in this case “LSCopier”. This is slightly challenging because it involves using the interface to ElementTree.Element. Let’s look at the fully expanded version first:

    for policy in all_policies:
        for printer in policy.findall('printers/printer'):
            if printer.findtext('name') == 'LSCopier':
                print('Printer found in ID %s: %s' %

Running this short (10 lines) gets me my results. Indeed, I could probably parameterize this and re-use it later… Which I’ll do next. Also, let’s trim it up into a list comprehension.

            results = [(, for policy in all_policies
                       for printer in policy.findall('printers/printer')
                       if printer.findtext('name') == search_name]

(There’s no way this will fit on a single line in this theme… Sorry!) This nets us a “results” array filled with tuples of policy names and ids that match our argument “search_name”. To pull this off we need to import sys, and make a few more changes.

Here is the entire finished script:

    import sys
    import jss
    jssPrefs = jss.JSSPrefs()
    j = jss.JSS(jssPrefs)
    if len(sys.argv) > 1:
        all_policies = j.Policy().retrieve_all()
        for search_name in sys.argv[1:]:
            print "Searching for %s" % search_name
            results = [(, for policy in all_policies
                       for printer in policy.findall('printers/printer')
                       if printer.findtext('name') == search_name]
            for result in results:
                print('Found in %s: %s' % result)

This would be easy to expand into a more general XML search utility for auditing your Policies. For example, you may want to search for policies that install a particular package (although jss_helper already does that). Or you might want to search for policies that Recon.