Self Service Script for Printers in an AD environment.

Look
Valued Contributor III

Here is a little something I cooked up for adding AD printers using Self Service, Basically pulls the printer directory, selects a printer then tries to locate an appropriate local driver before adding the printer. Still needs some work but certainly works in our environment where all printers are one make (various models though) with most drivers already loaded.

It's built in such a away it would be simple to move the configuration into script parameters and it has limited support for a naming convention if your printers are named in a logical manner that includes some location data.

Anyway hope it saves someone else some time out there!

#!/bin/bash
# Samuel Look 2015, all care no responsibility.
# Checks AD printer list for printers that match the strings in the Yes_Filter(s) and doesn't match the strings in the No_Filter(s)
# If there is a naming convention in the directory names you can specify the field separator, the field with the location data, and the length of the location data to display.
# It will use the location data to prompt the user for a location and then display printers in that location otherwise if left empty it will simply display all matching printers.
# It checks AD for the model and tries to locate local drivers, removing the specification for PCL or PS if no driver is initially found, it displays an error if no drivers are found.
# It gets the path to the printer from AD and then attempts to add the printer.
# Finally it displays all printers currently installed.
# If you want to you can override the default protocol specified in AD, I have set this lpd as this worked in out environment.

##### CONFIG STARTS HERE #####

Name_Separator=""
Location_Field=""
Location_Length=""

Yes_Filter1=""
Yes_Filter2=""

No_Filter1=""
No_Filter2=""

Preferred_Protocol="lpd"
Machine_Domain=$(dscl /Active Directory/ -read . SubNodes | awk '{print $2}')

##### CONFIG ENDS HERE #####


##### SUB ROUTINES START HERE #####

Get_Location() {
The_Location=$(osascript <<AppleScript
set All_Locations to {$All_Locations}
set The_Location to {choose from list All_Locations with title "ADD Printer Wizard" with prompt "Please select a location:" OK button name "Show Printers"}
AppleScript
)
}

Get_Printer() {
The_Printer=$(osascript <<AppleScript
set Location_Printers to {$Location_Printers}
set The_Printer to {choose from list Location_Printers with title "ADD Printer Wizard" with prompt "Please select a printer:" OK button name "Install Printer"}
AppleScript
)
}

Display_Cancel() {
osascript <<AppleScript
set NOTHING to the button returned of (display dialog "No printer selected, cancelling the process" with title "ADD Printer Wizard" buttons {"Exit"})
AppleScript
}

Display_Install() {
The_Answer=$(osascript <<AppleScript
set The_Answer to the button returned of (display dialog "You selected to install $The_Printer" with title "ADD Printer Wizard" buttons {"Not Now","Proceed"})
AppleScript
)
}

Display_Driver_Error() {
osascript <<AppleScript
set NOTHING to the button returned of (display dialog "WARNING: Installation failed for $The_Printer drivers for model $The_Model not found! Install drivers and try again or contact the Service Desk on 9888 for assistance." with title "ADD Printer Wizard" buttons {"Exit"})
AppleScript
}

Display_Final() {
Current_Printers=$(lpstat -a | awk '{print $1}')
osascript <<AppleScript
set NOTHING to the button returned of (display dialog "Process complete, currently installed printers:

$Current_Printers" with title "ADD Printer Wizard" buttons {"Finish"})
AppleScript
}

Install_Printer() {
The_Model=$(dscl "/Active Directory/$Machine_Domain/All Domains" -read /Printers/${The_Printer} | awk '/MakeAndModel/,/ /' | tail -n1 | sed -e 's/^ //g')
echo ${The_Model}
if [[ "$The_Model" ]]; then
The_Driver=$(lpinfo -m | awk -F ".gz" '/'"$The_Model"'/ && /.gz/ {print $1 ".gz"}' | head -n1)
fi
if [[ ! "$The_Driver" ]]; then
The_Model=$(echo ${The_Model} | sed  -e 's/ PCL.*//g' -e 's/ PS.*//g')
The_Driver=$(lpinfo -m | awk -F ".gz" '/'"$The_Model"'/ && /.gz/ {print $1 ".gz"}' | head -n1)
fi
echo ${The_Driver}
if [[ "$The_Driver" = "" ]];then
Display_Driver_Error

else
Printer_Name=$(dscl "/Active Directory/$Machine_Domain/All Domains" -read /Printers/${The_Printer} | awk '/RealName/ {print $2}')
echo ${Printer_Name}
Print_Server=$(dscl "/Active Directory/$Machine_Domain/All Domains" -read /Printers/${The_Printer} dsAttrTypeNative:shortServerName | awk '{print $2}')
echo ${Print_Server}
Printer_Path=$(dscl "/Active Directory/$Machine_Domain/All Domains" -read /Printers/${The_Printer} | awk '/PrinterURI/ {print $2}')
Current_Protocol=$(echo ${Printer_Path} | awk -F ":" '{print $1}')
if [[ "$Preferred_Protocol" ]] && [[ "$Current_Protocol" != "$Preferred_Protocol" ]]; then
Printer_Path=$(echo ${Printer_Path} | sed -e s/$Current_Protocol:/$Preferred_Protocol:/g)
fi
echo ${Printer_Path}
lpadmin -p "${The_Printer}" -E -v "${Printer_Path}" -m "${The_Driver}" -o printer-is-shared="false" -o auth-info-required="default" -D "${Printer_Name} on ${Print_Server}"
Display_Final
fi
}

##### SUB ROUTINES END HERE #####


##### MAIN PROGRAM STARTS HERE #####
if [[ -z "$No_Filter1" ]]; then
No_Filter1="GarbageGarbageGarbage"
fi
if [[ -z "$No_Filter2" ]]; then
No_Filter2="GarbageGarbageGarbage"
fi

All_Printers=$(dscl "/Active Directory/$Machine_Domain/All Domains" -list /Printers | awk '/'$Yes_Filter1'/ && /'$Yes_Filter2'/ && /'$Name_Seperator'/ && !/'$No_Filter1'/ && !/'$No_Filter2'/ {print $0}')
if [[ -z "$Name_Separator" ]] || [[ -z "$Location_Field" ]] || [[ -z "$Location_Length" ]] ; then
The_Location=""
else
All_Locations=$(echo "$All_Printers" | awk -F "$Name_Separator" '{print $'$Location_Field'}' | cut -c 1-$Location_Length | sort -u | tr "
" " " | sed -e 's/ $/"/g' -e 's/^/"/g' -e 's/ /","/g')
Get_Location
fi
echo ${The_Location}
if [ "${The_Location}" != "false" ]; then
Location_Printers=$(echo "$All_Printers" | awk '/'$The_Location'/' | tr "
" " " | sed -e 's/ $/"/g' -e 's/^/"/g' -e 's/ /","/g')
Get_Printer
echo ${The_Printer}
fi

if [ "${The_Printer}" != "" ] && [ "${The_Printer}" != "false" ]; then
Display_Install
fi

if [ "${The_Answer}" == "Proceed" ]; then
Install_Printer
else
Display_Cancel
fi

##### MAIN PROGRAM ENDS, THANKS FOR PLAYING #####
3 REPLIES 3

sean
Valued Contributor

FWIW, we just push the drivers for our printers to all macs and then add the users to lpadmin group. This then allows them to just select their local printer in System Preferences as they would for their own home printer.

The only gotcha with this is that you may need to edit the Nickname in the printer driver config PPD file.

geoffreykobrien
Contributor

What would really be awesome, if you pumped up the printers through API to your JSS once they are added....

Look
Valued Contributor III

@sean yeah the actual reason behind this in our environment is we have the building name included in the printer naming scheme so this script prompts for the building then lists just the printers in that building, given we have a large humber of printers this simplifies the process for the users, it also has a companion script alongside it in Self Service for listing a removing installed printers. Someone asked about AD printers and I realised it would be quite easy to make the script organisation agnostic(ish) which would also help us internally if we ever change vendors (we use the filter part to make sure it only shows printers from the latest vendor and none of the accidentally shared / never removed printers in the directory.