Determine if any Apple Software is in the Cache

mhinsz
New Contributor III

Hello.

I'm looking for a simple way - hopefully - to determine if there are any Apple Software Updates in the cache.

softwareupdate -d will cache updates, but I'm trying to build a Smart Group based policy that would only run if software updates have been cached.

Theoretically, a script could be used to look at the file size of /Library/Updates - where Apple Software Updates are stored, but that seems a bit clunky and overkill.

Thanks for any help.

8 REPLIES 8

mm2270
Legendary Contributor III

Do you have the option enabled in your JSS' inventory preferences to capture Software Updates? If so, I believe the JSS will report on available updates, and you can use the native criteria for your Smart Group.

If not, I do have some code that will tell you if updates are cached in that folder if you're interested.

mhinsz
New Contributor III

I'm seeing whether there are updates available, I want to make the distinction that they have been downloaded into the cache. I'd working on policies to have the updates cached before installation.

I'd be happy to see your code :)

alexjdale
Valued Contributor III

It looks like "ls -d /Library/Updates" would be a good way to get the data into an extension attribute. It would return all directories in that folder, and as far as I can tell the only results would be for cached updates.

You could process that result a little more to just extract the update names or get a count. That said, it would also return results for updates that are currently being downloaded but are not yet complete.

mm2270
Legendary Contributor III

Understood. So, hopefully the following info will help you out. Inside the /Library/Updates/ folder, you'll also notice an index.plist. That plist contains a reference to the locally created folders, or product IDs when softwareupdate caches updates.
The following command prints out just those Product IDs

defaults read /Library/Updates/index.plist ProductPaths | awk -F'"' '{print $4}' | sed '/^$/d'

You should be able to compare these IDs to the actual folders that are in /Library/Updates/, so for example, I might do something like this as an Extension Attribute to get a count of the cached updates in that directory, though note that its really only looking for the folder and not really checking the contents. YMMV with that since its always possible for the content to get removed by something and the folder to remain in place.

#!/bin/bash

## Gets the number of cached updates in /Library/Updates/

while read productID; do
    if [ -d "/Library/Updates/$productID" ]; then
        cachedUpdates+=("$productID")
    fi
done < <(defaults read /Library/Updates/index.plist ProductPaths | awk -F'"' '{print $4}' | sed '/^$/d')

echo "<result>$(printf '%s
' "${#cachedUpdates[@]}")</result>"

The above should print out a number, like 0, 1, 5, etc. You should be able to use that EA to gather machines that have one or more cached updates. Again, the above could end up being incorrect if someone was to go in manually and delete some of the updates out of that folder and leave the folders themselves behind. Probably not very likely of course, but something to keep in mind anyway.

If you need something that will really verify the updates are there, there are some ways to do that as well.

mhinsz
New Contributor III

Much thanks @mm2270 :

One change to the script looks like a typo: last line should be:

echo "<result>$(printf '%s
' "${#cachedUpdates[@]}")</result>"

there was an extra "s" in the last result(s)

mm2270
Legendary Contributor III

You're right, that extra "s" shouldn't be in the closing tag. Thanks for the catch. I updated my post above so its correct.

tkimpton
Valued Contributor II

This seems to have changed in macOS Big Sur. I tried above and does not work anymore. @mm2270 do you know a working one for Big Sur?

tkimpton
Valued Contributor II

This is what i have so far and it is looking promising

 

#!/bin/bash

OS_MAJOR=$(sw_vers -productVersion | awk -F. '{print $1}')
OS_MINOR=$(sw_vers -productVersion | awk -F. '{print $2}')
OS_BUILD_VERS=$(sw_vers -buildVersion | cut -c 1-2)

# If the OS Is lower than macOS Big Sur then read  /Library/Updates/index.plist
if [[ "$OS_MAJOR" -lt 11 ]]; then
	while read productID; do
    	if [ -d "/Library/Updates/$productID" ]; then
        	cachedUpdates+=("$productID")
    	fi
	done < <(defaults read /Library/Updates/index.plist ProductPaths | awk -F'"' '{print $4}' | sed '/^$/d')
	echo "<result>$(printf '%s\n' "${#cachedUpdates[@]}")</result>"

# If the OS Is equal or greater then macOS Big Sur then look in the new location and xml 
elif [[ "$OS_MAJOR" -ge 11 ]]; then
	XML="/System/Library/AssetsV2/com_apple_MobileAsset_MacSoftwareUpdate/com_apple_MobileAsset_MacSoftwareUpdate.xml"
	if [ -e "$XML" ]; then
		
		# Using PlistBuddy read the xml to see if there is a CachedAssetSetId entry
		QUERY=$(/usr/libexec/PlistBuddy -c "Print :CachedAssetSetId" "$XML" 2> /dev/null)
		
		#If the xml query is not blank then go count how many *.asset folders (the actual downloads exist)
		if [ "$QUERY" != "" ]; then
		DOWNLOADS=$(ls -l /System/Library/AssetsV2/com_apple_MobileAsset_MacSoftwareUpdate/ | grep -v "grep" | grep "^d" | grep "asset" | wc -l)
			echo "<result>$(printf '%s\n' "${DOWNLOADS//[[:space:]]}")</result>"
		else 
			echo "<result>0</result>"
		fi
	fi
fi
exit 0