Posted on 06-20-2019 11:03 AM
Apple today announced a voluntary recall of a limited number of older generation 15-inch MacBook Pro units which contain a battery that may overheat and pose a safety risk. The units were sold primarily between September 2015 and February 2017 and can be identified by their product serial number. The recall does not affect any other 15-inch MacBook Pro units or other Mac notebooks.
https://support.apple.com/15-inch-macbook-pro-battery-recall
Creating a saved search with the criteria "Model" - "MacBook Pro (Retina, 15-inch, Mid 2015)" "15-inch Retina MacBook Pro (Mid 2015)" should show any devices that may be part of the recall. A quick glance at my fleet showed a couple that come back positive in the eligibility tool, but I'm not seeing any commonality between their serial numbers.
edit apologies, bad copy and paste job
Posted on 06-20-2019 11:11 AM
At least for me, I had to use Model is "15-inch Retina MacBook Pro (Mid 2015)". Even then spot checking the serial numbers I found 1 out of about 10 tries that say it has the issue. If anyone finds a better query, please post it.
Posted on 06-20-2019 11:15 AM
yes, seriously... the thought of manually pasting all our serials into their lookup tool is a painful one!
Posted on 06-20-2019 11:17 AM
I just asked Apple if there was a upload feature as I don't feel like scripting this. We have almost 2000 that might qualify, so...
Posted on 06-20-2019 11:23 AM
Also asked as well, just checked a bunch by hand.
Posted on 06-20-2019 12:12 PM
glad I only had around 30 to check. 2 of them appear to be covered by the recall, and nothing similar with the serials either
Posted on 06-20-2019 12:33 PM
My Apple rep said there is an internal tool they can use, so I sent our list of serial numbers to him.
Posted on 06-20-2019 12:34 PM
If you have an Enterprise AppleCare OS Support agreement, you can send a csv of serials to your AppleCare Account Manager and they can have them checked. Not sure about non-Enterprise support customers.
Posted on 06-20-2019 09:09 PM
Looks like the serial checker thing on Apple's recall page posts the serial and a random guid to https://qualityprograms.apple.com/snlookup/062019, so just based our EA on that:
Updated on July 24: Agree with @elliotjordan so have added a Run Once option:
#!/usr/bin/env bash
# Run Once Option
# Update (24-JUL-2019): Added runOnce option
# Agree with [~elliotjordan] that we should avoid excessively querying Apple
# Set runOnce bool to true(1) to limit querying qualityprograms.apple.com to the
# first instance of receiving an expected response (E00, E01, FE01, or FE02)
# that is not a processing error (E99 or FE03).
runOnce="true"
if [[ "$runOnce" == "true" || "$runOnce" == "1" ]]; then
if [[ -e /usr/local/xattr/.appleRecall062019CheckDone ]]; then
# Using runOnce cached value:
echo "<result>$(cat /usr/local/xattr/.appleRecall062019CheckDone | head -n 1)</result>"
# Delete /usr/local/xattr/.appleRecall062019CheckDone to re-query qualityprograms.apple.com
exit 0
fi
fi
createRecallCheckDone () {
mkdir -p /usr/local/xattr
echo $1 > /usr/local/xattr/.appleRecall062019CheckDone
}
postURL="https://qualityprograms.apple.com/snlookup/062019"
quotSerial=$(ioreg -l | grep IOPlatformSerialNumber | awk '{print $4}')
quotGUID='"'$(uuidgen | tr "[:upper:]" "[:lower:]")'"'
modelID=$(system_profiler SPHardwareDataType | grep "Model Identifier" | awk '{print $3}')
# Be nice to qualityprograms.apple.com and only query valid models by pre-qualifying:
if [[ "$modelID" == "MacBookPro11,4" || "$modelID" == "MacBookPro11,5" ]]; then
# 12 charlen for all serials in affected years (14 incl quote)
# 36 charlen for all guids (38 incl quote)
if [[ "${#quotSerial}" -eq 14 ]]; then
if [[ "${#quotGUID}" -eq 38 ]]; then
postData="{"serial":$quotSerial,"GUID":$quotGUID}"
resp=$(curl -d "$postData" -H "Content-Type: application/json" -X POST "$postURL")
if [[ "$resp" == *'"status":"E00"'* ]]; then
echo "<result>E00-Eligible</result>"
createRecallCheckDone "E00-Eligible"
elif [[ "$resp" == *'"status":"E01"'* ]]; then
echo "<result>E01-Ineligible</result>"
createRecallCheckDone "E01-Ineligible"
elif [[ "$resp" == *'"status":"E99"'* ]]; then
echo "<result>E99-ProcessingError</result>"
# createRecallCheckDone "E99-ProcessingError"
elif [[ "$resp" == *'"status":"FE01"'* ]]; then
echo "<result>FE01-EmptySerial</result>"
createRecallCheckDone "FE01-EmptySerial"
elif [[ "$resp" == *'"status":"FE02"'* ]]; then
echo "<result>FE02-InvalidSerial</result>"
createRecallCheckDone "FE02-InvalidSerial"
elif [[ "$resp" == *'"status":"FE03"'* ]]; then
echo "<result>FE03-ProcessingError</result>"
# createRecallCheckDone "FE03-ProcessingError"
else
echo "<result>Err1-UnexpectedResponse</result>"
fi
else
echo "<result>Err2-NotQueried-InvalidGuidLength</result>"
fi
else
echo "<result>Err3-NotQueried-InvalidSerialLength</result>"
fi
else
echo "<result>Msg1-IneligibleModel</result>"
fi
According to the source for Apple's recall page, there are six possible valid responses:
E00-Eligible
E01-Ineligible
E99-ProcessingError
FE01-EmptySerial
FE02-InvalidSerial
FE03-ProcessingError
This attribute adds a message for models that are not pre-qualified for query, an error state for an unexpected response, and error states for not being able to run the query because of invalid serial or GUID lengths:
Msg1-IneligibleModel
The model will not be queried against qualityprograms.apple.com because it does not match MacBookPro11,4 or MacBookPro11,5.
Err1-UnexpectedResponse
The response was something other than one of the six expected codes above.
Err2-NotQueried-InvalidGuidLength
The combined length of the locally generated GUID and two soft-quote characters did not equal 38.
Err3-NotQueried-InvalidSerialLength
The combined length of the serial number and two soft-quote characters did not equal 14.
Anyhow, might be useful just for keeping an eye on things to make sure these don't pop back up once we think we have things cleaned up.
Posted on 06-20-2019 10:07 PM
Nice work!!! I hope you don't mind me linking your post to spread the word on this great script!
https://mrmacintosh.com/some-mid-2015-macbook-pros-recalled-over-battery-overheating-issues/
Posted on 06-20-2019 11:30 PM
Thanks! Just so you're aware, an edit had to be made to remove the (incorrect) assumption there would never be metadata returned (there is when an eligible device (E00) is identified).
Changed comparisons from the format of:
'{"metadata":"","status":"E00"}' to *'"status":"E00"'*
As positive responses do contain metadata:
{"metadata":"UmBRSI9lXL4j17Ub8qj3i6cvmx3a1NuJAdM%2FIyAtoS41HX4HaaWKNRmOHlwm8p50o6rRzdoIOWx%2BUBOdVsnXfL7tcuP8v0fULb6DQTw5%2FejMJfgwnaVzn8QwLGgxYC3xXutUfj7IvXzP0ba0U9ovB%2Fs%2BZvuoA%2FV%2B6iFIiXPxAga1DQ%2BKbd8wSvir%2B%2BL0yVyieMxwI%2FmfDjdFNl4K7lr0kIfMfDVbepkJ0jz8%2FW017XG5Ip1i5cFhxpu20DtLvLnYMeQfLu7FuVeVTxgF%2F9qQGjj1ySh%2BBvKTlHY2NVS7UV4ZV455ABhS24GsgYgHf05e8fotQGBedxDoHdaoX8Pgjg%3D%3D","status":"E00"}
Posted on 06-21-2019 04:06 AM
Thanks to Nick's EA I came up with this which you can feed a file containing a list of serials as well (and you can redirect output to a CSV if you want) - in case you don't fancy waiting for a recon:
https://soundmacguy.wordpress.com/2019/06/21/2015-macbook-pro-battery-recall-checker-script/
Hope it helps!
Posted on 06-21-2019 06:09 AM
Great! thanks for putting this together!!
Posted on 06-21-2019 09:51 AM
I'd strongly suggest using @neil.martin83's script instead of implementing an EA for this check. Best not to give Apple another reason to consider putting captchas on lookups like this in the future.
Posted on 06-21-2019 10:02 AM
Following that URL takes us to this???
Posted on 06-21-2019 10:51 AM
@swhps That URL is an API endpoint - not meant to be accessed by a browser. The way it's used is that you're supposed to send it a specifically crafted HTTP request that contains the serial number you're querying plus a random GUID string, then it'll return a response that you can determine eligibility from.
Posted on 06-21-2019 12:59 PM
@neil.martin83 Thanks so much for the script. It made identifying our affected MBPs child's play, allowing me to quickly notify our affected users.
Posted on 06-22-2019 03:45 AM
@elliotjordan and @neil.martin83 thanks to the internet, I stole from both of you, without remorse, and very thankful to you both. :)
Paying it forward...script runs locally (Once Per Computer), curls status from Apple, outputs status to EA...then just need to create a Smart Computer Group listing computers that output "E00-Eligible".
Script:
#!/usr/bin/env bash
# Adapted from Nick Tong's EA:
# https://www.jamf.com/jamf-nation/discussions/32400/battery-recall-for-15-mid-2015-mbp
# And from Neil Martin's script:
# https://soundmacguy.wordpress.com/2019/06/21/2015-macbook-pro-battery-recall-checker-script/
#
# This script checks status and outputs to a file (folder path created if not there).
# Run the script in a Once Per Computer policy.
# Create an EA to cat status in file and Smart Computer Group to report.
# 20190621 DM
postURL="https://qualityprograms.apple.com/snlookup/062019"
quotSerial=$(ioreg -l | grep IOPlatformSerialNumber | awk '{print $4}')
quotGUID='"'$(uuidgen | tr "[:upper:]" "[:lower:]")'"'
modelID=$(system_profiler SPHardwareDataType | grep "Model Identifier" | awk '{print $3}')
# Create output directory and define path to output file
OUTPUTDIR="/Library/COMPANY/SearchResults/20190620-15-inch-macbook-pro-battery-recall"
OUTPUTFILE="$OUTPUTDIR/status.txt"
/bin/mkdir -p "$OUTPUTDIR"
# Be nice to qualityprograms.apple.com and only query valid models by pre-qualifying:
if [[ "$modelID" == "MacBookPro11,4" || "$modelID" == "MacBookPro11,5" ]]; then
# 12 charlen for all serials in affected years (14 incl quote)
# 36 charlen for all guids (38 incl quote)
if [[ "${#quotSerial}" -eq 14 ]]; then
if [[ "${#quotGUID}" -eq 38 ]]; then
postData="{"serial":$quotSerial,"GUID":$quotGUID}"
resp=$(curl -d "$postData" -H "Content-Type: application/json" -X POST "$postURL")
if [[ "$resp" == *'"status":"E00"'* ]]; then
echo "E00-Eligible" > "$OUTPUTFILE"
elif [[ "$resp" == *'"status":"E01"'* ]]; then
echo "E01-Ineligible" > "$OUTPUTFILE"
elif [[ "$resp" == *'"status":"E99"'* ]]; then
echo "E99-ProcessingError" > "$OUTPUTFILE"
elif [[ "$resp" == *'"status":"FE01"'* ]]; then
echo "FE01-EmptySerial" > "$OUTPUTFILE"
elif [[ "$resp" == *'"status":"FE02"'* ]]; then
echo "FE02-InvalidSerial" > "$OUTPUTFILE"
elif [[ "$resp" == *'"status":"FE03"'* ]]; then
echo "FE03-ProcessingError" > "$OUTPUTFILE"
else
echo "Err1-UnexpectedResponse" > "$OUTPUTFILE"
fi
else
echo "Err2-NotQueried-InvalidGuidLength" > "$OUTPUTFILE"
fi
else
echo "Err3-NotQueried-InvalidSerialLength" > "$OUTPUTFILE"
fi
else
echo "Msg1-IneligibleModel" > "$OUTPUTFILE"
fi
exit 0
EA:
#!/bin/sh
OUTPUTDIR="/Library/COMPANY/SearchResults/20190620-15-inch-macbook-pro-battery-recall"
OUTPUTFILE="$OUTPUTDIR/status.txt"
if [ -e "$OUTPUTFILE" ]; then
STATUS=$( cat $OUTPUTFILE )
echo "<result>$STATUS</result>"
else
echo "<result>FileDoesNotExist</result>"
fi
Posted on 06-23-2019 03:10 PM
I also wrote something. As with ANY script - check to see what it does first, and don't be a dick about how you use it. Apple doesn't like DDoS any more than you do. The suggestions you have seen about writing status to disk as a one-off policy and reading that out to the EA seem like the wise way to go.
Here is my script either way. Quick and dirty, written in 5 minutes.
https://gist.github.com/nzmacgeek/ef453c8e96a67ee12d973e4c0594e286
Posted on 06-24-2019 02:27 AM
A subtle tweak on Neil's script to include a menu of the current Apple Exchange and Repair Extension Programs (at least the ones with a serial number check).
Hope someone finds it useful...
#!/bin/bash
# Check a list of serial numbers for eligibility in the 2015 MacBook Pro battery replacement recall
# Returns only eligible serial numbers
# The text file must be formatted with Unix (LF) line breaks
#
# Usage: mbpserialcheck.sh /path/to/inputfile.txt
#
# To output directly to a CSV file: mbpserialcheck.sh /path/to/inputfile.txt > /path/to/outputfile.csv
#
# Tweaked by John Sherwood to add a menu of current Exchange and Repair Extension Programs
#
#
# Written by Neil Martin https://soundmacguy.wordpress.com
#
#
# With thanks to Nick Tong for his original Jamf EA which gave me the inspiration for this script. https://www.jamf.com/jamf-nation/discussions/32400/battery-recall-for-15-mid-2015-mbp
#
# 2019-06-21
# Edit the variable below to the filename of your text file containing a list of serial numbers to check
file=$1
# Do not edit below this line
# Present list of current service and recall programs
echo ""
echo "Available Exchange and Repair Extension Programs"
echo ""
echo "a) 15-inch MacBook Pro Battery Recall Program"
echo "b) 13-inch MacBook Pro (non Touch Bar) Solid-State Drive Service Program"
echo "c) 13-inch MacBook Pro (non Touch Bar) Battery Replacement Program"
echo "d) iPhone 8 Logic Board Replacement Program"
echo "e) iPhone 6s Program for Unexpected Shutdown Issues"
echo "f) iSight Camera Replacement Program for iPhone 6 Plus"
echo ""
read -n1 -p "Selct the Exchange and Repair Extension Program to check " programChoice
case $programChoice in
a|A) printf "
You selected 15-inch MacBook Pro Battery Recall Program
" && programChoice="062019";;
b|B) printf "
You selected 13-inch MacBook Pro (non Touch Bar) Solid-State Drive Service Program
" && programChoice="112018";;
c|C) printf "
You selected 13-inch MacBook Pro (non Touch Bar) Battery Replacement Program
" && programChoice="032018";;
d|D) printf "
You selected iPhone 8 Logic Board Replacement Program
" && programChoice="082018";;
e|E) printf "
You selected iPhone 6s Program for Unexpected Shutdown Issues
" && programChoice="112016";;
f|F) printf "
You selected iSight Camera Replacement Program for iPhone 6 Plus
" && programChoice="082015";;
esac
# Verify the file exists
if [[ ! -e "$file" ]]; then
echo "Serial number list file not found or specified"
echo "Ensure there are no spaces and that the path specified is correct"
echo "Script usage: ./mbpserialcheck.sh /path/to/file.txt"
exit 1
fi
# Loop through the list and submit data to Apple
while read -r serial; do
guid=$(uuidgen | tr "[:upper:]" "[:lower:]")
postData="{"serial":$serial,"GUID":$guid}"
resp=$(curl -d "$postData" -H "Content-Type: application/json" -X POST "https://qualityprograms.apple.com/snlookup/$programChoice" 2>&1)
if [[ "$resp" == *'"status":"E00"'* ]]; then
echo "$serial,eligible"
elif [[ "$resp" == *'"status":"E01"'* ]]; then
echo "$serial,ineligible"
elif [[ "$resp" == *'"status":"E99"'* ]]; then
echo "$serial,error please recheck"
elif [[ "$resp" == *'"status":"FE01"'* ]]; then
echo "$serial,empty serial"
elif [[ "$resp" == *'"status":"FE02"'* ]]; then
echo "$serial,invalid serial"
elif [[ "$resp" == *'"status":"FE03"'* ]]; then
echo "$serial,error please recheck"
else
echo "$serial,unknown result please recheck"
fi
done < "$file"
Posted on 06-25-2019 04:03 AM
have you verified you script is working ?. Just wondering that the one I test with just say filedoesnotexist
Posted on 06-25-2019 04:26 AM
@jameson yes, make sure you run the script with admin rights, else the folder/file can't get created and you'll get FileDoesNotExist.
bash-3.2# /tmp/test.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 101 100 30 100 71 19 45 0:00:01 0:00:01 --:--:-- 45
bash-3.2# cat /Library/COMPANY/SearchResults/20190620-15-inch-macbook-pro-battery-recall/status.txt
E01-Ineligible
bash-3.2#
On a computer we know is effected, the output was E00-Eligible. It was already sent out for repair.
Posted on 06-25-2019 04:32 AM
Jamf is executing the script so admin rights should be there to create the script. I will try and check again
Posted on 06-25-2019 04:39 AM
@nzmacgeek yeap, got yelled at in the past for doing that...the script I posted runs the check once per computer and only to affected computers...it is indeed most logical way to scope. #dontPissAppleOff
Posted on 06-25-2019 04:39 AM
@jameson can you check at least that the folder path is being created? Heading in to work now, can peek here later...
Posted on 06-25-2019 05:09 AM
It is working. Just had a typing error that caused the issue for me
Posted on 06-25-2019 11:54 PM
One could use the 'Model Identifier' from the Advanced Criteria to create a smart group as a target for the script, reducing the scope and the workload on the system.
Posted on 07-01-2019 01:51 PM
@donmontalvo i tried this with a script and EA with smart group, however, while i can run the command fine, natively on the machine, it does run right as a script.
Error running script: return code was 126.
i assume its having difficulty making the directory for reason, maybe it needs a $currentuser or something to that effect defined vs just /library/ ?
Posted on 08-14-2019 06:13 AM
Great script, thank you :)
Posted on 08-14-2019 10:02 PM
@nicktong doing the Lord's work I see! Thanks, gonna steal a bunch of this at some point when I want to automate the battery checking
Posted on 08-28-2019 10:44 PM
@tlarkin lol, I can barely keep up with my own work, let alone... :) In any case, I have noticed that once a battery has been replaced, the response still comes back from qualityprograms.apple.com/snlookup/062019 as "Eligible" .. which is definitely annoying
Posted on 08-29-2019 01:44 PM
I guess quality programs is just a clever name then :-D