Article Outline
Example Python program collect-info.py For Python version 2.x. To test your Python version use:
python --version
Modules
- import AppKit
- import sys
- import os
- import Tkinter
- import tkFont
- import tkMessageBox
- import subprocess
- import plistlib
Classes
- class App:
Methods
- def init(self, master):
- def cancel(self):
- def submit(self):
- def main():
Code
Python tkinter example
#!/usr/bin/python
"""
Collect Info
To be used in a Jamf Pro workflow to prompt a user/tech for info
Heavily cribbed from Jamf's iPhone ordering script:
https://github.com/jamfit/iPhone-Ordering
"""
import AppKit
import sys
import os
import Tkinter
import tkFont
import tkMessageBox
import subprocess
import plistlib
# Path to Jamf binary
JAMF = "/usr/local/bin/jamf"
# base64-encoded GIF for "icon" at the top of the GUI
# MUST BE A GIF!
mbp_icon = '''
R0lGODdh+gCWAMQAAAAAAElJSVJSUlxcXGFhYW5ubnNzc3x8fIWFhY+Pj6WlpampqbKysry8vMbGxsjI
yNTU1Nzc3OHh4enp6fLy8v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkKABYALAAA
AAD6AJYAAAX/oCWOZGmeaKqubOu+cCzPdG3feK7vfO//wKBwSCwaj8ikcslsOp/QqHRKrVqv2Kx2y+16
v+CweEwum8/otHrNbrvf8Lh8Tq/b7/i8fs/PGQ6AgYKDhIWGh4iJiouMjY6GBn0pCAwRE5eYmZqbnJ2e
n6ChoqOkpZ0RDAiSJQkSFa+wsbKztLW2t7i5uru8vbkTCasiBxO+xsfHEg/IzM25EgerBAzO1davEAsU
19zNDASSBRHd5OXm568RBZLE6O7v8LsT0X3tsBIQ+fr7/P3+/wADChxIsKDBg/1cwZrHrhisCA4iSpxI
saLFixgzatzIsaPHjxXHLaTHx94rCQ4e/6hcybKly5cwY8qcSbOmzZs4WToQ+YphPYcnU+YcSrSo0aNH
d8byWRJoBZRIo0qdSvWm0pENY0GtyrWrV6NXe5LcY/Kp0K9o06rVybMCU7JOt66dS5dqWLdj9ZSVW7ev
35x33+qNe/av4cMwA+fNs7cw4seIFWe95xiy5b6Sf2qtfLmz2sxNN3sePRc0XNGkU381PRi16td22wpm
TBi2bamsabu+zXtobjyNewsHLHsx8NrDk9P8fSe48ueJi08OCr16S+Z2nFu3jr2O9u3Qu9P5Dl65+Dnk
yw8/Lye9+t7s47h/fzs+nPn0Ydt/gz+/6v1u9OcfaQC2IeCAnhXIxv+BCF6m4BoMNgjZg2pEKGFk0mlG
2YW2UZiGhRz+5SEaIIaIWYahbWhiaiOeUeKKpaF4moowJihjazTW6OCNuuWo44Q8Hrfbj4+1aMaLRHpl
ZBlIJsnVkmQ06WRsSxnXHHJTHgblGFJmGdWWYnTpZVJBXjnkmHSBGYaYaBKlJhhstklcldOZJeeJdGpI
3Z1plpkdlnx+5qd3gAaK1ptfxGnoTIh6oeiiMTXaxaOQviQpF5RWet2g4xWqKZVY6Wnnp11dukWmpD5g
qhaokrpqFq1++ioWsWo66xW1VnqrFblCumsVvS76KxXBGjrsFMUGeqwUyfK5bBTN3vksFNHKOe3/E9W2
ea0T2aK5bRPdjvktE+F6Oe4S5WZ5rhLpTrluEu06+S4S8SY57xH1EnmvEfn+uG8R/er4LxEB1zjwEAXD
eLAQZUEE0sMQRyzxxBQvHERZE0ig8cYcd+zxxyCHLPLIJJds8skoe+zUbELG4/LL8bBsJsw019yNzH/a
rPPOyOBMKM9AB42Lz50KbfTRYoXTAEJMN/1PBFBHLfXUVFft9NVXN7AOlw5gnc9wChRgwNhkl2322WYX
oMBwXkPggJUMO4W0OeqgbffdY4sztztE/1DW3uU0gMDghBdu+OGGNwA4On378Pfi3VAg+eSUV2555ZCf
03gPCMid+eegNzOBoCrwKrDA6ainrvrqrLfu+uuwxy777LTXbvvtuM+uANxCiF222L7jLfzwxBdv/PHI
J6/88swDnza2B/wRCPPUV2/99dhnn7wg0gP7x9iAaC/++OSXP3743/M+BdnRm+/++/DH334kwtRv//34
56///vz37///AAygAAdIwAIa8IAITKACF8jABjrwgRCMoAQnSMEKWvCCGMygBjfIwQ56MAQAOw==
'''
class App:
def __init__(self, master):
"""Main GUI window"""
self.master = master
self.master.resizable(False, False)
self.master.title("Assign User Information")
self.master.protocol("WM_DELETE_WINDOW", self.cancel)
self.master.call('wm', 'attributes', '.', '-topmost', True)
x = (self.master.winfo_screenwidth() - self.master.winfo_reqwidth()) / 2
y = (self.master.winfo_screenheight() - self.master.winfo_reqheight()) / 3
self.master.geometry("+{0}+{1}".format(x, y))
# w, h = self.master.winfo_screenwidth(), self.master.winfo_screenheight()
# self.master.overrideredirect(1)
# self.master.geometry("%dx%d+0+0" % (w, h))
bgcolor = '#F0F0F0'
self.master.tk_setPalette(background=bgcolor,
highlightbackground=bgcolor)
font = tkFont.nametofont('TkDefaultFont')
font.config(family='system',
size=14)
self.master.option_add("*Font", font)
menu_bar = Tkinter.Menu(self.master)
self.master.config(menu=menu_bar)
print('Starting app')
# Input variables
self.input_assigned_user = Tkinter.StringVar()
self.input_assigned_dept = Tkinter.StringVar()
self.input_asset_tag = Tkinter.StringVar()
# Get icon
self.icon_data = Tkinter.PhotoImage(data=mbp_icon)
# Icon Frame
self.frame1 = Tkinter.Frame(self.master)
self.photo_canvas = Tkinter.Canvas(self.frame1, width=250, height=150)
self.photo_canvas.pack()
self.icon = self.photo_canvas.create_image(0, 0, anchor="nw", image=self.icon_data)
self.frame1.pack(padx=40, pady=(30, 5))
# Title Frame
self.frame2 = Tkinter.Frame(self.master)
title_label = Tkinter.Label(self.frame2, text="Assign Device")
title_label.grid(row=0, column=0)
self.frame2.pack(padx=40, pady=(10,5))
# Inputs frame
self.frame3 = Tkinter.Frame(self.master)
user_label = Tkinter.Label(self.frame3, text="Assigned User:")
user_label.pack()
self.entry_assigned_user = Tkinter.Entry(self.frame3,
background='white',
textvariable=self.input_assigned_user,
width=30)
self.entry_assigned_user.pack(pady=(0, 20))
dept_label = Tkinter.Label(self.frame3, text="Department Code:")
dept_label.pack()
self.entry_assigned_dept = Tkinter.Entry(self.frame3,
background='white',
textvariable=self.input_assigned_dept,
width=30)
self.entry_assigned_dept.pack(pady=(0, 20))
asset_label = Tkinter.Label(self.frame3, text="Asset Tag:")
asset_label.pack()
self.entry_asset_tag = Tkinter.Entry(self.frame3,
background='white',
textvariable=self.input_asset_tag,
width=30)
self.entry_asset_tag.pack(pady=(0, 20))
self.frame3.pack(padx=40, pady=5)
# Buttons
self.frame5 = Tkinter.Frame(self.master)
submit = Tkinter.Button(self.frame5, text='Assign', height=1, width=8, command=self.submit)
submit.pack(side='right')
cancel = Tkinter.Button(self.frame5, text='Cancel', height=1, width=8, command=self.cancel)
cancel.pack(side='right')
self.frame5.pack(padx=40, pady=(5, 30))
# Add GUI padding
def cancel(self):
"""Exit the GUI"""
print('User has closed the app')
self.master.destroy()
def submit(self):
"""
Do something with the data submitted
You can do...well, anything you want here.
I use the gathered data to set the computer's name to conform with
our naming convention and submit the asset tag and end user's username
to the JSS.
"""
print('User has submitted')
# Our naming convention is:
# [department code]-[M for Mac][L for latop or D for desktop][asset tag]
# i.e. IT-ML00000
#
# Fun Fact! Our asset tags are prepended with the year the device was
# purchased, so a quick glance at a hostname tells us where it goes,
# the platform and form factor, and an approximate age. We order them
# from myassettag.com each year this way.
# Clean up the submitted end username and make it lowercase
# Splitting each character of the input with split(), then re-joining
# with ''.join() strips all whitespace as opposed to strip() which
# just cleans the head and tail
i_user = ''.join(self.input_assigned_user.get().lower().split())
# Clean up the department code and make it uppercase
i_dept = ''.join(self.input_assigned_dept.get().upper().split())
# Just strip whitespace from the asset tag
i_atag = ''.join(self.input_asset_tag.get().split())
# Determine model for assigning name
# https://github.com/gregneagle/psumac2014_python/blob/master/4_3_0_machine_info.py
cmd = ['/usr/sbin/system_profiler', 'SPHardwareDataType', '-xml']
output = subprocess.check_output(cmd)
info = plistlib.readPlistFromString(output)
hardware_info = info[0]['_items'][0]
if "Book" in hardware_info['machine_model']:
model_id = "L"
else:
model_id = "D"
# Assemble hostname
hostname = "{}-M{}{}".format(i_dept, model_id, i_atag)
print "Hostname: {}".format(hostname)
# Rename the computer
cmd = [JAMF, 'setComputerName', '-name', hostname]
rename = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, err) = rename.communicate()
if rename.returncode == 0:
print "Set computer name to {}".format(hostname)
else:
print "Rename failed!"
sys.exit(1)
# Submit new inventory
cmd = [JAMF, 'recon', '-endUsername', i_user, '-assetTag', i_atag]
inventory = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, err) = inventory.communicate()
if inventory.returncode == 0:
print "Submitted inventory to JSS"
else:
print "Inventory update failed!"
sys.exit(1)
self.master.destroy()
def main():
# Prevent the Python app icon from appearing in the Dock
info = AppKit.NSBundle.mainBundle().infoDictionary()
info['CFBundleIconFile'] = u'PythonApplet.icns'
info['LSUIElement'] = True
root = Tkinter.Tk()
app = App(root)
# Have the GUI appear on top of all other windows
AppKit.NSApplication.sharedApplication().activateIgnoringOtherApps_(True)
rdata = app.master.mainloop()
sys.exit(0)
if __name__ == '__main__':
main()
Useful Links
- Articles: https://python-commandments.org/
- Python shell: https://bsdnerds.org/learn-python/
- Tutorial: https://pythonprogramminglanguage.com/