MacAdmins have known for several years now that PPD files are deprecated and AirPrint is the way forward. However many of us have put off transitioning due to a lack of automated configuration options.
That all changed with the HP Printer Driver Certificate Fiasco of October 2020. With the first official remediation option being to reconfigure using AirPrint, this project suddenly moved up the to-do list for many admins, myself included.
Instead of continuing to make users sit through lengthy installs of HP’s enormous driver packages I decided to build on the work of others and create AirPrint_Generator. Read on for the details.
I have long used Nick McSpadden‘s Printer Generator to create Munki NoPkgs that allow standard users to install printers via Managed Software Center. The CSV option makes it easy for me to keep all our printer configurations in source control and using Managed Software Center is familiar for users.
AP Orlebeke (apizz) did most of the legwork needed to accomplish our goal last year. This includes identifying the ipp2ppd tool and process used when a user manually adds an AirPrinter in System Preferences. AP also wrote a preinstall_script for use in the Munki NoPkg that was the basis of my work.
The only caveat with AP’s script was a generic printer icon in System Preferences when the AirPrinter was created using root, such as with Munki or Jamf. This doesn’t effect usability but I wanted to see if I could come up with a workaround.
Workaround using Outset
After trying a number of things I settled on leveraging Outset to programmatically generate the PPDs and icons identical to those created when installing an AirPrinter via System Preferences.
The only downside to this workaround is that printers can only be installed when a user is logged in. This is no problem for self-service installs, but might not be desirable in lab situations or if you want to have printers be managed installs.
Using this preinstall_script, Munki will write out a script to Outset’s on-demand folder and then trigger it as the user to generate the PPD and icon. Afterwards it will proceed with the printer installation as normal.
#!/bin/zsh ## Programmatically generate an Outset on-demand script that will create the AirPrint PPD # Check for a logged in user so we don't attempt this at the login window currentUser=$(stat -f %Su "/dev/console") if [[ "$currentUser" == "root" ]] then echo "No user is currently logged in, exiting." exit 1 fi # Define the script line1="#!/bin/zsh" line2="/System/Library/Printers/Libraries/ipp2ppd ADDRESS everywhere > /tmp/PRINTERNAME.ppd" # Write it to disk echo $line1 > /usr/local/outset/on-demand/PRINTERNAME-PPD-Generator.sh echo $line2 >> /usr/local/outset/on-demand/PRINTERNAME-PPD-Generator.sh # Fix the permissions so Outset will execute it /bin/chmod 755 /usr/local/outset/on-demand/PRINTERNAME-PPD-Generator.sh # Trigger an Outset on-demand run so the logged in user will execute the script /usr/bin/touch /private/tmp/.com.github.outset.ondemand.launchd # Give it time to run sleep 10 # Make sure it all worked and the PPD is where we want it before attempting to install the printer if [[ ! -f /tmp/PRINTERNAME.ppd ]] then echo "The PPD doesn't exist where expected, exiting.'" exit 1 fi
We have Outset deployed across the fleet and use it for a number of things so incorporating it for this workaround doesn’t present an additional burden. However since I didn’t want to impose a dependency on everyone who uses the script I also created a version that does everything as root.
This much simpler version of the preinstall_script can be run without a user logged in. The printers work the same, they just all have generic icons in System Preferences. You can still specify the correct icons for use in Managed Software Center as always.
If you and your users won’t notice or don’t care about the generic icons then definitely use this version of the script. It installs much faster and the lower complexity means there is less that can go wrong.
#!/bin/zsh ## Generate the AirPrint PPD using ipp2ppd /System/Library/Printers/Libraries/ipp2ppd ADDRESS everywhere > /tmp/PRINTERNAME.ppd # Make sure the PPD is where we want it before attempting to install the printer if [[ ! -f /tmp/PRINTERNAME.ppd ]] then echo "The PPD doesn't exist where expected, exiting.'" exit 1 fi
Both versions of the script, AirPrint_Generator.py and AirPrint_Generator_Outset.py, are available in my fork of PrinterGenerator on Github. An updated version of the original print_generator.py is there as well of course.
Eventually I would like to combine all three scripts into a single version with arguments to specify if you want AirPrinters (with or without the Outset option) when it is run. But for now I thought it best just to put the scripts out there so others can use or improve upon them.
There are a couple things to keep in mind when transitioning to AirPrint from traditional driver installations.
First, AirPrint works over ipp:// so make sure to specify that protocol or only an IP for the address. The scripts will add ipp:// if it is missing but there is no logic to change an incorrect protocol such as lpd, socket, etc.
Second, the installs will only work if the computer can route to the printer at the time of install. This direct connection is needed to generate the AirPrint PPD on the fly. With traditional installs this was not a concern since the PPD was already on disk.