Posted on 10-15-2015 12:59 PM
This is damn frustrating. Not sure if it's Apple's issue or Casper.
Apple GSX (and MacTracker) lists the model name as "MacBook Pro (15-inch, Early 2011)" or "MacBook Pro (15-inch, Late 2011)" while Casper lists them both as "15-inch MacBook Pro (2011)"!
I'm not sure if Casper is pulling this info from the hardware itself, or from an internal database. But it becomes a big issue when trying to separate Early from Late 2011 machines (13, 15 or 17).
This is a big problem for me because I'm trying to create smart groups for policies so we can deploy Apple Hardware Test to our machines since we reimage them (which removes AHT). The Early models of 2011 MacBook Pros (13/15/17) use versions 3A208, 3A209, and 3A211 of AHT. While the Late models of 2011 MacBook Pros (13/15/17) use version 3A222. But I've found no way of differentiating between at least the Early and Late 2011 15" machines.
If Casper is pulling the model name from a built-in database - STOP! Please. If it's pulling it from the machine, well damnit. :-(
Does anyone have any suggestions for how I can create a smart group to differentiate between the two models of 2011 15" MacBook Pros?
Solved! Go to Solution.
Posted on 10-16-2015 09:22 AM
I took Per's code (https://github.com/MagerValp/MacModelShelf), borrowed some code from @chilcote (https://github.com/chilcote/pyfacts/blob/master/pyfacts) and made a few changes to be able to use this as an EA.
You'll need to place Per's macmodelshelf.db file somewhere on these machines and update the script to point to that location, but once done you have an EA that will return the model info.
#!/usr/bin/env python
import sys
import shelve
import urllib2
import subprocess
import plistlib
from xml.etree import ElementTree
DBPATH = "/your/path/to/macmodelshelf"
try:
macmodelshelf = shelve.open(DBPATH)
except BaseException, e:
print >>sys.stderr, "Couldn't open macmodelshelf.db: %s" % e
sys.exit(1)
def model_code(serial):
if "serial" in serial.lower(): # Workaround for machines with dummy serial numbers.
return None
if len(serial) in (12, 13) and serial.startswith("S"): # Remove S prefix from scanned codes.
serial = serial[1:]
if len(serial) in (11, 12):
return serial[8:].decode("ascii")
return None
def lookup_mac_model_code_from_apple(model_code):
try:
f = urllib2.urlopen("http://support-sp.apple.com/sp/product?cc=%s&lang=en_US" % model_code, timeout=2)
et = ElementTree.parse(f)
return et.findtext("configCode").decode("utf-8")
except:
return None
def model(code):
global macmodelshelf
code = code.upper()
try:
model = macmodelshelf[code]
except KeyError:
print >>sys.stderr, "Looking up %s from Apple" % code
model = lookup_mac_model_code_from_apple(code)
if model:
macmodelshelf[code] = model
return model
def _dump():
print "macmodelshelfdump = {"
for code, model in sorted(macmodelshelf.items()):
print ' "%s": "%s",' % (code, model)
print "}"
if __name__ == '__main__':
try:
output = subprocess.check_output(['/usr/sbin/ioreg',
'-c', 'IOPlatformExpertDevice',
'-d', '2',
'-a'])
d = plistlib.readPlistFromString(output)
#return d['IORegistryEntryChildren'][0]['IOPlatformSerialNumber']
sernum=d['IORegistryEntryChildren'][0]['IOPlatformSerialNumber']
# m = model(sernum)
if len(sernum) in (11, 12, 13):
m = model(model_code(sernum))
else:
m = model(sernum)
if m:
print "<result>"+m+"</result>"
sys.exit(0)
else:
print >>sys.stderr, "Unknown model %s" % repr(sys.argv[1])
sys.exit(1)
except IndexError:
print "Usage: macmodelshelf.py serial_number"
sys.exit(1)
I know this can be cleaned up a lot, and there might be a different way to do this, but I just wanted to prove it could be done with the code. Besides, my Python Fu is not that good.
Hopefully that will help you get part of the way to your SG.
HTH
Posted on 10-15-2015 01:18 PM
Its JAMF mostly, although in some cases, Apple is also to blame since they very stupidly started deciding to re-use model identifiers for different Macs. (Aside: Who in their right, sane mind decided it was a good idea to re-use a model identifier. Isn't a model identifier supposed to be unique to that specific hardware!? grrrr Apple!!)
Anyway, I've complained often about this myself before. JAMF has a hardcoded table in the JSS database that translates the model ids into a human readable name, but since Apple is using the same id for multiple different models, well, you get the picture.
Your best bet is to implement an Extension Attribute that uses Apple's own process to identify the actual Mac name, and not go by some wacky translation table the way JAMF is doing.
See my post on this old FR for an example of how to do it. There are variations on this general process out there as well, so pick your poison.
https://jamfnation.jamfsoftware.com/featureRequest.html?id=2567#responseChild7202
Edit: Here's a somewhat simplified version of the EA script that gets the same information, just doesn't need to do 2 possible curl commands to get it.
#!/bin/sh
SerialNum=$(ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')
if [[ ${#SerialNum} -eq 12 ]]; then
Serial=$(echo "$SerialNum" | tail -c 5)
else
Serial=$(echo "$SerialNum" | tail -c 4)
fi
FullModelName=$(curl -s "http://support-sp.apple.com/sp/product?cc=$Serial&lang=en_US" | xmllint --format - 2>/dev/null | awk -F'>|<' '/<configCode>/{print $3}')
if [ "$FullModelName" != "" ]; then
echo "<result>$FullModelName</result>"
else
echo "<result>NOT FOUND</result>"
fi
Posted on 10-15-2015 02:00 PM
Is there a way to pull the EMC number or the Order Number? Looking at MacTracker, those are the two sets of identifiers that seem to be different, but I haven't figured out how to pull them. I've been tinkering for the last 30 minutes trying to see if system_profiler or ioreg, or a curl from one of the Apple sites would pull that info down, but I can't find one.
That might be your only choice, other than dropping a text file on the machine at imaging time to ID the machines.
Posted on 10-15-2015 06:01 PM
It's not ideal, but you could combine "Model Name 'Like'" and "Serial Number 'Like'" criteria to determine this info. See https://github.com/MagerValp/MacModelShelf for more info
Posted on 10-16-2015 04:58 AM
Bit of a different approach, but could you create a smart group using the CCC code in the serial number? The last three characters should be be fairly consistent per model.
Posted on 10-16-2015 07:20 AM
@davidacland The only possible issue with that approach is that the Serial Number criteria does not have an "ends with" modifier, only "like" so there's a remote possibility of those last 3 characters showing up somewhere else within the serial number. I suppose its probably not likely, but I don't know for sure. I still think getting the full human readable name direct from Apple in an EA is the best approach, since then you can just do something like
Actual model name | is | "MacBook Pro (15-inch, Late 2011)"
to correctly gather all those models into a Smart Group.
I was also thinking that my EA script above could be made to look for a local file with the full model name, and do the curl pull from Apple if its not there, then write the value into the file. Next time the EA script runs, and every time thereafter, it should see the file and pull the stored value. That way its not doing a curl against Apple's site at every inventory. Its not as if a Mac's model name ever changes from day to day :)
Posted on 10-16-2015 07:29 AM
Thats true. I guess you could grab the CCC via an EA ioreg -l | grep IOPlatformSerialNumber | awk '{print $4}' | sed 's/"//g' | cut -c 10-12
Posted on 10-16-2015 09:22 AM
I took Per's code (https://github.com/MagerValp/MacModelShelf), borrowed some code from @chilcote (https://github.com/chilcote/pyfacts/blob/master/pyfacts) and made a few changes to be able to use this as an EA.
You'll need to place Per's macmodelshelf.db file somewhere on these machines and update the script to point to that location, but once done you have an EA that will return the model info.
#!/usr/bin/env python
import sys
import shelve
import urllib2
import subprocess
import plistlib
from xml.etree import ElementTree
DBPATH = "/your/path/to/macmodelshelf"
try:
macmodelshelf = shelve.open(DBPATH)
except BaseException, e:
print >>sys.stderr, "Couldn't open macmodelshelf.db: %s" % e
sys.exit(1)
def model_code(serial):
if "serial" in serial.lower(): # Workaround for machines with dummy serial numbers.
return None
if len(serial) in (12, 13) and serial.startswith("S"): # Remove S prefix from scanned codes.
serial = serial[1:]
if len(serial) in (11, 12):
return serial[8:].decode("ascii")
return None
def lookup_mac_model_code_from_apple(model_code):
try:
f = urllib2.urlopen("http://support-sp.apple.com/sp/product?cc=%s&lang=en_US" % model_code, timeout=2)
et = ElementTree.parse(f)
return et.findtext("configCode").decode("utf-8")
except:
return None
def model(code):
global macmodelshelf
code = code.upper()
try:
model = macmodelshelf[code]
except KeyError:
print >>sys.stderr, "Looking up %s from Apple" % code
model = lookup_mac_model_code_from_apple(code)
if model:
macmodelshelf[code] = model
return model
def _dump():
print "macmodelshelfdump = {"
for code, model in sorted(macmodelshelf.items()):
print ' "%s": "%s",' % (code, model)
print "}"
if __name__ == '__main__':
try:
output = subprocess.check_output(['/usr/sbin/ioreg',
'-c', 'IOPlatformExpertDevice',
'-d', '2',
'-a'])
d = plistlib.readPlistFromString(output)
#return d['IORegistryEntryChildren'][0]['IOPlatformSerialNumber']
sernum=d['IORegistryEntryChildren'][0]['IOPlatformSerialNumber']
# m = model(sernum)
if len(sernum) in (11, 12, 13):
m = model(model_code(sernum))
else:
m = model(sernum)
if m:
print "<result>"+m+"</result>"
sys.exit(0)
else:
print >>sys.stderr, "Unknown model %s" % repr(sys.argv[1])
sys.exit(1)
except IndexError:
print "Usage: macmodelshelf.py serial_number"
sys.exit(1)
I know this can be cleaned up a lot, and there might be a different way to do this, but I just wanted to prove it could be done with the code. Besides, my Python Fu is not that good.
Hopefully that will help you get part of the way to your SG.
HTH
Posted on 10-16-2015 12:50 PM
Just over 24 hours... and i'm gobsmacked. I so hope I can make it to JNUC next year so I can buy people some beers. :-)
I'm going to use @stevewood's script. Normally we don't "push" anything to our users since we don't know where they might be, and what type of internet connection they could be using and if they're doing anything critical for air. Since this is really only affecting these 2011 MacBook Pros though, and since their number is blissfully declining, we're going to make an exception for them.
I'll try and get back to this thread with updates.