Check Multiple iMacs for 1TB Seagate Repair Program Eligibility

Apple recently announced that certain iMacs with 1TB Seagate hard drives are eligible for replacement. If you have one iMac it’s easy to check it on their website here.

However if you have a lot of iMacs at your company you might prefer to do this a bit more quickly! The following command can be sent via ARD:

curl  "https://supportform.apple.com/201107/SerialNumberEligibilityAction.do?cb=iMacHDCheck.response&sn=$(ioreg -c "IOPlatformExpertDevice" | awk -F '"' '/IOPlatformSerialNumber/ {print $4}')" 2>/dev/null

To explain: It’s using curl to send a request to the Apple URL, the sn= field is populated with the results of the ioreg command, which is cleaned up with awk (thanks OS X Hints), stderr of curl is sent to /dev/null so you don’t get the download/progress output that curl usually displays.

Another variation is if you already have a list of serial numbers, separated with some sort of whitespace. You can put them in a bash variable and loop though them locally:

serialNumbers="QP0231XXXPK
QP0240XXYRU
D25FP1TXXXJT
QP6481XXXUW"

for number in $serialNumbers; do echo $number $(curl "https://supportform.apple.com/201107/SerialNumberEligibilityAction.do?cb=iMacHDCheck.response&sn=$number" 2>/dev/null); done

This outputs the serial number queried and the response from the Apple server on each line. E03 the response you’ll be looking for. I’ll leave it to you the reader if you want to do any additional cleanup of the output, here’s a sample:

QP0231XXXPK iMacHDCheck.response({"ERROR_CODE":"E08","ERROR_DESC":"Valid iMac SN but WoM is outside of program range"})
QP0240XXXRU iMacHDCheck.response({"ERROR_CODE":"E03","ERROR_DESC":"Valid iMac SN has Seagate HDD - covered by program"})
D25FP1TXXXJT iMacHDCheck.response({"ERROR_CODE":"E07","ERROR_DESC":"Valid iMac SN with NO Seagate HDD"})
QP6481XXXUW iMacHDCheck.response({"ERROR_CODE":"E02","ERROR_DESC":"Serial ID is not iMac."})

 

Apple’s New Epoch Time for WebComponentsLastUsed

The latest Java update for Lion 2012-003 ( which after 3 revisions is still called JavaForOSX-1.0 in Software Update – oh, Apple! But I digress…) will turn off Java if it hasn’t been used in 30 days (or so I hear). It accomplishes this by writing a value to the WebComponentsLastUsed in ~/Library/Preferences/ByHost/com.apple.java.JavaPreferences.UUID.plist.

It used to be enough to have WebComponentsEnabled set to True, but now WebComponentsLastUsed is required or the unclickable “Plugin-Disabled” button will be shown in Safari’s lower right corner (it totally looks clickable yeah?)

If you work at a company that requires Java web components to be on for things like timesheets, making sure Java stays on helps to avoid getting help desk calls.

So I needed to figure out how this value was computed, it was too small to be the Unix epoch (seconds since January 1, 1970), so I did some sleuthing, some comparitive analysis (just to sound fancy), and figured out it is the number of seconds since January 1, 2001. To get this value you just need to get the Unix epoch and subtract the number of seconds since Jan 1, 2001.

Here’s the way to get this value in a BASH Terminal:

echo $(( $(date "+%s") - 978307200 ))

Toggling the check box in /Applications/Utilities/Java Preferences will reset the WebComponentsLastUsed value and you will find it very close to the value from Terminal.

Wasn’t that fun? The Der Flounder blog has a script using this method to turn on Java. He was a good sport to incorporate my code, too. He enlightened me with his UUID scripting code, so share and share alike, I say.

Bonus link for Apple’s other epoch time, for iTunes’ XML Play Date field: January 1, 1904 – that’s the first year of the last century with a leap year, so says Filemaker! ;)

Update / Create Lion RecoveryHD Partition Quickly Without Reinstalling

April 6, 2015 UpdatecreateRecoveryHDUpdater 15.4.6.command – built PKG now is targetable to volumes other than /

Feb 28, 2015 Update: New script on Software page and here:
createRecoveryHDUpdater 15.2.28.command

Apple released the Lion Recovery Update in October, 2011, and, after they updated the Lion recovery partition to 10.7.2, there was a great hint from Clay Caviness who dug into the update and highlighted the the relevant files and commands that it used to accomplish this update.

Recently, 10.7.3 came out, however, and the RecoveryHD partition is not updated if you use Software Update; it will stay at 10.7.2. This is probably not a big deal, as Apple didn’t deem it necessary to update, but for some users, this may not be good enough.

Note: Running the full 10.7.3 installer from the App Store will update the partition; this is fine for your home computer but not practical for large deployments.

Script Workflow:

  • Asks for locations of Recovery Update, Install OS X Lion.app, and destination
  • Expands and collects the dmtest tool from the Lion Recovery Update
  • Collects the hidden Basesystem chunklist and dmg found in the InstallESD.dmg inside “Install Mac OS X Lion.app”
The script making the Disk Image
  • Puts it all neatly into a self-contained disk image along with the script RecoveryHD Updater.command which can be used to easily create or update the RecoveryHD partition, even on the disk you are currently booted from; don’t worry dmtest takes care of all the logic to create or update.
The final disk image

Requirements:

  • Download the latest version of Install OS X Lion.app. Option-click the Purchases tab in the App Store and you will be able to “Install” (download) the latest version available
  • Download Lion Recovery Update from Apple

Script Tip:

Copy and paste the script into TextWrangler, save with a .command extension and it will automatically set the executable bit.

createRecoveryHDUpdater.command (downloadable script):

#!/bin/bash

#this script will make a disk image with the tools needed to update your Recovery HD with the newest OS X Lion release

#Required components:
#Lion Recovery Update v1.0 - http://support.apple.com/downloads/DL1464/en_US/RecoveryHDUpdate.dmg
#"Install Mac OS X Lion.app" - App Store

###########################
# RecoveryHD Updater.command
###########################

#this script that will be saved to the disk image that is created
RecoveryHDUpdaterScript='#!/bin/bash
clear;
MYPATH="$(dirname "$0")"

#get destination drive
if [ "$1" == "" ]; then
echo -n "Please drag in DESTINATION disk for Recovery HD partition and press Enter: "
while [ -z "$DEST" ]; do
read DEST
done
if [ ! -d "$DEST" ]; then echo "$DEST not found"; exit; fi
else
DEST="$1"
fi

#create Recovery partition
sudo "$MYPATH"/bin/dmtest ensureRecoveryPartition "$DEST" "$MYPATH"/etc/BaseSystem.dmg 0 0 "$MYPATH"/etc/BaseSystem.chunklist
'
######
# END
######

###########################
# VARIABLES
###########################

#IMAGETEMP is the pathname for the disk image being built, will the OS and Build appended to the name later
IMAGETEMP="/tmp/Recovery HD Updater"

#temp folder for package expansion
RECOVERY_EXPANDED="/tmp/RecoveryHDUpdate"

#Mounted disk image paths
ESDPATH="/Volumes/Mac OS X Install ESD"
RECOVERYPATH="/Volumes/Mac OS X Lion Recovery HD Update"

#############
# MAIN SCRIPT
#############
clear;
#get Recovery Update dmg path
if [ "$1" == "" ]; then
echo -n "Please drag in RecoveryHDUpdate.dmg and press enter: "
while [ -z "$RECOVERYHDUPDATE" ]; do
read RECOVERYHDUPDATE
done
if [ ! -f "$RECOVERYHDUPDATE" ]; then echo "$RECOVERYHDUPDATE not found"; exit; fi
else
RECOVERYHDUPDATE="$1"
fi

#get Lion Installer path
if [ "$2" == "" ]; then
echo -n "Please drag in \"Install Mac OS X Lion.app\" and press enter: "
while [ -z "$LION" ]; do
read LION
done
if [ ! -d "$LION" ]; then echo "$LION not found"; exit; fi
else
LION="$2"
fi

#get destination path for disk image to be created at
if [ "$3" == "" ]; then
echo -n "Please drag in Destination folder for disk image: "
while [ -z "$DEST" ]; do
read DEST
done
if [ ! -d "$DEST" ]; then echo "$DEST is not a valid path"; exit; fi
else
DEST="$3"
fi

#mount Recovery Update image
hdiutil attach "$RECOVERYHDUPDATE"

#expand packge inside to temp folder (contains dmtest)
pkgutil --expand "$RECOVERYPATH"/RecoveryHDUpdate.pkg "$RECOVERY_EXPANDED"

#if we were using what's inside the chunklist and recovery inside the update we would mount this
#RecoveryHDMeta="/Volumes/Recovery HD Update"
#hdiutil attach "$RECOVERY_EXPANDED"/RecoveryHDUpdate.pkg/RecoveryHDMeta.dmg

#open Lion install ESD image for the newest files
hdiutil attach "$LION"/Contents/SharedSupport/InstallESD.dmg

#get OS version from Lion Installer ESD
OSVER=$(defaults read "$ESDPATH"/System/Library/CoreServices/SystemVersion ProductUserVisibleVersion)
OSBUILD=$(defaults read "$ESDPATH"/System/Library/CoreServices/SystemVersion ProductBuildVersion)

#append info to path so disk image volume name is informative and useful
IMAGETEMP="$IMAGETEMP $OSVER $OSBUILD"

#make work the folder
mkdir -p "$IMAGETEMP"/etc/
mkdir "$IMAGETEMP"/bin/

#copy dmtest to IMAGETEMP
if [ -f "$RECOVERY_EXPANDED"/RecoveryHDUpdate.pkg/Scripts/Tools/dmtest ]; then
cp "$RECOVERY_EXPANDED"/RecoveryHDUpdate.pkg/Scripts/Tools/dmtest "$IMAGETEMP"/bin/
else
echo "$RECOVERY_EXPANDED/RecoveryHDUpdate.pkg/Scripts/Tools/dmtest not found, exiting"
exit 1
fi

#copy the BaseSystem dmg and chunklist to destination/etc
if [ -f "$ESDPATH"/BaseSystem.chunklist -o -f "$ESDPATH"/BaseSystem.dmg  ]; then
cp "$ESDPATH"/BaseSystem.chunklist "$ESDPATH"/BaseSystem.dmg "$IMAGETEMP"/etc/
#unhide BaseSystem
chflags -R nohidden "$IMAGETEMP"
else
echo "$ESDPATH/BaseSystem* not found, exiting"
fi

#put script in folder root
echo "$RecoveryHDUpdaterScript" > "$IMAGETEMP"/"RecoveryHD Updater.command"
#set permissions
chmod ugo+x "$IMAGETEMP"/"RecoveryHD Updater.command"

#create disk image from folder
hdiutil create -srcfolder "$IMAGETEMP" "$DEST"/RecoveryHDUpdater_$OSVER_$OSBUILD.dmg
if [ $? -eq 0 ]; then
echo "Success! Created: $DEST/RecoveryHDUpdater_$OSVER_$OSBUILD.dmg"
echo "Now opening "$DEST"/RecoveryHDUpdater_$OSVER_$OSBUILD.dmg"
hdiutil attach "$DEST"/RecoveryHDUpdater_$OSVER_$OSBUILD.dmg
else
echo "Disk Image failed"
fi

echo "Cleaning Up"
#delete temp folders
rm -rf "$IMAGETEMP" "$RECOVERY_EXPANDED"

#eject the volumes
hdiutil eject "$RECOVERYPATH"
hdiutil eject "$ESDPATH"

echo "Done."

exit

The script can also be run with command line arguments:

$ ./createRecoveryHDUpdater.command [Recovery Update DMG] [Install Lion App] [Destination for DMG]

As well as the script that is put in the created disk image:

$ ./RecoveryHD\ Updater.command [Destination]

Otherwise just double-click it in the Finder and it will ask you for the files and paths which you can just drag into the Terminal window and press Enter (don’t worry about the trailing spaces it adds)

When you run the script in the disk image you will be prompted for an admin password and away it goes, with all sorts of ugly output because it never thought a human would gaze upon it’s hidden ways…

dmtest updating the RecoveryHD partition

 

Update: Just tested with 10.7.4 and this script still works correctly, nothing has changed in the structure of the updated Install OS X Lion.app from the App store, note that the 10.7.4 installer is version 1.0.21 (10.7.2=1.0.13 and 10.7.3=1.0.16)

Update: Script will work on 10.8 without modification, however I have updated the script anyway to be a bit quieter when mounting the various DMGs, to accept tilde paths, accept the RecoveryHDUpdater as either a DMG or PKG, and changed prompt phrasing to include Mountain Lion.

Getting and setting PPD options via command line for use with lpadmin in OS X

UPDATE – Script now will convert CR to LF line endings for better reliability with old PPDs

There are some good hints for adding printers via the command line with lpadmin: Managing multiple printers via the command line

However, there is still confusion surrounding the setting of printer options from the command line, as a poster to Debian bugs pointed out back in 2006: lpoptions documentation doesn’t. After doing some testing, here’s the two main takewaways:

  • If you use lpadmin and specify options with “-o” the PPD is altered and OS X will recognize the options for the printer.
  • However, if you setup the printer using lpadmin without any options and later use lptoptions to set the options, they are not written to the PPD and the GUI is unaware of the printer’s options.

more helpful hints about lpadmin and lpoptions:

lpoptions -p printername -l

  • Prints PPD options, “Default” is filtered out from option name (compared to looking at the raw PPD)
  • It uses a colon when reporting key value pairs, however replace that with an equals sign when specifying an option
  • The option name stops at the first slash
  • Example: The duplex option for HP printers will output like this “HPOption_Duplexer/Duplex Unit: *True False”
    When specified as a “-o” option it would be “HPOption_Duplexer=True”

lpadmin … -o this=that

    • Alters the ppd that is placed in /etc/cups/ppd/ when the printer is installed

Unhelpful things:

lpoptions -p printername

  • These are NOT the PPD options you want to set

lpoptions -o

  • Only writes options to: /private/etc/cups/lpoptions (run with sudo) or ~/.cups/lpoptions (run as current user), GUI apps are unaware of these options


The following script compares the original and the newly installed PPD to generate the options syntax to be used with lpadmin: 

The main magic in this script is a little diff and sed:

diff "$originalfile" "$newfile" | grep "> [*]Default" | sed 's/> [*]Default/-o /g' | sed 's/: /=/g'

Script Workflow

  • Copy and paste the script into TextWrangler (or download ppdOptionsDiff.command), save with a .command extension and it will automatically take care of the executable bit
  • Setup your printer via the Printers Preference Pane in the GUI.
  • Look in /etc/cups/ppd and find the newest .ppd (it will be named as the printer)
  • Locate the original .ppd.gz (or .ppd) in /Library/Printers/PPDs/Contents/Resources/, usually the printer ppd is easily found by name, but some like Canon have some cryptic filenames, so look inside the /etc/cup/ppd file, the “PCFileName” variable sometimes helps to determine the file name
  • Run the script given below, it will ask you to drag in the original and the modified ppds. Out will come the “-o” options for use with lpadmin

You can also run the script with the original and modified file paths as arguments and the string will be output

The script “ppdOptionsDiff.command“:

#!/bin/bash
[ -f /tmp/debug ] && set -x
#ppd option maker

#help
if [ “$1” == “-h” ]; then
echo “$(basename $0) compares two ppds and outputs the differences as a string for use in lpadmin”
echo “Usage: $(basename $0) [original_ppd] [new_ppd]”
exit
fi

#check for parameter if not ask
if [ -z “$1” -o -z “$2” ]; then
clear;
echo “Drag in the unmodified PPD from /Library/Printers/PPDs/Contents/Resources:”
open /Library/Printers/PPDs/Contents/Resources
while [ -z “$originalfile” ]; do
read originalfile
done

echo “Drag in the PPD from /etc/cups/ppd:”
open /etc/cups/ppd
while [ -z “$newfile” ]; do
read newfile
done
#else just take the arguments
elif [ -n “$1” -o -n “$2″ ]; then
newfile=”$2″
originalfile=”$1”
fi

#make a temp file of the original to compare
#strip off path and extension for temp file name
tempOriginalFile=”/tmp/$(basename “$originalfile” .gz)”

#if file is compressed expand
if [ “${originalfile##*.}” == “gz” ]; then
#uncompress
IFS=$’\n\t’
#gunzip to temp file
gunzip < “$originalfile” > “$tempOriginalFile”
else
#just make a copy
cp “$originalfile” “$tempOriginalFile”
fi

#change line endings from CR to LF (diff fails unless this is done)
sed -e $’s/\\\r/\\\n/g’ -i ” “$tempOriginalFile”

#make a temp file of the new file to compare
#strip off path
tempNewFile=”/tmp/$(basename “$newfile”)”
cp “$newfile” “$tempNewFile”

#change line endings from CR to LF (diff fails unless this is done)
sed -e $’s/\\\r/\\\n/g’ -i ” “$tempNewFile”

#test for file existence
if [ ! -f “$tempOriginalFile” ]; then echo “$tempOriginalFile is not a valid path”; exit; fi
if [ ! -f “$tempNewFile” ]; then echo “$tempNewFile is not a valid path”; exit; fi

#create options list by diffing and filtering
optionList=$(diff “$tempOriginalFile” “$tempNewFile” | grep “> [*]Default” | sed ‘s/> [*]Default/-o /g’ | sed ‘s/: /=/g’)

#print out the options with no line breaks
IFS=$’\n\t’
if [ ! -z “$optionList” ]; then
for option in $optionList; do
echo -n “$option ”
done
echo
else
echo No differences
fi

#delete the temp filess
rm “$tempOriginalFile” “$tempNewFile”

exit

Example (with pathnames provided as arguments, otherwise runs in interactive mode):

$ ./ppdOptionsDiff.command /Library/Printers/PPDs/Contents/Resources/HP\ LaserJet\ 5200.gz /private/etc/cups/ppd/PRINTERNAME.ppd

-o HPOption_Tray3=Tray3_500 -o HPCollateSupported=True -o HPOption_Duplexer=True -o HPOption_Disk=RAMDisk

Use the generated string in lpadmin to set the printer options.

Make a Snow Leopard 10.6.7 Installer Disc from a Mac Restore Disc

So there was this hint the other day at MacWorld’s OS X Hints site:
10.6: Make a universal 10.6.7 Snow Leopard installer – Mac OS X Hints

It was a very useful hint for hacking together a retail Snow Leopard disc (10.6.0/10.6.3 ) and the newest system specific restore disc (10.6.7 for iMacs and MacBook Pros) to make a “universal” 10.6.7 disc that would work on new and old machines alike, that are qualified to run Snow Leopard. Useful not only for techs who need a one disc does it allbut others who might lack bandwidth for updates since this cuts down on some Software Update downloads (10.6.8 is only a smaller “delta” update this way.)

So, it was a good hint because it got to the heart of the matter, that OSInstall.mpkg was where the script logic determines if your machine is qualified for the restore. However using the original 10.6 disc and copying over all the old printer drivers is a little too kludgy for me, the less donethe better. I knew there had to be a more elegant way…

Voila – this bash script strives for automagic: it reads in your restore disc, prompts you to grab your disc and pop in a blank DVD, then modifies the install logic, and burns the disc you can use on all your Snow Leopard elligible Macs (P.S. Don’t steal OS X). It hasn’t been QC’d or QA’d beyond a few runs using one set of 10.6.7 restore disc, but I hope it comes in handy for some Mac tech out there somewhere who is in a pinch and needs to restore Snow Leopard – if only to get App Store on a machine and then up to 10.7 or 10.8!

makeUniversalSnowLeoDisc.command

#!/bin/bash
clear

destination=~/Desktop/Mac\ OS\ X\ Install\ DVD

#make destination folder
[ ! -d "$destination" ] && mkdir "$destination"

#make sure disc is in drive
while [ ! -d /Volumes/Mac\ OS\ X\ Install\ DVD ] ; do
echo Please insert Mac OS X Install DVD and press Enter
read
done

#get device node for block copy
device=$(diskutil info /Volumes/Mac\ OS\ X\ Install\ DVD/ | grep Node | cut -f2 -d:)

#create disk image from device (retains Finder window custom background)
echo "Creating Disc image at $destination, please wait..."
/usr/bin/hdiutil create -srcdevice $device -format UDRW "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#disk image using source folder (loses custom Finder background)
#/usr/bin/hdiutil create -srcfolder /Volumes/Mac\ OS\ X\ Install\ DVD/ -format UDRW "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#eject media
/usr/bin/drutil eject

#tell user to take out disc
echo -e $'\a'$'\a'$'\a'$'\n'"Please Remove the disc and press Enter"$'\n'
read

echo "Modifying Image"
#mount r/w image
hdiutil attach "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

#expand OSINstall.mpkg
/usr/sbin/pkgutil --expand /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded

#modify Distribution script in place with no backup
/usr/bin/sed -i '' "s/modelProp\ \=\=\ hwbeSupportedMachines\[i\]/1/g" /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded/Distribution

#modify Distribution script in place with backup (for sissies)
#/usr/bin/sed -i '.original' "s/modelProp\ \=\=\ hwbeSupportedMachines\[i\]/1/g" /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded/Distribution

#remove original OSInstall.mpkg package
/bin/rm -rf /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg

#flatten new package
/usr/sbin/pkgutil --flatten /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.mpkg

#remove expanded folder
/bin/rm -rf /Volumes/Mac\ OS\ X\ Install\ DVD/System/Installation/Packages/OSInstall.expanded

### image is now ready to be burned ###

#eject disk image
hdiutil eject /Volumes/Mac\ OS\ X\ Install\ DVD/

#burn disc image
/usr/bin/drutil burn "$destination"/Mac\ OS\ X\ Install\ DVD.dmg

echo -e $'\a'$'\a'$'\a'$'\n'"Disc Complete, Please Remove the disc"$'\n'

Make Safari find substring matches by default

So, I thought I’d tip ol’ Pierre at betalogue to an apparent bug that Safari doesn’t find substrings, only words that begin with the search string! But then his astute readers pointed out that Safari 5.1 has changed the behaviour of the Find window, if you just look close enough *blush*

Now by default in Safari 5.1, when you hit Command-F and type in a word, Safari will match words that “Start with” your search item, clicking the magnifying glass, presents you with the option to search for words that “Contain” your search phrase (this was the default search behaviour in Safari pre-5.1), and in fact clicking the magnifying glass used to step through matches. Who knew!? I’m a (Shift)/Command-G man myself.

Now how could we change this behaviour back for a few hundred users who are used to the way Safari has been functioning before Apple so elegantly altered it? Here we go!

Preference domain: com.apple.Safari
Key Name: FindOnPageMatchesWordStartsOnly
Values: Boolean, TRUE equals “Start With” and FALSE equals “Contains”.

It is a per-user preference, if the key is not present Safari defaults to “Start With” in a search. Writing the pref to the higher level /Library/Preferences/com.apple.Safari.plist will affect all users who don’t already have the key set, otherwise Safari will defer to the user’s prefs (and it can then be assumed the user is aware of the change since they clicked on the magnifying glass and altered the setting).

Here’s the defaults commands for Terminal to set Safari’s Find back to “Contains”:
All Users (who don’t have it set in their prefs)
defaults write /Library/Preferences/com.apple.Safari FindOnPageMatchesWordStartsOnly -bool FALSE
Current User
defaults write com.apple.Safari FindOnPageMatchesWordStartsOnly -bool FALSE

There you go that’ll get things back the way they were, make sure it’s all on one line, the theme seems to like to wrap code, but a copy/paste does not include the newline.

Restore previous Safari version from .SafariArchive.tar.gz

Did that new Safari update break something? Want your old version back?
Simple. Thanks to Apple’s prescient yet secretive engineers, there’s a way.
Let me show you.

When Safari does an upgrade it saves the previous version in this location:
/Library/Application\ Support/Apple/.SafariArchive.tar.gz

To restore we just need to tell tar to expand the archive to the root folder:
sudo tar -xvf /Library/Application\ Support/Apple/.SafariArchive.tar.gz -C /

To be complete, delete the receipt from /var/db/receipts, in this case it is Safari 5.1
sudo rm -rf /private/var/db/receipts/com.apple.pkg.Safari51SnowLeopard.*

Reboot. (since we’ve just replaced a whole bunch of public and private frameworks the OS uses)

Done.
(Whew. This will fix the early Safari 5.1 adopters at work who now can’t use our Java based timesheet app since upgrading!)

myXProtectStatus

myXProtectStatus – A drop down status menulet for XProtect, showing date, version, and threats protected against. Written in bash, and wrapped with Platypus, it is informational only, so don’t ask me to add some menu item to do something, it just reports. However I did add the Command Line and GUI ways to update XProtect in the output, so it’s of some use for that. When run, it’ll reside in your menu bar and call a script inside itself each time it runs. Tuck it away somewhere, add it to your loginitems. Check it every once and a while…

Screenshot of myXProtectStatus:

Other notes: I pipe the output of the threat list though /usr/bin/uniq, because while Hell.RTS has three different signatures it retains the same name in each and it seemed redundant to list all of them out! So all recurring names will be reduced to one entry.

The menu bar icon: it’s an X with a grey picket fence around it, I made it tiny… then realized I need an icon for the App too rather than Platypus’ so I sized it up, it’s fugly, but you’ll never see it! :)

Bonus: When run as root, it will show the auto-update on/off status, which can only be determined on the command line by root.

 

Safe Downloads List Info Widget

UPDATE: The AUTOUPDATE code only works as root and so is not useful in the Dashboard environment! This has been removed from the widget.

So I slapped together a widget for the Safe Downloads commands I post at OSXHints:

Safe Downloads Info Widget

Nothing glamorous just the facts and the following code is how it gets it’s values:

defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta LastModification
defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta Version

The auto updates status took a bit more massaging:

eval $(sudo defaults read /private/var/db/launchd.db/com.apple.launchd/overrides com.apple.xprotectupdater | sed 's/ //g')
if [ ${Disabled:=0} -eq 0 ]; then
echo ON
else
echo OFF
fi

All apologies to Dashboard coding perfectionists but the calls for the widget are synchronous, and reading up on Dashboard coding best practices, Apple says a shipping widget should only use asynchronous calls for info… oh well it works well enough for me! :) Perhaps I’ll go back and throw in extra lines of code for asynchronous handlers when I can, if my widget freezes up any other widgets you can simply restart Dashboard by killing to Dock process from Activity Monitor.

Related:
myXprotect Status – a drop down list of threats protected against for the menu bar

More App Store tips for admins

Continuing the tech ramble about how to keep the App Store from your users…

So, I figured out the two ways the App Store icon is added to the dock:

1. Existing users on an upgraded system are affected by this file: /Library/Preferences/com.apple.dockfixup

Looking at the add-app key inside contains the answer:

<key>add-app</key>
<array>
<dict>
<key>path</key>
<string>/Applications/App Store.app</string>
<key>after</key>
<string>begin</string>
</dict>
</array>

We can rid ourselves of  this behavior with defaults:

defaults delete /Library/Preferences/com.apple.dockfixup add-app

However, if you try to use a loginhook to remove the icon, it will not take effect unitl the second login, sine the loginhook runs before Apple’s dockfixup is applied.

The solution to a user never seeing it (and avoiding calls about it) is to use a daemon that runs at system startup and deletes the entry in the plist before it is ever used.

Save as /Library/LaunchDaemon/com.brunerd.dockfixer.plist (or whatever you wish):

<?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>Label</key>
<string>com.sts.dockfixup</string>
<key>ProgramArguments</key>
<array>
<string>defaults</string>
<string>delete</string>
<string>/Library/Preferences/com.apple.dockfixup</string>
<string>add-app</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

You could call another script, check for add-app’s presence, but having this run everytime, insures that despite OS updates and reversions of files your user will never have App Store added to their Docks.

2. Suppressing App Store in new user accounts is affected by Dock.app’s default.plist:
/System/Library/CoreServices/Dock.app/Contents/Resources/English.lproj/default.plist

But just deleting this and not com.apple.fixup.plist will not do what you want since fixup will still run, you must delete both. Altering that is the perfect job for removeitemfromdock… if only it worked with a supplied path… now it does! So after installing and downloading you can run this command to alter the default dock:

sudo /sbin/removeitemfromdock -f /System/Library/CoreServices/Dock.app/Contents/Resources/English.lproj/default.plist /Applications/App\ Store.app/

You could make this another Daemon or just have the daemon call an external script, your choice, I can’t do all the work for you :)