nmcspadden / printergenerator Goto Github PK
View Code? Open in Web Editor NEWGenerate specific pkginfos for printers with nopkg method
License: Apache License 2.0
Generate specific pkginfos for printers with nopkg method
License: Apache License 2.0
From @pexner on MacAdmins Slack #munki:
A public request to anyone who can code and wants to add a very cool feature to PrinterGenerator:
It seems possible to grab also the corresponding printer icon for munki!
It can be easily found inside the PPD used! Just search for *APPrinterIconPath:
inside the PPD used. You'll see the /path/to/the/printerXXX.icns
file.
I contaced Nick and he answered: I have no plans to add that feature, but I welcome Pull Requests 🙂 I don't use this particular tool anymore and I have no spare time to work on it.
Is someone interested and able to make this possible, I'll pay in beer. (German beer, no sugar, no artificial flavours!)
Having the beautiful, corresponding printer icon in the optional installs would be cool.
The pkginfo resulting from either --csv or cli import shows (for an example HP 1600 printer):
"printer-make-and-model":"HP1600dn.ppd"
but when running msu -v:
Settings mismatch: printer-make-and-model is 'HP LaserJet Professional P1600dn, 6.9', should be 'HP1600dn.ppd'
What license is this released under? Apache would be preferable!
Suggestion to modify the postinstall script as listed below to check for existence of PPD before creating print queue. (OSX has a yucky tendency when PPD is not found to create a queue as "raw" which is visible in CUPS but not in the GUI System Preferences app.)
Relevant section:
postinstall_script
#!/usr/bin/python
import subprocess
import sys
import os.path
if not os.path.exists( "DRIVER" ):
print "PPD DRIVER not found."
sys.exit(1)
printerOptions = { OPTIONS }
Full, modified template file:
autoremove catalogs testing description DESCRIPTION display_name DISPLAY_NAME installcheck_script #!/usr/bin/python import subprocess import sys import shlexprinterOptions = { OPTIONS }
cmd = ['/usr/bin/lpoptions', '-p', 'PRINTERNAME', '-l']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpoptLongOut, lpoptErr) = proc.communicate()
if lpoptErr:
print lpoptErr
sys.exit(0)
cmd = ['/usr/bin/lpoptions', '-p', 'PRINTERNAME']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpoptOut, lpoptErr) = proc.communicate()
for option in lpoptLongOut.splitlines():
for myOption in printerOptions.keys():
optionName = option.split("/", 1)[0]
optionValues = option.split("/",1)[1].split(":")[1].strip().split(" ")
for opt in optionValues:
if "" in opt:
actualOptionValue = opt.replace('', '')
break
if optionName == myOption:
if not printerOptions[myOption] == actualOptionValue:
print "Found mismatch: %s is '%s', should be '%s'" % (myOption, printerOptions[myOption], actualOptionValue)
sys.exit(0)
optionDict = dict()
for builtOption in shlex.split(lpoptOut):
optionDict[builtOption.split("=")[0]] = builtOption.split("=")[1]
comparisonDict = { "device-uri":"ADDRESS", "printer-info":"DISPLAY_NAME", "printer-location":"LOCATION", "printer-make-and-model":"DRIVER" }
for keyName in comparisonDict.keys():
if not comparisonDict[keyName] == optionDict[keyName]:
print "Settings mismatch: %s is '%s', should be '%s'" % (keyName, optionDict[keyName], comparisonDict[keyName])
sys.exit(0)
sys.exit(1)
installer_type
nopkg
minimum_os_version
10.7.0
name
AddPrinter_DISPLAYNAME
postinstall_script
#!/usr/bin/python
import subprocess
import sys
import os.path
if not os.path.exists( "DRIVER" ):
print "PPD DRIVER not found."
sys.exit(1)
printerOptions = { OPTIONS }
cmd = [ '/usr/sbin/lpadmin', '-x', 'PRINTERNAME' ]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminxOut, lpadminxErr) = proc.communicate()
cmd = [ '/usr/sbin/lpadmin',
'-p', 'PRINTERNAME',
'-L', 'LOCATION',
'-D', 'DISPLAY_NAME',
'-v', 'ADDRESS',
'-P', "DRIVER",
'-E',
'-o', 'printer-is-shared=false',
'-o', 'printer-error-policy=abort-job' ]
for option in printerOptions.keys():
cmd.append("-o")
cmd.append(str(option) + "=" + str(printerOptions[option]))
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminOut, lpadminErr) = proc.communicate()
if lpadminErr:
print "Error: %s" % lpadminErr
sys.exit(1)
print "Results: %s" % lpadminOut
sys.exit(0)
unattended_install
uninstall_method
uninstall_script
uninstall_script
#!/bin/bash
/usr/sbin/lpadmin -x PRINTERNAME
uninstallable
version
VERSION
Testing out this on Catalina and I noticed that the Install Check Script via munki says all the printers are installed even when they are not, but on Mojave everything is working as intended. Is this known to currently not work on catalina?
Hello,
this is probably not a real issue of PrinterGenerator then more an issue with the lpoptions
command. When the installcheck_script
is run on a client which is in same bonjour broadcast domain as the printer and that printer is using bonjour. The output of lpoptions -p printername
on client is that what is announced by bonjour not want is used to configure the printer.
If you use lpd://10.0.0.1
to configure the printer but the printer is broadcasting its services via Ipp://bonjourname._ipp._tcp.local./
as well, the output of lpoptions
on the client if it is in the same subnet will be Ipp://bonjourname._ipp._tcp.local./
. The installcheck_script
will fail and the munki will try to install the printer again and again ;-)..
I have no cloud how to handle this but it drove me insane until I run lpoptions -p printername
while no printer was configured...
Hello
i have this issue with canon printer. I use the csv method. Hp or Xerox printer doesn't create the error. With files is useful for you ?
Traceback (most recent call last):
File "/tmp/munki-yzwmz7/installcheck_script", line 41, in
optionDict[builtOption.split("=")[0]] = builtOption.split("=")[1]
It would be nice if the script could look at all of the pieces, collectively including the version so that updates could easily be made to the printer. This way the installer could be updated without modifying the printer name.
This may not be an issue in your environment and we've been happy with the older method that you posted.
Just a thought.
Original thread information:
Ran into another issue. I used the updated tool to make the new pkginfo file, which worked and put in the correct settings for the device and address. I tried to indicate the new version at 0.3 and added it to my repo. Here is the the pkginfo file and associated output.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>autoremove</key>
<false/>
<key>catalogs</key>
<array>
<string>testing</string>
</array>
<key>description</key>
<string></string>
<key>display_name</key>
<string>Maintenance WC3325</string>
- show quoted text -
'-D', 'Maintenance WC3325',
'-v', 'lpd://10.0.10.92',
'-P', '/Library/Printers/PPDs/Contents/Resources/Generic_PCL_OSX.ppd',
'-E',
'-o', 'printer-is-shared=false',
'-o', 'printer-error-policy=abort-job' ]
for option in printerOptions.keys():
cmd.append("-o")
cmd.append(str(option) + "=" + str(printerOptions[option]))
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(lpadminOut, lpadminErr) = proc.communicate()
if lpadminErr:
print "Error: %s" % lpadminErr
sys.exit(1)
print "Results: %s" % lpadminOut
sys.exit(0)</string>
<key>unattended_install</key>
<true/>
<key>uninstall_method</key>
<string>uninstall_script</string>
<key>uninstall_script</key>
<string>#!/bin/bash
/usr/sbin/lpadmin -x MaintenanceWorkCentre</string>
<key>uninstallable</key>
<true/>
<key>version</key>
<string>0.3</string>
</dict>
</plist>
verbose output:
* Processing manifest item AddPrinter-MaintenanceWorkCentre for install
Looking for detail for: AddPrinter-MaintenanceWorkCentre, version latest...
Considering 1 items with name AddPrinter-MaintenanceWorkCentre from catalog testing
Considering item AddPrinter-MaintenanceWorkCentre, version 0.3 with minimum os version required 10.7.0
Our OS version is 10.10.3
Found AddPrinter-MaintenanceWorkCentre, version 0.3 in catalog testing
Running installcheck_script for AddPrinter-MaintenanceWorkCentre
installcheck_script returned 1
AddPrinter-MaintenanceWorkCentre version 0.3 (or newer) is already installed.
Looking for updates for: AddPrinter-MaintenanceWorkCentre
Looking for updates for: AddPrinter-MaintenanceWorkCentre-0.3
Looking for updates for: AddPrinter-MaintenanceWorkCentre--0.3
MSC recognizes that it is installed (indicating version 0.3 as the current version) and allows for removal of the printer. When removing the printer, it removes without issue. If I then re-install the printer, it installs with the updated information from version 0.3 (correct address and such).
Thoughts?
May 22
Did the versioning not trigger correctly on the post-install script because the address of the printer in question was different from version 0.1 to 0.3?
=== You ===
The installcheck_script compares the options that are specified by lpoptions. If there is no change in any of the printer options, and the printername is the same, the pkginfo won't overwrite the existing print queue, because it thinks it's installed. The idea is that the reinstall will trigger if the queue is removed, or you have new options to specify.
The version number of the pkginfo is more for admin sanity than anything else - the version number isn't actually used to make any determination about installing.
But that raises the good idea that I should make a check on all specifiable options - including the address, display name, etc. Could you please file a GitHub issue about that?
I'm encountering this error when trying to create a noplkg for follow_me print queue.
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 81: ordinal not in range(128)
Direct connection isn't a problem, and running an lpadmin command with the same settings creates the queue etc, correctly.
I got the following error when using the script:
$ ./print_generator.py --csv paf_printers.csv
Traceback (most recent call last):
File "./print_generator.py", line 46, in <module>
theOptionString = getOptionsString(row[6].split(" "))
File "./print_generator.py", line 13, in getOptionsString
for option in optionList.split(" "):
AttributeError: 'list' object has no attribute 'split'
The CSV was fine:
https://gist.github.com/anonymous/9ee79c76768ddd29c448
People wiser than me looked at the code, and provided the following bandaid:
https://gist.github.com/arubdesu/120a83a10025695f3be9
With the following comments:
allister [4:03 PM]
insert a newline at line 13
allister [4:03 PM]
use proper indentation, then
allister [4:03 PM]
optionList = str(optionList)
allister [4:04 PM]
he’s not validating what type is passed, it should really be a try/except and in case of exception convert to string, which still may end up with garbage data
allister [4:04 PM]
not that I understand everything that went into this
Hopefully this will help you figure out what happened.
First off:
Thanks for this tool, made printers easier for me before this update. I am sure this update will rock just as much.
I am having one issue trying to get it running:
$ python print_generator.py --address '10.115.100.44' --printername 'WIAD_TechServ_01' --driver 'HP LaserJet P4010 Series.gz' --location 'Willson Suite 220, RM 222A' --displayname 'TechServ Upstairs' --desc "Adds TechServ Upstairs Printer to your machine" --version '2.0'
Traceback (most recent call last):
File "print_generator.py", line 114, in
newPlist['installcheck_script'] = newPlist['installcheck_script'].replace("OPTIONS", optionsString)
NameError: name 'optionsString' is not defined
Removed the entire dir, and re-ran a git clone. Same issues. Not 100% sure but as far as I can read into the script it's not seeing that optionsString as existing or being optional.
Have you seen this @nmcspadden?
It's from my Sal, reporting on my Munki nopkg printer setup.
It started with 10.15 (could have been 10.15.1, not entirely sure).
Don't know if you're interested, but now I've reported it anyway... :)
I'm getting this error on a set of printers. Is it possible to change the install-check script to be case-insensitive for options?
Running installcheck_script for AddPrinter_FindMeBW
Found mismatch: FXHighCapacityFeeder is 'TRUE', should be 'True'
installcheck_script returned 0
I have loaded in Apple's FujiXerox print drivers and pushed them out via Munki. However, when I create printers using PrinterGenerator, I found that the installation check script returns a not-installed status even after successful installation.
On investigation, I found that the install check script is comparing an expected printer-make-and-model key with what it reads from the installed printer, and this is not matching exactly.
The expected key is “FX ApeosPort-V C3373 PS” which I presume is being pulled from somewhere inside the PPD. However, the key returned to the check script is actually “FX ApeosPort-V C3373 PS v3018.103 PS” which is the same as what as expected except that it has the version number injected.
To work around this, I edited the AddPrinter-Template.plist file and removed the "printer-make-and-model":"DRIVER" comparison from the comparisonDict declaration. After recreating my printer definitions, I found that the installed printers pass the install check script based on the remaining three comparisons in the comparisonDict object.
Printers were created by running against a CSV with a good number of printers. I did not test this with a one-off run, but I expect it would behave the same as the change was made in the AddPrinter Template. GitHub is saying “Something went really wrong” when I try to attach my Template file, but I will paste it below.
Printer Name | Location | Display Name | Address | Driver | Description | Options |
---|---|---|---|---|---|---|
ICTLabBW | ICT Lab | ICT Lab B&W | 10.30.248.145 | FX ApeosPort-V C3373 PS.gz | FX ApeosPort-V C2275 | FXColorMode=Black |
ICTLabColour | ICT Lab | ICT Lab Colour | 10.30.248.145 | FX ApeosPort-V C3373 PS.gz | FX ApeosPort-V C2275 |
Thanks for this script - I'm in the process of migrating from Graham's project to this one, due to the whole Python 2 to 3 transition.
One of my printer configs references Apple's generic driver:
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/Resources/Generic.ppd
Is there any way to specify that driver in the CSV file?
On almost every munki-run all the printers try to re-install themselves (on mojave at least)
I'm pretty sure this is because the OS is arbitrarily changing my LPD printer URLS to IPP:
From ManagedSoftware.log:
Settings mismatch: device-uri is 'ipp://ajw-451._ipp._tcp.local./', should be 'lpd://192.168.10.130'
From AddPrinter-ajw_451-2.0.pkginfo
# Install the printer
cmd = [ '/usr/sbin/lpadmin',
'-p', 'ajw_451',
'-L', '',
'-D', '',
'-v', 'lpd://192.168.10.130',
'-P', "/Library/Printers/PPDs/Contents/Resources/HP LJ 300-400 color M351-M451.gz",
'-E',
'-o', 'printer-is-shared=false',
'-o', 'printer-error-policy=abort-job' ]
If the printer-location is 'Nick McSpadden's Office', it can install okay if you escape the quotation mark.
But then if you run the installcheck_script, the script will choke with raise ValueError, "No closing quotation"
In the now archived https://github.com/grahamgilbert/printer-pkginfo, you could specify a default catalog to import the printer to, which I liked.
It appears that this is not available via the command line or in the CSV file template, and instead defaults to "testing".
Would love to be able to specify a default catalog for importing
This may be a problem with lpoptions and not PrinterGenerator itself, but it may be worth putting in a workaround.
If you run the script on a regular HP LaserJet P4010 Series, the installcheck_script will think the printer is not installed:
Settings mismatch: printer-make-and-model is 'HP LaserJet P4010 Series', should be 'HP LaserJet P4010_P4510 Series'
Likewise for P2015:
Settings mismatch: printer-make-and-model is 'HP LaserJet P2015 Series', should be 'HP LaserJet P2015'
If the location is blank then the check script fails.
Imported in printer via csv with no location defined.
Printer installs fine, no location, check script fails with error below.
Feb 19 2019 12:13:24 -0800 Traceback (most recent call last):
Feb 19 2019 12:13:24 -0800 File "/tmp/munki-62Cn03/installcheck_script", line 49, in
Feb 19 2019 12:13:24 -0800 optionDict[keyName] = None if keyName not in optionDict or optionDict[keyName].strip() == "" else optionDict[keyName]
Feb 19 2019 12:13:24 -0800 AttributeError: 'NoneType' object has no attribute 'strip'
When I run ./print_generator.py --csv ./Template.csv with fresh files downloaded from the git, the comparisonDict array is not filled in with the proper values. Here's what comparisonDict in the resulting pkginfo looks like:
comparisonDict = { "device-uri":"ADDRESS", "printer-info":"DISPLAY_NAME", "printer-location":"LOCATION", "printer-make-and-model":"DRIVER" }
Since future versions of macOS 10.16 --> will slownly make printers deprecated would it be a possibility to make the need for drivers and option instead of a requirement?
SMB and LDP etc is planning to be removed and IPP is planned to take over so maybe it should be a default for IPP instead of LDP?
Hi,
I'm starting to experiment with this, but have run into an error. Here's the output from Terminal:
$ ./print_generator.py --printername="hs_south_copier" --driver="TOSHIBA_ColorMFP_X7.gz" --address="serveraddress.org/hs_south_copier" --location="High School South Office" --displayname="HS South Copier @ quill" --desc="Color Toshiba Copier" --options="" --version=1.0
$ ./print_generator.py --printername="hs_south_copier" --driver="TOSHIBA_ColorMFP_X7.gz" --address="serveraddress.org/hs_south_copier" --location="High School South Office" --displayname="HS South Copier @ quill" --desc="Color Toshiba Copier" --options="Finisher=StapleM" --version=1.0 Traceback (most recent call last): File "./print_generator.py", line 127, in <module> optionsString = getOptionsString(args.options[0]) File "./print_generator.py", line 13, in getOptionsString optionsString += "\"%s\":\"%s\"" % (str(option.split('=')[0]), str(option.split('=')[1])) + ', ' IndexError: list index out of range
If I have anything in the --options
parameter, I get this error.
This could (should?) be converted into a nice terminal one-liner using grep/sed/awk, but this is what I just cooked up and wanted to log it before I forgot it. Might come back with the full terminal command...
Copy the output of lpoptions and paste into a TextWrangler window. Then using text wrangler's grep-enabled search/replace:
Find: /[^\*]*\*([^\s]*).*
Replace: \=\1
This will get you to the Key=Value format, but each on their own line (easier for proofing)
Then to put them all on a space-separated single line:
Find: \r
Replace: <space>
The following is output from --csv, whereas using the cli method adds lpd:// for -v and the full driver path to -v:
cmd = [ '/usr/sbin/lpadmin',
'-p', 'Math',
'-L', 'Math Room',
'-D', 'Math Room',
'-v', '10.111.110.78',
'-P', 'HP1600dn.ppd.gz',
'-E',
'-o', 'printer-is-shared=false',
'-o', 'printer-error-policy=abort-job' ]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.