AirPrint Generator

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.

Building Blocks

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

No Outset

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

Download

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.

DOWNLOAD: https://github.com/kevinmcox/PrinterGenerator

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.

Notes

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.


If you have any suggestions, thoughts or questions please reach out, leave a comment or join us in the #printers-n-cups channel on the the MacAdmins Slack for more discussion.

6 comments on “AirPrint Generator

  1. Mikael Lofgren

    Nice work!
    Have you tried to add this line to the PPD
    *APPrinterIconPath: “/Library/Printers/Icons/HP_LASER JET1818.icns”
    That should match the filepath to the printer .icns file
    Im been thinking something like this:

    #!/bin/sh
    PRINTERNAME=”HP_LASER JET1818″
    PRINTER_IP=192.168.1.10

    # Download icon with curl from printer or from Munki should work
    curl http://$PRINTER_IP/ipp/images/printer-large.png -o “/tmp/$PRINTERNAME.png”
    # Make sure its a common size 512 px seems to be standard
    sips -z 512 512 /tmp/”$PRINTERNAME”.png –out /tmp/”$PRINTERNAME”_512.png
    # Convert it to .icns and save to /Library/Printers/Icons/
    sips -s format icns /tmp/”$PRINTERNAME”_512.png –out /Library/Printers/Icons/”$PRINTERNAME”.icns
    # Add Iconpath to PPD file
    echo “*APPrinterIconPath: \”/Library/Printers/Icons/$PRINTERNAME.icns\”” >> /tmp/$PRINTERNAME.ppd

    Reply
    1. Kevin M. Cox Post author

      Good thought, looks like that would be another workaround for the icon issue. Thanks for sharing.

      Reply
  2. Pingback: Weekly News Summary for Admins — 2020-12-04 – Scripting OS X

  3. Matthias Choules

    Thanks for your work! Based on these pieces we have come up with another solution for the icon issue. We do a query with ipptool, gather the urls of the printer-icons, download them, and generate the needed iconset/icns file on the fly. Mikaels approach assumes a static URL for the images, which does not seem to work with different printer makes.

    May be helpful for others as well:
    https://github.com/wycomco/airprint-ppd

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *