Add Apple's CatalogURL to one time command ?

May
Contributor III

Hi All

I'm working on the best way to update XProtect and Gatekeeper whilst keeping auto updates unticked as we don't want those joyous notifications.

The plan is to temporarilly enable ConfigDataInstall:
defaults write /Library/Preferences/com.apple.SoftwareUpdate ConfigDataInstall -bool True

And softwareupdate schedule:
softwareupdate --schedule on

Then run

softwareupdate --background-critical

then turn it all off again after the installation has completed

I'd like the option to download these updates from Apple's catalog rather than our own SUS as it's not accessible externally.

Does anyone know of a way i can add Apple's catalogurl to the softwareupdate --background-critical command or another way i can get it to download from Apple and temporarilly ignore our SUS (which is set via a Config profile)

Cheers,
Andy

11 REPLIES 11

dwandro92
Contributor III

The solution that comes to mind is shown below. Please bear in mind that the solution is for a SUS hosted via JAMF NetBoot/SUS or reposado, and may not be applicable on a SUS hosted via the OS X Server app:

  1. Configure the SUS to download updates daily.
  2. Setup a script to run on the SUS which does the following:
    • Monitors changes to the mirrored update catalogs.
    • When changes occur, checks if new Gatekeeper/XProtect updates have been released.
    • If new updates have been released, automatically adds them to all SWU branches so that they will be installed automatically using softwareupdate --background-critical.

May
Contributor III

Thanks for the info @dwandro92

That won't work for our current set up as Our SUS is running on OS X server, i do plan to set up Reposado but it won't be in the near future.

dwandro92
Contributor III

Is your SUS configured to auto download updates with manual enablement?

May
Contributor III

@dwandro92 We're using Manual download and manual enable

dwandro92
Contributor III

I created a script for use on an Apple SUS:

#!/bin/bash

# Use newline for field seperator
IFS=$'
'

# Function for writing to the log file
writeLog() { 
    # Get timestamp for logging purposes
    timeStamp=`date "+%m/%d/%Y %H:%M:%S"`

    # Set output message text to timestamp and message. Omit timestamp if message is blank
    [ -n "$1" ] && outMsg="$timeStamp - $1" || outMsg=""

    # Output message to log and shell
    echo -e "$outMsg" | tee -a "$logFile"
}

# Set path to log file
logFile="/var/log/SWU_Sync.log"

# Set alias for software update sync
swuSync="/Applications/Server.app/Contents/ServerRoot/usr/sbin/swupd_syncd"

# Set path to Software Update home directory
swuDir="/Library/Server/Software Update/Data/html"

# Output information
writeLog "Running software update sync..."

# Run software update sync
"$swuSync" -sync

# Get a list of all catalogs 
appleCatalogs=(`ls "${swuDir}/content/catalogs/others" | grep -E '.apple$'`)

# If Apple catalogs were found
if [ ${#appleCatalogs[@]} -ne 0 ]; then
    # For each catalog that was found
    for appleCatalog in ${appleCatalogs[@]}; do
        # Output infromation
        writeLog "Searching for Gatekeeper and XProtect updates in ${appleCatalog}..."

        # Get a list of all XProtect and Gatekeeper packages from Apple's catalogs
        applePkgs=(`grep -E -i 'XProtect|Gatekeeper' "$swuDir/content/catalogs/others/$appleCatalog" | grep '.pkg' | sed -e 's/.*/content/content/g' -e 's/</.*//g'`)

        # If packages were found
        if [ ${#applePkgs[@]} -ne 0 ]; then
            # Set local catalog filename
            localCatalog=`echo "$appleCatalog" | awk -F '.apple' '{ print $1 }'`

            # For each package that was found
            for applePkg in ${applePkgs[@]}; do
                # Get ID for update
                updateID=`echo "$applePkg" | awk -F '/' '{ print $5 }'`

                # Set package to update package
                pkgPath="$swuDir/$applePkg"

                # If the package doesn't exist (hasn't been downloaded)
                if [ ! -e "$pkgPath" ]; then
                    # Output information
                    writeLog "Downloading update $updateID..."

                    # Download the update
                    "$swuSync" -mirror $updateID 
                fi

                # Check if update is enabled
                enabledCheck=`grep "$updateID" "$swuDir/content/catalogs/others/$localCatalog"`

                # If update is not enabled
                if [ -z "$enabledCheck" ]; then
                    # Output information
                    writeLog "Enabling update $updateID..."

                    # Enable the update
                    "$swuSync" -enable $updateID 2>&1
                fi
            done
        fi
    done
fi

# Exit script
exit 0

Please keep in mind that I don't actually use Apple SUS in my environment, and have therefore only verified this script's functionality on a test server that doesn't serve any clients.

May
Contributor III

Hi @dwandro92 that is awesome thank you!

Running through the script i think maybe i didn't describe what we wanted to acheive properly, my script Fu is
not that strong so i may have read it wrong! but it looks like it's all based on the SUS, the change we want to make is on the Mac end of things.

We are able to download the XProtect and Gatekeeper updates to our SUS and manually enable them, and we can install these updates on a Mac by temporarily enabling Automatically check for updates, ConfigDataInstall and running the command "softwareupdate --background-critical"
(without the auto updates on and ConfigDataInstall enabled Xprotect + Gatekeeper updates do not get installed info here
This works great for users inside the network with access to our SUS

We have Automatically check for updates turned off as we don't want users to get Software update notifications.

What i'm looking for is a simple way to temporarilly overide the setting that points each Mac to our SUS and have them get these updates from Apple. We set our SUS CatalogURL using a Configuration Profile.
If there is a command that i could add to softwareupdate --background-critical that would be perfect, i'll keep looking :)!

Thanks again for your help

bpavlov
Honored Contributor

If you have a profile that points your client machines to your internal SUS then you will most likely need to have that profile removed as that's going to dictate the SUS the client points to.

Is there any particular reason you are against the notifications? Seems like a lot of trouble just to avoid notifications.

May
Contributor III

Hi @bpavlov

Thanks for the info,

We'd like to keep notifications off as our users do not have rights to install any Apple updates and the notifications will cause confusion and more than likely additional service desk tickets.

bpavlov
Honored Contributor

Then perhaps you would be more comfortable with the user using Self Service to have the updates installed. It doesn't require admin rights as any Self Service item runs as root.

A policy scoped to all computers that would simply use the Software Update payload (or you could additionally have it run a script calling softwareupdate) may do the trick. I'm actually starting to test this out myself so I can provide more technical details once I'm done.

dwandro92
Contributor III

The script above would be setup as a scheduled task that runs on the SUS to download and enable Gatekeeper and XProtect updates, so that you don't have to manually download them and enable them yourself. In other words, you would still have to download and enable other updates on your SUS as usual, but these types of updates would be handled in an automated fashion. By doing this, you wouldn't have to point the clients to the Apple catalogs at all, which would simplify the client-side automation quite a bit.

On the client-side, you could then enable the settings you stated above and install updates programatically as follows (not tested):

#!/bin/bash

# Turn on automatic updates
softwareupdate --schedule on

# Enable configuration updates
defaults write /Library/Preferences/com.apple.SoftwareUpdate ConfigDataInstall -bool TRUE

# Disable critical updates
defaults write /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstall -bool FALSE

# Install updates
softwareupdate --background-critical 

# Disable automatic updates
softwareupdate --schedule off

If your reason for using the Apple catalogs is that the systems are off the network and do not have access to the SUS, you would need to do the following:

  1. If using a config profile to manage your SUS catalog URL, remove the profile. You can use profiles -R -p <Config Profile UUID> to do this in a script.

  2. Set the Apple Catalog URL using the code proposed at the bottom of this comment.

  3. Install updates using the code proposed at the top of this comment.

  4. Re-apply your SUS settings by re-installing your config profile via profiles -I -F - <Config Profile Contents> or by using defaults write "/Library/Preferences/com.apple.SoftwareUpdate.plist" CatalogURL <SUS URL>

Code for setting Apple Catalog URL:

#!/bin/bash

# Set path to config file
configFile="/Library/Preferences/com.apple.SoftwareUpdate.plist"

# Get OS version
osVersion=`defaults read /System/Library/CoreServices/SystemVersion ProductVersion | awk -F "." '{ print $1"."$2 }'`

# Get OS minor version
osMinorVersion=`defaults read /System/Library/CoreServices/SystemVersion ProductVersion | awk -F "." '{ print $2 }'`

# Examine OS version
case $osMinorVersion in
    # Set catalog name for OS X Lion
    7) catalogName="index-lion-snowleopard-leopard";;
    # Set catalog name for OS X Mt. Lion
    8) catalogName="index-mountainlion-lion-snowleopard-leopard";;
    # Set catalog name for OS X Mavericks
    9) catalogName="index-10.9-mountainlion-lion-snowleopard-leopard";;
    # Set catalog name for OS X Yosemite
    10) catalogName="index-10.10-10.9-mountainlion-lion-snowleopard-leopard";;
    # Set catalog name for OS X El Capitain
    11) catalogName="index-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard";;
    # Do not set a catalog name for any other version of OS X
    *) echo "Unable to determine catalog path for ${osVersion}.";;
esac

# If catalog name is set
if [ -n "$catalogName" ]; then
    # Set full catalog URL
    catalogURL="http://swscan.apple.com/content/catalogs/others/${catalogName}.merged-1.sucatalog"

    # Write full path to catalog URL
    defaults write "$configFile" CatalogURL "$catalogURL"

    # Output catalog URL
    echo "Software Update Catalog was set to $catalogURL..."
fi

Please let me know if you have any questions.

May
Contributor III

Thanks for your suggestion @bpavlov , it would be beneficial to add updates to self service to supplement our updates schedule, though at the moment it would require more time than is available to configure, test and document, that's in the "to do when we're bored" list!

and thank you @dwandro92 , i think your solution could do what we need, thanks for sharing the script also, very handy, I'm looking forward to testing it out tomorrow!