Get list of printers online and available?

Shane wrote the script below years ago, and it’s terrifically useful (thank you, Shane…). I’ve spent the past few hours trying to figure out how to limit the list of printers to those that are online and available, and I can’t make any progress. Can anyone provide a pointer to the answer? Many thanks, as always.

EDIT: I found this thread, but can’t figure out how to adapt the Swift-related information linked at the end to AppleScript. I think what I want is PMPrinterState but that’s as far as I can get.

https://developer.apple.com/forums/thread/730231

-- Created 2015-08-11 by Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set theNames to current application's NSPrinter's printerNames() as list

set printerName to (choose from list theNames with prompt "Choose a printer:")
if printerName = false then error number -128

set thePrinter to current application's NSPrinter's printerWithName:(item 1 of printerName)

set thePrintInfo to current application's NSPrintInfo's sharedPrintInfo()

thePrintInfo's setPrinter:thePrinter

Unfortunately PMPrinterGetState is a C function not accessible from AppleScriptObjC. I fear you’re out of luck.

Thank you for this. I once managed to write an Objective-C program that did almost nothing, and it may be time to try again…

And, if I’m reading the documentation correctly (something that is NOT guaranteed), it seems that PMPrinterGetState doesn’t report whether a printer is onine or offline, so I’ll keep looking.

Maybe, you could use code from this list’s member, Naganoya-san, here
http://piyocast.com/as/archives/1291
or here
http://piyocast.com/as/archives/tag/nsnetservicebrowser

and adapt it using the printing related service types here:
https://android.googlesource.com/platform/external/avahi/+/refs/heads/master/service-type-database/service-types

No idea if this works on your system or meets your needs but there is also the command line giving you access to

lpstat -p -d

https://opensource.apple.com/source/cups/cups-450/cups/doc/help/options.html

and the likes. Maybe combining several approaches may help.

@peter - Unfortunately, current macOS lpstat doesn’t provide this information. The idea of adapting Naganoya-san’s code is interesting. I will see if I can figure out how to do it. Thank you.

This free app also could help

https://apps.apple.com/us/app/discovery-dns-sd-browser/id1381004916?mt=12

Thank you again, but this doesn’t help to get information that I can use in an AppleScript or shell script. I’ll keep looking…

Hm, but it certainly helps to see which printers answer to which service type query.
So if this doesn’t help, Naganoya-san’s code won’t help you either, I am afraid.

@peter - Now that I’m back at my home setup, it turns out that you’ve pointed me toward the answer. The command

dns-sd -B _printer._tcp

lists available network printers, and presumably variations on that command can list other printers. One difficulty is that the DNS name of a printer does not need to be the same as the macOS lpstat -p printer name or the queue name, but this can presumably be sorted out. Meanwhile, belated but heartfelt thanks.

1 Like

Interesting, never heard or read about dns-sd. Thanks!

It turns out that the answer to this was in an ancient thread where StefanK did all the work:

And a script that displays only networked IP printers is here. It’s horribly slow, but it seems to work (and I could probably get rid of quite a bit of it):

-- Display a list of available networked IP printers
-- by Edward Mendelson, using code adapted from many posts at MacScripter.net
-- requires "Bonjour Events" by Stefan Klieme, downloadable here:
-- http://www.klieme.ch/pub/Bonjour%20Events.zip

set noPrinters to 0
try
	set printerNames to (do shell script "lpstat  -l -p | grep -i Description: |awk -F'Description: ' '{print $2}' ") -- as list
on error
	set noPrinters to 1
end try
if printerNames = "" then
	set noPrinters to 1
end if
if noPrinters is 0 then
	try
		set queueNames to (do shell script "lpstat -a | awk -F' accepting' '{print $1}'") -- as list
	on error
		set noPrinters to 1
	end try
end if

if noPrinters = 0 then
	try
		set printerList to (every paragraph of printerNames) as list
		set queueList to (every paragraph of queueNames) as list
	end try
	
	set item_num to 0
	set ipPrinterList to {}
	repeat with j in printerList
		
		set thePrinter to j
		set item_num to item_num + 1
		set theQueue to (item item_num in queueList)
		
		set dnsURL to do shell script "lpstat -v " & theQueue
		set dnsString to (do shell script "perl -e 'use URI::Escape; print uri_unescape(\"" & dnsURL & "\")';")
		
		try
			tell application "Bonjour Events"
				scan type "_ipp._tcp" in domain "local"
				repeat until browser finished
					delay 0.5
				end repeat
				
				if (count services) > 0 then
					set nameList to name of services
					set addressList to IPv4 address of services
				else
					set nameList to {}
					set addressList to {}
				end if
				quit
				-- Bonjour Events quits automatically after 2 minutes of inactivity
			end tell
		on error errorMessage number errorNumber
			display dialog "An error occurred: " & errorMessage & " (" & errorNumber & ")"
		end try
		
		set ipPrinterFound to false
		repeat with currentItem in nameList
			if currentItem is in dnsString then
				set ipPrinterFound to true
				set currentListItem to currentItem as item
				set dnsNumber to my list_position(currentListItem, nameList)
				set printerIP to item dnsNumber in addressList
				copy thePrinter to the end of ipPrinterList
				-- tell me to activate
				-- display dialog thePrinter & return & return & "has the DNS instance name" & return & return & currentItem & return & return & "IP address:" & space & printerIP & return & return & "queue name:" & space & theQueue buttons {"OK"}
				exit repeat
			end if
		end repeat
		
	end repeat
	
	tell me to activate
	set chosenPrinter to choose from list ipPrinterList
	set chosenPrinter to item 1 of chosenPrinter
	set printer_num to my list_position(chosenPrinter, printerList)
	set theQueue to (item printer_num in queueList)
	display dialog "You chose:" & return & return & (chosenPrinter as string) & return & return & "queue name:" & return & return & (theQueue as string) buttons {"OK"}
	error number -128
	
else
	tell me to activate
	display dialog "No printers found!" buttons {"OK"}
	error number -128
	
end if

on list_position(this_item, this_list)
	repeat with i from 1 to the count of this_list
		if item i of this_list is this_item then return i
	end repeat
	return 0
end list_position

StefanK’s Bonjour Events app no longer seems to be available, and I see that there was once a version 2.1 of the app. It would be good to have it again.

Sorry, there were issues with my post. I’ll repost later.