Posted 2019 March 16
I currently configure the printers in my Labs at work using a configuration profile. At one time, we used a shell script that leveraged
lpoptions — many admins still prefer using such commands. But since I wanted uniformity and didn’t want users to be able to mess with the settings, a profile seemed like the right choice for us.
There are a few ways to create the configuration profile needed, but probably the simplest is to leverage the capabilities of your MDM solution; many of those have the ability to create and deploy such a profile. If you’re not using an MDM (yet), a fairly simple way to create such a profile is to use Profile Manager (you will need a copy of macOS Server to use this method; Profile Manager is one of the few things still left in Server). In that method, you would install the printer drivers needed on the computer that has Server installed on it, manually configure the printer(s) you wish to include using the Printers & Scanners pane of System Preferences, then use Profile Manager to capture those settings and export a configuration profile. You can then install that profile on client computers using your preferred management system or via manual methods.
Normally, printer configurations in a Lab situation are pretty stable. It might be years before you need to change a printer in or out. Lucky me, I experienced two changes merely weeks apart: one printer swap and one deletion. This is where the learning began for me.
First was the good news: our large format printer was replaced with the latest and greatest model. This seemed like a pretty easy task: deploy the drivers to our Lab computers, update the configuration profile, deploy the profile and voilá. In many ways, it was that easy to get the new printer working. The only problem was that the printer we took off the network still showed up in the GUI when users were picking the destination printer for their job. So while we had 4 physical printers, it looked like we had 5. This was not a show stopper, since jobs sent to the decommissioned printer would simply go nowhere and need to be re-sent to the new printer. I had more urgent issues, like dealing with some dead hardware, which required putting a new computer into service quickly. So I put this support task in my support queue and prioritized it accordingly.
Before I could correct that printer picker problem, one of the other printers died. We decided that, for now, we would not replace this printer and would just operate with the remaining printers. So I built a new profile containing just those three printers and pushed it out. Now it had become a little more urgent to fix that printer picker issue, since only 3 of the 5 printers showing would be valid. To complicate matters further, that new computer I rushed into service never had the original profile deployed, just the updated version (i.e. after we deployed the new printer), so it was showing 4 printers in Print dialog boxes on that Mac. (This becomes important in a moment.)
Deleting Old Printers
My scale is small enough that I could have justified going into the Printers & Scanners preference pane to manually delete the extra printers, but there’s one problem with that: you can’t actually see the printers there. There’s a workaround where you enable printers that connect directly to the printer which apparently makes the list show up, but that’s not desirable in my environment, so I looked next to command line / shell commands.
You can delete a printer by sending the shell command
lpadmin -x printername. I knew the printer names I had assigned in the profile, but for some reason, using that name didn’t work. So I asked the system for the printers’ names using the
lpstat -v command. The output for most systems looked something like this (sanitized for publication):
device for mcx_0: dnssd://LaserPrinter._printer._tcp.local./auto device for mcx_1: dnssd://LargePrinterWeReplaced._printer._tcp.local./auto device for mcx_2: dnssd://SmallPrinterThatDied._printer._tcp.local./auto device for mcx_3: dnssd://SmallPrinterThatLives._printer._tcp.local./auto device for mcx_4: dnssd://NewLargePrinter._printer._tcp.local./auto
For you Mac Admin newbies, MCX stands for Managed Client for OS X. You may see reference to this acronym in some configuration profiles, but all you need to understand for the purpose of this discussion is that the printers were assigned an arbitrary name when they were created using a configuration profile, and that name is
mcx_#, where # is an integer, incrementing from zero.
So everything is awesome, right? I’ve determined that
mcx_2 are the names of the printers I need to kill. Except that I haven’t. Remember that new Mac I had to rush into production? The output for
lpstat -v was different because it never had the profile that included LargePrinterWeReplaced. It was more like this:
device for mcx_0: dnssd://LaserPrinter._printer._tcp.local./auto device for mcx_1: dnssd://NewLargePrinter._printer._tcp.local./auto device for mcx_2: dnssd://SmallPrinterThatDied._printer._tcp.local./auto device for mcx_3: dnssd://SmallPrinterThatLives._printer._tcp.local./auto
So if I had wantonly killed
mcx_1 on all my Lab computers, it would have come back to bite me. Again, because my scale is small enough, I could use a tool like Apple Remote Desktop to report the results of an
lpstat -v command on each station and determine the
mcx name of the printer(s) I would need to delete on each one. But it is certainly possible to determine this programatically. Depending on how you configure your printers, you could be looking for a name, a particular IP address, or something else in that printer URI that would uniquely indicate which printer you are seeking. In the above example, LargePrinterWeReplaced and SmallPrinterThatDied would be unique strings that identified the printers. I played with regular expressions and substitutions using
sed (which, to be clear, I am not particularly proficient in using) to come up with this command which could be used to return just the name of the printer that had the unique string in its URI:
lpstat -v | grep UniqueString | sed s/device.for.// | sed s/:.*$//
Once you have that value, you can then use it in an
lpadmin -x command. If you are in a Jamf shop, you might take the
lpstat command above (with your desired value in place of
UniqueString) and turn that into an Extension Attribute (EA), then set a policy that deletes the printer returned by the EA. If you’re creating a shell script, you might assign the results of the above command to a variable and then (if the value is not empty) delete the found printer using
lpadmin -x $variablename. Regardless of how you implement this in your shop, I strongly recommend you test and test again before deploying more widely, since it is destructive.
This seems like a pretty long blog post to just payoff with a single shell command. So why did I post it this way? A few reasons:
- It’s in my nature.
Those who know me know I can be loquacious. I like providing context and lots of it.
- I’m not the first person to encounter this problem.
One of the reasons to have a blog is to put problem solutions like this out in the world, reachable by every search engine, so that other people who have the problem can find a possible answer. The MacAdmin Slack is fantastic for problem-solving, quick questions, and interactive discussions. The fact that search engines can’t touch it means that we need to document our learnings outside of it. By posting in story form, a search is more likely to find a match that reveals this possible solution, since it’s hard to anticipate how someone might search for this topic.
- We learn through stories.
Sometimes, what I learned is not as important as how I learned it. Telling the story gives different readers the opportunity to get different things from the post. If you are a “get to the point” kind of person, you’ve probably already learned to skim my posts (if you read them at all).
Future Me may very well need this knowledge, and based on how long printers last, I might not need it for a few years. Specifics of the solution may or may not change, but I’m betting the process will be similar. It’s why the Minor in Computer Science on my Music degree from 1985 still pays dividends today. While the UNIX commands I used on mainframes way back when gave me a head start when the Mac adopted a UNIX-based OS, the main thing I learned from my studies long ago was process. I often say that the biggest thing my CPSC Minor taught me was how to get what I needed from a manual. So why not create my own manual?
I hope you got from this story what you needed today.
Updated 2019-03-17 to fix a typo (h/t Patrick Fergus).
 Technically, the printer was B.E.R.: Beyond Economic Repair. [Return to main text]
 I generally use the term URI instead of URL because that’s the W3C recommendation — there’s an entire W3C Note on the topic. In other posts, I have often used the more informal term URL for better readability, but this is a case where the protocol at the front of the URI is unlikely to be http(s). So URI felt right in this instance. [Return to main text]