A while back I wrote this application for our IT Helpdesk Technicians to use when they needed to install a printer on a Mac, and I thought I'd share the idea with the Pharos community. My goal was to give the Helpdesk staff an easy GUI interface to get printers installed quickly. I'd also be interested in hearing what everyone else has done when deploying printers to Macs. Our University is about 50% Macs out of over 1500 computers, so we get a lot of requests for printer installs.  I revisited this application recently since we are now looking at deploying printers via the Casper Suite JSS. Before Casper, however, this application has been very helpful for our Helpdesk.

 

Application Info

I will preface this by saying that I had never worked with AppleScript or SQLite before this project, so if things seem odd in the code, it's likely from just figuring it out as I went along.

 

The App was written in Apple's Script Editor program / the AppleScript language. It's saved as a .app file.

I called it the "Ultimate Pharos Installer" just for fun, since it can install any one of our printers on any MacOS from 10.6-10.10.

 

This application assumes you have created a SQLite 3 database file that contains one table named "pharos"

The "pharos" table needs to contain the following columns: "printqueue" "driver" "ppd" "location"

I've included a script (below) to help with this. I also recommend this app for updating the database when needed: DB Browser for SQLite

 

SQLite database items are formatted as following:

printqueue - matches the queue name in Pharos Administrator

driver - matches the file name of the driver installer package, without the .pkg extension

ppd - matches the file name of the ppd file for the printer, without the .ppd extension

location - whatever you want someone to see as the location option for the individual printer, such as building name.

 

Everything is bundled in a read-only DMG file which contains all drivers, ppd files, and the SQL database, and can then be run from a network share / any location.

The root of the DMG contains the actual .app file and a folder named ".Custom"

 

The .Custom folder contains all the other things that it needs to work.

grab1.png

There was a lot of up-front work to get all the drivers and PPD files configured (paper tray, installed options, etc). Once it was done, though, I only had to update the SQL file occasionally as we got new printers with new drivers, etc.

ppd.png drivers.png

 

 

Logic Summary:

The program basically looks if the computer has the Popup.pkg installed, and if not, installs it.

Then it presents the user with a choice: Choose a printer by location, or choose a printer from the entire list of every printer.

Once you choose a printer, it installs the correct driver, uses the correct PPD file, and gives a completion message.

 

Biola's printers are mostly either HP or Konica Minolta, so some sections of the code reflect that - setting values if it's a "bizhub" (KM) or not.

There are also a few drivers that need "exceptions" to the normal driver logic, which you can specify in the exceptions function.

Finally, the HP Driver pack from Apple is already installed on all of our computers, so I didn't need to include that with the installer, just the PPD files for most HP printers.

 

Action Shots:

Here's what it looks like:

action1.png action2.png

  action4.png  actino5.png

 

Application Code:

Copy and paste this in the Script Editor, then validate the code to see all the nice AppleScript syntax highlighting.  There are comments throughout to hopefully let you now the logic as you read it.

# Ultimate Pharos Installer

# Created by Alex Schumacher, October 2014

#

 

 

# Set Global Variables

global mySelectedPrinters

global myOS

global mySelectedBuilding

global myDriver

global old_delims

global driver_location

global ppd_location

global db_location

global pharos_server

 

# Set Values

set driver_location to "/Volumes/Ultimate_Pharos/.Custom/Drivers/"

set ppd_location to "/Volumes/Ultimate_Pharos/.Custom/PPD/"

set db_location to "/Volumes/Ultimate_Pharos/.Custom/printerDB.db"

set pharos_server to "popup://pharos.server.edu/"

set popup_installer to "/Volumes/Ultimate_Pharos/.Custom/Popup.pkg"

set popup_version to "8.4.1"

set popup_location to "/Library/Application\\ Support/Pharos/Popup.app/Contents/Info.plist"

 

# Automatically get the OS version and convert to number

set selectOS to system version of (system info)

if selectOS contains "10.9" then

  set myOS to 109

else if selectOS contains "10.10" then

  set myOS to 110

else if selectOS contains "10.8" then

  set myOS to 108

else if selectOS contains "10.7" then

  set myOS to 107

else if selectOS contains "10.6" then

  set myOS to 106

else if selectOS is false then

  error number -128

end if

 

# Set old_delims variable to reset text item delimiters when needed

set old_delims to AppleScript's text item delimiters

 

# Checks current version of Pharos Popup installed and installs newer version if needed

set theFile to "/Library/Application Support/Pharos/Popup.app"

 

tell application "System Events"

  if exists file theFile then

  set fileCheck to "true"

  else

  set fileCheck to "false"

  end if

end tell

 

if fileCheck contains "true" then

  set installedVersion to (do shell script "/usr/libexec/PlistBuddy -c print " & popup_location & " | grep CFBundleShortVersionString")

else

  set installedVersion to "9.999"

end if

 

 

if installedVersion contains popup_version then

# do nothing

else

do shell script "/usr/sbin/installer -pkg " & popup_installer & " -target / &> /dev/null & echo $!" with administrator privileges

end if

 

 

# Run Main Logic

ultimatePharos()

 

# See if the user wants to run the function again.

set whatDo to display dialog "Printers installed. Would you like to install more printers?" buttons {"Install More Printers", "Exit"}

if button returned of whatDo is "Install More Printers" then

ultimatePharos()

display dialog "Printers Installed." buttons {"Okay"}

else

  error number -128

end if

 

########## Functions ###########

# Shouldn't need to change anything down here except for the driver exceptions, if any

 

# Main Logic Function

on ultimatePharos() # This puts the whole thing in a function to be called again

# Have user choose what to do

  set firstChoice to display dialog "This is the Ultimate Pharos installer. You can either choose printers to install by building, or from a list of every printer on campus." buttons {"Printers by Building", "List All Printers", "Cancel"}

  if button returned of firstChoice is "Printers by Building" then

  select_by_building()

  printer_by_building()

  install_selected_printers()

  else if button returned of firstChoice is "List All Printers" then

  list_all_printers()

  install_selected_printers()

  else if button returned of firstChoice is "Cancel" then

  error number -128

  end if

end ultimatePharos

 

# Select Building Logic Function

on select_by_building()

# Making the list of buildings and remove duplicates

  set AppleScript's text item delimiters to {ASCII character 10} -- always a linefeed

  set building_list to (do shell script "sqlite3 " & db_location & " \"select location from pharos;\"")

  set building_string to (building_list as string)

  set new_string to do shell script "echo " & quoted form of building_string & " | sort -f"

  set new_building_list to (paragraphs of new_string)

  set final_building_list to {}

  repeat with x from 1 to count of items of new_building_list

  set n to item x of new_building_list

  if n is not in final_building_list then set end of final_building_list to n

  end repeat

  set mySelectedBuilding to choose from list final_building_list with prompt "Choose your Building" with multiple selections allowed

  if mySelectedBuilding is false then

  error number -128

  end if

  set getBuilding to "select printqueue from pharos where location = '" & mySelectedBuilding & "';"

  set AppleScript's text item delimiters to old_delims

end select_by_building

 

# Print Queue by Building Function

set AppleScript's text item delimiters to {ASCII character 10} -- always a linefeed

on printer_by_building()

  set printer_list to (do shell script "sqlite3 " & db_location & " \"select printqueue from pharos where location = '" & mySelectedBuilding & "';\"")

  set printQueues to {}

  set Queues to paragraphs of printer_list

  repeat with nextLine in Queues

  if length of nextLine is greater than 0 then

  copy nextLine to the end of printQueues

  end if

  end repeat

# Display the array to choose print queues.

  set mySelectedPrinters to choose from list printQueues with prompt "Choose your Print Queues" with multiple selections allowed

  if printQueues is false then

  error number -128

  end if

  return mySelectedPrinters

  set AppleScript's text item delimiters to old_delims

end printer_by_building

 

# List All Printers function

on list_all_printers()

  set AppleScript's text item delimiters to {ASCII character 10} -- always a linefeed

  set the_list to paragraphs of (do shell script "sqlite3 " & db_location & " \"select printqueue from pharos;\"")

  set list_string to (the_list as string)

  set new_string to do shell script "echo " & quoted form of list_string & " | sort -f"

  set new_printer_list to (paragraphs of new_string)

  set final_printer_list to {}

  repeat with x from 1 to count of items of new_printer_list

  set n to item x of new_printer_list

  if n is not in final_printer_list then set end of final_printer_list to n

  end repeat

  set mySelectedPrinters to choose from list final_printer_list with prompt "Choose your Print Queues" with multiple selections allowed

  if mySelectedPrinters is false then

  error number -128

  end if

  set AppleScript's text item delimiters to old_delims

end list_all_printers

 

# Install mySelectedPrinters function

on install_selected_printers()

  repeat with n from 1 to (count mySelectedPrinters) # Repeat for all printers in mySelectedPrinters variable

  # Make SQL call

  set head to "sqlite3 -column " & db_location & " " & quote

  set myPrinter to item n in mySelectedPrinters

  set dPrinters to "select driver, ppd from pharos where printqueue = '" & myPrinter & "';"

  # Set Driver and PPD info from SQL

  set {myDriver, myPPD} to words of (do shell script head & dPrinters & quote) # These last few lines are getting the PPD and Driver info from the database

  try

  set ppd_bizhub to ppd_location & myOS & myPPD & ".ppd" # Set the PPD location if a bizhub

  end try

  try

  set ppd_hp to ppd_location & myPPD & ".ppd" # Set the PPD location if not a bizhub.

  end try

 

  # Starts with site-specific exceptions, end with printers that fit the pattern in the database.

  driver_exceptions() # Installs the printer drivers, depending if they need them or not.

 

  #Install the printer and PPD file

  if myDriver contains "bizhub" then

  try

  do shell script "/usr/sbin/lpadmin -p " & myPrinter & " -D " & myPrinter & " -v " & pharos_server & myPrinter & " -E -P " & ppd_bizhub & " -o printer-is-shared=false" with administrator privileges

  end try

  else if myDriver contains "XeroxPrinterDrivers" then # another exception unique to the Xerox

  try

  do shell script "/usr/sbin/lpadmin -p " & myPrinter & " -D " & myPrinter & " -v " & pharos_server & myPrinter & " -E -P " & ppd_bizhub & " -o printer-is-shared=false" with administrator privileges

  end try

  else

  try

  do shell script "/usr/sbin/lpadmin -p " & myPrinter & " -D " & myPrinter & " -v " & pharos_server & myPrinter & " -E -P " & ppd_hp & " -o printer-is-shared=false" with administrator privileges

  end try

  end if

  end repeat

end install_selected_printers

 

# Driver Installation with Exceptions Function

# Set Exceptions as needed

on driver_exceptions()

#### HP M401n Exception ####

  if myDriver = "hpm401" and myOS as number is equal to 106 then

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & "hpm401/hp_m401_106_02.mpkg -target /" with administrator privileges

  do shell script "/usr/sbin/installer -pkg " & driver_location & "hpm401/hp_m401_106_03.pkg -target /" with administrator privileges

  do shell script "/usr/sbin/installer -pkg " & driver_location & "hpm401/hp_m401_106_04.pkg -target /" with administrator privileges

  do shell script "/usr/sbin/installer -pkg " & driver_location & "hpm401/hp_m401_106_05.mpkg -target /" with administrator privileges

  end try

  else if myDriver = "hpm401" and myOS as number is not equal to 106 then

  try

  do shell script "echo no_driver_needed"

  end try

  #### Xerox ColorQube 8570 Exception ####

  else if myDriver = "XeroxPrinterDrivers" and myOS as number is equal to 106 then

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & "106XeroxPrinterDrivers.pkg -target /" with administrator privileges

  end try

  else if myDriver = "XeroxPrinterDrivers" and myOS as number is not equal to 106 then

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & "XeroxPrinterDrivers.pkg -target /" with administrator privileges

  end try

  #### Bizhub 25 Exception ####

  else if myDriver = "gutenprintpcl" then

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & "gutenprintpcl.mpkg -target /" with administrator privileges

  end try

  else if myDriver = "none" then

  try

  do shell script "echo no_driver_needed"

  end try

  #### This is the logic if the printer isn't among the above exceptions ####

  else

  # Install Driver Package

  if myDriver contains "bizhub" then

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & myOS & myDriver & ".pkg -target /" with administrator privileges

  end try

  else

  try

  do shell script "/usr/sbin/installer -pkg " & driver_location & myDriver & ".pkg -target /" with administrator privileges

  end try

  end if

  end if

end driver_exceptions

 

Create SQL database script:

 

set loc to space & "/Set/Location/here/pharos.db" & space

set head to "sqlite3" & loc & quote

set tail to quote

-- "head" tells SQLite where to put our db if it doesn't exist, identifies it if it does.

-- "head" is the opening statement of every future command to our db.

-- "tail" ends every query started with "head".

 

-- Next, we set up a table and give the columns labels (there can be several).

-- Note the space between the semicolon (which ends every line) and the quote.

set tblName to "pharos"

set newTbl to "create table " & tblName & "(printqueue, driver, ppd,location); "

 

-- Now we set up the data to be entered in the table

set d2 to "insert into pharos values('bardwell209-bizhub','bizhubc364','bizhubc364e','Bardwell');"

set d3 to "insert into pharos values('bardwelloffice-bizhub','bizhubc364','bizhubc364e','Bardwell');"

set d4 to "insert into pharos values('bardwelloffice1','none','hp4200','Bardwell');"

set d5 to "insert into pharos values('bardwelloffice2','none','hpcolor2840','Bardwell');"

-- And finally, build the SQLite query and execute it

do shell script head & newTbl & d2 & d3 & d4 & d5 & tail

-- a new db called pharos.db should appear on your desktop!