Xprotect Status Extension Attribute

milesleacy
Valued Contributor

Hey all,

I'm researching this, but in the interest of not reinventing the wheel, I thought I'd ask the nation...

The Xprotect Status extension attribute posted here returns the following on 10.11.3:

The domain/default pair of (/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta, LastModification) does not exist

I've looked through the file referenced and there's no instance of a date or the words "modified," "modification," change," or "update" in the XML. Does anyone know where to look for the last Xprotect update?

3 ACCEPTED SOLUTIONS

mm2270
Legendary Contributor III

Hmm. That's a good question and I think the LastModification line has not shown up in that plist for a while now. Its not in my 10.10.5 Mac's plist anyway.

I seem to recall seeing somewhere that XProtect files moved around to different places, but I can't recall now where to find the modification date.

Just in case no-one shows up with a proper explanation, however unlikely that is here, here's a method using stat -s and converting the raw mtime format into a Casper friendly format:

date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +"%Y-%m-%d %T"

As an aside, here's a nice way of getting a full list of the applied XProtect malware blocks. I have not confirmed if the list this pulls is accurate or not. It may or may not be.

xmllint --format /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist | awk -F'>|<' '/Description/{getline; print $3}' | sed '/^$/d'

View solution in original post

rtrouton
Release Candidate Programs Tester

Now that I've seen @mm2270's method, I like his better for pulling the information from the 10.6 - 10.8 XProtect.meta.plist file. Updated EA below:

#!/bin/bash

osvers_major=$(sw_vers -productVersion | awk -F. '{print $1}')
osvers_minor=$(sw_vers -productVersion | awk -F. '{print $2}')

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -lt 6 ]]; then

result="XProtect not available for `sw_vers -productVersion`"

  echo "<result>$result</result>" 

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 6 ]] && [[ ${osvers_minor} -lt 9 ]]; then

last_xprotect_update_epoch_time=`date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +%s`
last_xprotect_update_human_readable_time=`date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
result="$last_xprotect_update_human_readable_time"

  echo "<result>$result</result>" 

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 9 ]]; then

  last_xprotect_update_epoch_time=$(printf "%s
" `for i in $(pkgutil --pkgs=".*XProtect.*"); do pkgutil --pkg-info $i | awk '/install-time/ {print $2}'; done` | sort -n | tail -1)
  last_xprotect_update_human_readable_time=`/bin/date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
  result="$last_xprotect_update_human_readable_time"

  echo "<result>$result</result>"

fi

That should give consistent human-readable output for 10.6.x and higher, as well as handling 10.5.8 and earlier by indicating that XProtect is not available for those versions of Mac OS X.

EDIT: After more testing, I realized that Apple changed how it named XProtect receipts sometime between 2014 and 2015. That meant that tailing the list may give an inaccurate result.

I've updated the EA so that it's checking when the individual XProtect installer packages were actually installed, as that will give a more accurate reading of the last time XProtect was updated.

View solution in original post

mm2270
Legendary Contributor III

Hey @milesleacy, something like this is close I think:

/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist PlugInBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;N;s/
/ /'

On my 10.10.5 Mac this outputs:

com.apple.java.JavaAppletPlugin 14.8.0
com.apple.java.JavaPlugin2_NPAPI 14.8.0
com.macromedia.Flash Player ESR.plugin 18.0.0.324
com.macromedia.Flash Player.plugin 20.0.0.267
com.microsoft.SilverlightPlugin 5.1.41212.0
com.oracle.java.JavaAppletPlugin 1.8.51.16

The only issue is that there is a key above the 'PlugInBlacklist' dict that has the following, which won't show up in the results:

<key>JavaWebComponentVersionMinimum</key>
    <string>1.6.0_45-b06-451</string>

I believe that's a very old Java version for 10.6 and earlier, back when Apple maintained it, not Oracle. (Actually this looks like Oracle Java now that I'm looking closer at it, so it may just be a simple minimum version string for that, just as it implies) I'm not sure how relevant it is to get that in the results since I don't think that line has changed now in years. For some reason, Apple keeps it outside of the PlugInBlacklist section.

EDIT: Actually I just realized you also wanted the ExtensionBlacklist, not just the Plugin one. Hmm. Not sure if its possible to have a one liner, but you could combine two or three commands to pull it all together I think.
Or, I'd probably maintain two separate EAs. One for the Plugins and one for Safari Extensions.
Here's one for pulling the Safari Extension Blacklist.

/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist ExtensionBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;/Developer Identifier/d'

And the output:

com.searchnt.safari
com.spigot.safari.searchme
com.spigot.safari.ebayshopassist
com.smokycap.safari
com.searchconnect.safariext
com.codec.extension
com.zako.chatzum
com.adobe.flash
com.optimalcycling.safari.popupblocker
com.genieo.safari
com.app65867
com.defaultsearch.safariext
com.jbsearch.safariext
com.mtsearch.safariext
com.rohit.MacMInSale
com.tabgreg.safariext
com.gold.safari
com.eliaho.safari
com.nariabox.safari
com.diigo.safari.awesomeScreenshot
com.portsayd.safari

View solution in original post

34 REPLIES 34

mm2270
Legendary Contributor III

Hmm. That's a good question and I think the LastModification line has not shown up in that plist for a while now. Its not in my 10.10.5 Mac's plist anyway.

I seem to recall seeing somewhere that XProtect files moved around to different places, but I can't recall now where to find the modification date.

Just in case no-one shows up with a proper explanation, however unlikely that is here, here's a method using stat -s and converting the raw mtime format into a Casper friendly format:

date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +"%Y-%m-%d %T"

As an aside, here's a nice way of getting a full list of the applied XProtect malware blocks. I have not confirmed if the list this pulls is accurate or not. It may or may not be.

xmllint --format /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.plist | awk -F'>|<' '/Description/{getline; print $3}' | sed '/^$/d'

thoule
Valued Contributor II

True. There is no LastModification key in that plist. I use 'Version' myself.

rtrouton
Release Candidate Programs Tester

For 10.6.x - 10.8.x, you should still be able to pull the LastModification value from the plist. For 10.9.x and later, I'd go by the installer package receipt, as XProtect updates now come down from the Apple software update feed:

https://derflounder.wordpress.com/2014/12/27/managing-automatic-installation-of-configdata-and-secur...

To poll for the last modified date, I've written the following extension attribute:

#!/bin/bash

osvers_major=$(sw_vers -productVersion | awk -F. '{print $1}')
osvers_minor=$(sw_vers -productVersion | awk -F. '{print $2}')


if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -lt 9 ]]; then
  last_xprotect_update_human_readable_time=`/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta LastModification`

  echo "<result>$last_xprotect_update_human_readable_time</result>" 

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 9 ]]; then

  last_xprotect_update_install=`pkgutil --pkgs=".*XProtect.*" | tail -1`
  last_xprotect_update_epoch_time=`pkgutil --pkg-info "$last_xprotect_update_install" | awk '/install-time/ {print $2}'`
  last_xprotect_update_human_readable_time=`date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`

  echo "<result>$last_xprotect_update_human_readable_time</result>"

fi

rtrouton
Release Candidate Programs Tester

Now that I've seen @mm2270's method, I like his better for pulling the information from the 10.6 - 10.8 XProtect.meta.plist file. Updated EA below:

#!/bin/bash

osvers_major=$(sw_vers -productVersion | awk -F. '{print $1}')
osvers_minor=$(sw_vers -productVersion | awk -F. '{print $2}')

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -lt 6 ]]; then

result="XProtect not available for `sw_vers -productVersion`"

  echo "<result>$result</result>" 

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 6 ]] && [[ ${osvers_minor} -lt 9 ]]; then

last_xprotect_update_epoch_time=`date -jf "%s" $(stat -s /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist | tr ' ' '
' | awk -F= '/st_mtime/{print $NF}') +%s`
last_xprotect_update_human_readable_time=`date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
result="$last_xprotect_update_human_readable_time"

  echo "<result>$result</result>" 

fi

if [[ ${osvers_major} -eq 10 ]] && [[ ${osvers_minor} -ge 9 ]]; then

  last_xprotect_update_epoch_time=$(printf "%s
" `for i in $(pkgutil --pkgs=".*XProtect.*"); do pkgutil --pkg-info $i | awk '/install-time/ {print $2}'; done` | sort -n | tail -1)
  last_xprotect_update_human_readable_time=`/bin/date -r "$last_xprotect_update_epoch_time" '+%m/%d/%Y %H:%M:%S'`
  result="$last_xprotect_update_human_readable_time"

  echo "<result>$result</result>"

fi

That should give consistent human-readable output for 10.6.x and higher, as well as handling 10.5.8 and earlier by indicating that XProtect is not available for those versions of Mac OS X.

EDIT: After more testing, I realized that Apple changed how it named XProtect receipts sometime between 2014 and 2015. That meant that tailing the list may give an inaccurate result.

I've updated the EA so that it's checking when the individual XProtect installer packages were actually installed, as that will give a more accurate reading of the last time XProtect was updated.

chris_kemp
Contributor III

Good stuff, thanks!

mbezzo
Contributor III

Cool, thanks for this!

I'm trying to create a Smart Group of machines that haven't received it - but not sure what an "acceptable" timeframe is. Does anybody know the frequency in which Apple pushes these - is it a regular interval at all?

Any suggestions on how best to do that?

Thanks,
mbezzo

milesleacy
Valued Contributor

@mbezzo Use a Configuration Profile to automate...
1238c0fd11754fb282e2cd653d847ad1
ConfigDataInstall is the key that needs to be set to true.

As far as I know, these updates are issued as needed to respond to exploits. I'm planning to ask my Apple rep in later this week if they're able to share a feed of the latest update either by date or version.

Failing that, you could set up a Mac or OS X VM with known-good automatic updates enabled. Then use it and the JSS API to update your smart group whenever the version/date changes.

milesleacy
Valued Contributor

Anyone have a one liner similar to @mm2270 's XProtect malware blocks list that will output the pluglin and extension blacklists in the format of <bundleIdentifier><space><minimumPluginBundleVersion>?

I want Extension Attributes that InfoSec teams can reference to verify remediation.

I'll give it a whirl when I get home unless anyone else gets it before then.

mm2270
Legendary Contributor III

Hey @milesleacy, something like this is close I think:

/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist PlugInBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;N;s/
/ /'

On my 10.10.5 Mac this outputs:

com.apple.java.JavaAppletPlugin 14.8.0
com.apple.java.JavaPlugin2_NPAPI 14.8.0
com.macromedia.Flash Player ESR.plugin 18.0.0.324
com.macromedia.Flash Player.plugin 20.0.0.267
com.microsoft.SilverlightPlugin 5.1.41212.0
com.oracle.java.JavaAppletPlugin 1.8.51.16

The only issue is that there is a key above the 'PlugInBlacklist' dict that has the following, which won't show up in the results:

<key>JavaWebComponentVersionMinimum</key>
    <string>1.6.0_45-b06-451</string>

I believe that's a very old Java version for 10.6 and earlier, back when Apple maintained it, not Oracle. (Actually this looks like Oracle Java now that I'm looking closer at it, so it may just be a simple minimum version string for that, just as it implies) I'm not sure how relevant it is to get that in the results since I don't think that line has changed now in years. For some reason, Apple keeps it outside of the PlugInBlacklist section.

EDIT: Actually I just realized you also wanted the ExtensionBlacklist, not just the Plugin one. Hmm. Not sure if its possible to have a one liner, but you could combine two or three commands to pull it all together I think.
Or, I'd probably maintain two separate EAs. One for the Plugins and one for Safari Extensions.
Here's one for pulling the Safari Extension Blacklist.

/usr/bin/defaults read /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist ExtensionBlacklist | awk -F'"' '{print $2}' | sed '/^$/d;/Developer Identifier/d'

And the output:

com.searchnt.safari
com.spigot.safari.searchme
com.spigot.safari.ebayshopassist
com.smokycap.safari
com.searchconnect.safariext
com.codec.extension
com.zako.chatzum
com.adobe.flash
com.optimalcycling.safari.popupblocker
com.genieo.safari
com.app65867
com.defaultsearch.safariext
com.jbsearch.safariext
com.mtsearch.safariext
com.rohit.MacMInSale
com.tabgreg.safariext
com.gold.safari
com.eliaho.safari
com.nariabox.safari
com.diigo.safari.awesomeScreenshot
com.portsayd.safari

milesleacy
Valued Contributor

Thanks @mm2270! That's exactly what I was looking for. I owe you a beer next time you're in the Bay Area.

milesleacy
Valued Contributor

Thanks to @rtrouton as well.

The second script you posted is great for environments where running an old OS X version is acceptable.

scottb
Honored Contributor

FWIW, you can force this stuff to update using:

sudo softwareupdate --background-critical

TomDay
Release Candidate Programs Tester

@thoule I used "Version" as you suggested and my EA works now by pulling the version and I get "2076" as the output for the EA on my test device. Where do you cross reference or look up to actually see what the latest version is? Does Apple post it somewhere? All of my Google searches have tuned up empty.

scottb
Honored Contributor

There are a number of items that fall within Apple's newer security updates scheme. Here is a screenshot of the little AppleScript app we use that shows the items and the dates, etc.
I won't post up the code as it's a rudimentary AS that was written by someone else and it got a lot of grief from guys that know how to write code properly. It does the job nicely, and we can see when the Macs are getting behind on things or not.

5d8df83b0d1045358eaf4af368edf944

TomDay
Release Candidate Programs Tester

@scottb Nice lil trick there. I am by know means a coder, would love a look at the code if you don't mind off this thread somehow? Having those stats would be extremely helpful!

milesleacy
Valued Contributor

@scottb Never be afraid of rough code. It's how we all learn. I'd love to see what's behind that screenshot!

gachowski
Valued Contributor II

@scottb

Me too : ) I know that I can use your exact AS in my environment. And I don't care what it looks like : ) it will get the job done and allow me move on to the next thing I have to fix/improve : )

C

mm2270
Legendary Contributor III

+1 to the above comments. I'm interested to see how its pulling the above info. I took a quick look yesterday, and I can see where its getting the XProtect version, as already mentioned on this thread, but I'm not sure where its getting the other data from. Would love to see it.

scottb
Honored Contributor

OK, I'll post it. Again - I did NOT write this. I didn't even know it was "crap" until I put it on Slack one day and got endless ribbing over it. I'm just learning the basics now and was only trying to be helpful. So, again, with apologies towards those who know WTH they are doing with code, here it is. Hope you find it useful. This one if for 10.11.x. I think I also have one setup for the older OS X's. I'll locate that and post later.

Open up Script Editor and create a new item. Save as a ".app" and run.

set a to do shell script "defaults read /System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist Version"
tell application "Finder" to set b to get creation date of (POSIX file "/System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist" as alias)
set s to short date string of b
set t to time string of b
set c to do shell script "defaults read /private/var/db/gkopaque.bundle/Contents/version.plist CFBundleShortVersionString"
tell application "Finder" to set d to get creation date of (POSIX file "/private/var/db/gkopaque.bundle/Contents/version.plist" as alias)
set u to short date string of d
set v to time string of d
set e to do shell script "defaults read /System/Library/CoreServices/SystemVersion.plist ProductVersion"
set f to do shell script "defaults read /System/Library/CoreServices/SystemVersion.plist ProductBuildVersion"
set g to do shell script "defaults read /System/Library/Sandbox/Compatibility.bundle/Contents/version.plist CFBundleShortVersionString"
tell application "Finder" to set h to get creation date of (POSIX file "/System/Library/Sandbox/Compatibility.bundle/Contents/version.plist" as alias)
set w to short date string of h
set x to time string of h
set i to do shell script "defaults read /System/Library/CoreServices/MRT.app/Contents/version CFBundleShortVersionString"
tell application "Finder" to set j to get creation date of (POSIX file "/System/Library/CoreServices/MRT.app/Contents/version.plist" as alias)
set y to short date string of j
set z to time string of j
set k to do shell script "defaults read '/System/Library/Intelligent Suggestions/Assets.suggestionsassets/Contents/version.plist' CFBundleShortVersionString"
tell application "Finder" to set l to get creation date of (POSIX file "/System/Library/Intelligent Suggestions/Assets.suggestionsassets/Contents/version.plist" as alias)
set m to short date string of l
set n to time string of l
display dialog "XProtect " & tab & tab & a & tab & tab & s & tab & " " & t & return & "Gatekeeper " & tab & tab & c & tab & tab & tab & u & tab & " " & v & return & "SIP " & tab & tab & tab & tab & g & tab & tab & tab & w & tab & " " & x & return & "MRT " & tab & tab & tab & i & tab & tab & tab & y & tab & " " & z & return & "Core Suggest " & tab & k & tab & tab & tab & m & tab & " " & n & return & return & "OS X " & e & " (" & f & ")" buttons {"Close"} default button 1

mm2270
Legendary Contributor III

Thanks for posting @scottb. Its not crap, but I would say that some of the labels used throughout could be more descriptive. Its a little tough to follow what "h" or "x" means, so if anything I would only change some of the set <label> strings to things that are more descriptive so its easier to understand and troubleshoot. Also, a few items could be shortened, but again, far from crap.

scottb
Honored Contributor

@mm2270 - I was going to try and re-do it and make it a little easier to grasp - just never took the time to do it.
I see what you mean, and honestly, I often grab code here and there and try to understand it and re-form it to my needs. I'll mess around one day to see if I can clean it up while keeping it functional. I already feel subpar when it comes to the guys like you who write the code, so I was a bit thin-skinned over the response to it before, even though it's not my creation.

mm2270
Legendary Contributor III

@scottb Yes, well, its an unfortunate fact of the internet age that snobs of all kinds (code snobs, intellectual snobs, grammar snobs, etc) have found a haven behind their screens and keyboards to make fun of anyone who doesn't know as much as them in their preferred topic. Its a sign of confidence issues in themselves really, and I doubt most of them would say what they say online to someone's face, but.. I digress.

Personally I learned a lot looking at that, because I was honestly not aware of some of those files and plists to check for versions and creation dates, so props to whomever wrote it for knowing what to look for in the first place, even if the code could be a little cleaner.

gachowski
Valued Contributor II

@scottb

Mike is spot on!!!! : ) Life is way to short for any snobs : ) That said I am an Apple and Casper snob

Thank you very much Scott!!!

C

TomDay
Release Candidate Programs Tester

Excited to get this running but when I create the .app file with TextWrangler and run the file, the .app won't run, throws up an error "You can’t open the application “GetLatestVersionASU” because PowerPC applications are no longer supported.

Researching how to get his done, but if any of the gurus know the answer, I'd greatly appreciate the help!

mm2270
Legendary Contributor III

@TomDay Its an Applescript, so you need to paste it into Script Editor, located in /Applications/Utilities/ and then click the build button in the toolbar. Then save it as an application bundle. See screenshots...

Raw code, click the Build button highlighted
78bdbe89eafd42ffa305df0c6c42a322

The compiled code. Save from here to an application bundle
77212270769e475baa314a2bfb5d3a7f

TomDay
Release Candidate Programs Tester

@scottb Thanks so much for sharing the code and @mm2270 thank you for taking the time to teach me that, I got it working now!

scottb
Honored Contributor

@TomDay - I posted that above but maybe I should have used bold on it.
Glad you guys are finding it useful. We use it in testing seed builds of the OS so I guess I forgot how cool it was when I started using it as well. Maybe a good item to put into Self Service for checking on Macs in the "Maintenance" tab. Not that anyone would know what to do with the info, but it looks nice. :)

mbezzo
Contributor III

Thanks scottb! Appreciate the share.

Forgive my ignorance, but anybody have any info on "Core Suggest"? I'm not familiar with it and didn't find much with a quick search.

scottb
Honored Contributor

@mbezzo - here's the contents of it. Still not really sure, but you can get some ideas looking at this:

e6a4dc5ede7d454fbed47df5a09189de

mbezzo
Contributor III

@scottb Interesting - thanks!

scottb
Honored Contributor

Here's an updated rev that is a little nicer. A mix of contributions by a few people.
Gives you the below in the screenshot.

--start of script 

########################################## 
# Variables 
########################################## 
set updateMarker to " *"

set saveLocation to "~/Library/Preferences/com.appleseedCriticalUpdates.txt"

set lastUpdate to {}

set thisDate to {}

set hasBeenUpdated to ""

set TimeStrings to {"/System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist", "/private/var/db/gkopaque.bundle/Contents/version.plist", "/System/Library/Sandbox/Compatibility.bundle/Contents/version.plist", "/System/Library/CoreServices/MRT.app/Contents/version.plist", "'/System/Library/Intelligent Suggestions/Assets.suggestionsassets/Contents/version.plist'", "/System/Library/Extensions/AppleKextExcludeList.kext/Contents/version.plist", "/usr/share/mecabra/updates/com.apple.inputmethod.SCIM.bundle/Contents/version.plist", "/usr/share/kdrl.bundle/info.plist"}

set VersionStrings to {"/System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.meta.plist Version", "/private/var/db/gkopaque.bundle/Contents/version.plist CFBundleShortVersionString", "/System/Library/Sandbox/Compatibility.bundle/Contents/version.plist CFBundleShortVersionString", "/System/Library/CoreServices/MRT.app/Contents/version CFBundleShortVersionString", "/System/Library/Intelligent\ Suggestions/Assets.suggestionsassets/Contents/version.plist CFBundleShortVersionString", "/System/Library/Extensions/AppleKextExcludeList.kext/Contents/version CFBundleShortVersionString", "/usr/share/mecabra/updates/com.apple.inputmethod.SCIM.bundle/Contents/info SUVersionString", "/usr/share/kdrl.bundle/info CFBundleVersion"}

set theComponents to {"XProtect", "Gatekeeper", "System Integrity Protect...", "Malware Removal Tool", "Core Suggestions", "Incompatible Kernel Ext...", "Chinese Word List", "Core LSKD (dkrl)"}
set theTabSpaces to ""

set _multiTabs to tab & tab & tab & tab
set displayString to "Component" & _multiTabs & "Version" & tab & "Updated" & tab & tab & "Time" & return & "_______________________________________________________________" & return & return


########################################## 
# Handlers 
########################################## 


# calculate the number of tabs required for the display dialog 
on getTabs(aWord)
    set n to round (25 - (length of aWord)) / 4
    if n is less than 0 then set n to 1
    if length of aWord is 10 then set n to 3
    set this_tab to tab
    repeat n times
        set this_tab to this_tab & tab
    end repeat
    return this_tab
end getTabs

#get the last modification date 
on getUpdatedDate(aFile)
    set d to do shell script "stat -f "%Sc" -t "%d-%m-%Y %H:%M" " & aFile
    set end of my thisDate to d
    return d

end getUpdatedDate

#compare the dates to see if there's been a change 
on checkLastUpdate(aDateString, anIndex)
    set n to text 1 thru 10 of aDateString
    set o to text 1 thru 10 of my (item anIndex of lastUpdate)

    if (n is equal to o) then
        return ""
    else
        return my updateMarker
    end if
end checkLastUpdate


########################################## 
# Commands 
########################################## 

# read the dates into our script from the last run 
set oldTIDS to AppleScript's text item delimiters
set AppleScript's text item delimiters to ","
try
    set s to (do shell script "cat " & saveLocation)
    set lastUpdate to text items of s
end try
set AppleScript's text item delimiters to oldTIDS

# this is the workhorse, getting all the data for each component 
repeat with i from 1 to number of items in theComponents
    set component_item to item i of theComponents
    set version_item to item i of VersionStrings
    set time_item to item i of TimeStrings
    set theTabSpaces to getTabs(component_item)
    set updatedDate to getUpdatedDate(time_item)

    # check if we had some saved dates from a previous run 
    #and if so, check them against the current dates 
    if (count of (lastUpdate as list)) = (count of theComponents) then
        set my hasBeenUpdated to checkLastUpdate(updatedDate, i)
    end if

    # organise the display string 
    set v to (do shell script "defaults read " & version_item)
    if length of v < 4 or (length of v = 4 and v contains ".") then set v to v & tab
    set displayString to displayString & component_item & theTabSpaces & v & tab & updatedDate & my hasBeenUpdated & return
    set my hasBeenUpdated to ""
end repeat

#write out current dates to file 
set writeData to ""
repeat with i from 1 to number of items in thisDate
    set this_item to item i of thisDate
    if length of writeData is 0 then
        set writeData to this_item
    else
        set writeData to writeData & "," & this_item
    end if
end repeat
do shell script "echo " & writeData & "> " & saveLocation

# finally, get the OS version and build 
set theSysInfo to (do shell script "sw_vers")
set sysString to paragraph 2 of theSysInfo & return & paragraph 3 of theSysInfo
set displayString to displayString & return & sysString

# and... 
display dialog displayString buttons {"Close"} default button "Close" with title "Critical Updates (v1.1)"

--EOF

4bffd5f991f843e3a462fbf8a0253f26

ClassicII
Contributor III

@scottb

Nice AppleScript! Hey have you updated this for 10.12?

scottb
Honored Contributor

@ClassicII - not yet. I'll see if that can be looked at and post back. Thanks for the reminder... Happy 4th!

scottb
Honored Contributor

Hey @ClassicII et.al, Phil has taken this over and is offering it up on his site (with other stuff). Check it out - he's a dev and a longtime fellow AppleSeeder. I pinged him about getting the script as he delivers it in .app form now. If he's cool with me posting the script here, I'll add it later. We used to pass it around and folks would edit to their needs...guess he's the gatekeeper (not intended) now.

Phil's site

Current screenie

e030cf5cadac4e7cac759967a8fd8d22