Software Update Script

hkim
Contributor II

I've been playing with some more robust ways to run softwareupdate than the built in implementation in Casper and came up with this. Modify as you like to make it work for your environment, it currently only works with 10.8 because 10.7 uses a slightly different structure for index.plist (and I just didn't have time to modify for it). Basically it checks if you are on 10.8, then if you have any updates, and if you do and they requires a restart, download them all and modify the proper files so that when someone does go to Apple - Restart, it'll bring up the built in Apple environment to show them a pretty progress bar on how their updates are going, and if there are updates but none of them require a restart, install them silently. This can be used in conjunction with a Policy so that you can warn users that it's running, that if it finds updates that require restart that it'll install those updates when they restart the computer, etc. etc. etc.

Enjoy!

#!/bin/bash SWUL=/usr/sbin/softwareupdate -l | /usr/bin/awk '{printf "%s", $0}' SWULER=/usr/sbin/softwareupdate -l 2>&1 | /usr/bin/head -1 NoRestartUpdates=/usr/sbin/softwareupdate -l | /usr/bin/grep -v restart | /usr/bin/grep -B1 recommended | /usr/bin/grep -v recommended | /usr/bin/awk '{print $2}' | /usr/bin/awk '{printf "%s ", $0}' osvers=sw_vers -productVersion | awk -F. '{print $2}' if [[ $osvers -eq 7 ]]; then /bin/echo "Script only for 10.8 ONLY" exit 1 elif [ "$SWULER" == "No new software available." ]; then /bin/echo "$SWULER" exit 1 elif [[ "$SWUL" == *"[restart]"* ]]; then echo "Installing Updates that require Restart" /usr/bin/sudo /usr/sbin/softwareupdate -d -a /usr/libexec/PListBuddy -c "Copy CompletedProducts InstallAtLogout" /Library/Updates/index.plist /usr/bin/touch /var/db/.SoftwareUpdateAtLogout /bin/chmod og-r /var/db/.SoftwareUpdateAtLogout /usr/libexec/PListBuddy -c "Add -RootInstallMode STRING YES" /var/db/.SoftwareUpdateOptions /usr/libexec/PListBuddy -c "Add -SkipConfirm STRING YES" /var/db/.SoftwareUpdateOptions /bin/chmod og-r /var/db/.SoftwareUpdateOptions elif [[ "$SWUL" == *"[recommended]"* ]]; then /bin/echo "Installing Updates that does not require Restart" /usr/bin/sudo /usr/sbin/softwareupdate -i $NoRestartUpdates fi exit 0
30 REPLIES 30

agirardi
New Contributor II

Awesome work! We have not been 100% satisfied with our update policies, and had some issues recently. I will give this a shot in our environment. Thanks for sharing.

Chris_Hafner
Valued Contributor II

This looks great! I'll be checking it out this morning. Very well thought out!

rderewianko
Valued Contributor II

Beautiful script! Thanks

Kumarasinghe
Valued Contributor

Thanks.

I had this URL not found issue reported but installed updates as you described. Excellent script.

softwareupdate[1889]: No alternate URLs found for packageId amds
App Store[688]: No alternate URLs found for packageId amds

Have you seen this before?

hkim
Contributor II

I need to give credit where credit is due. After reading http://managingosx.wordpress.com/2009/10/12/apple-software-update-options/ and talking with Greg briefly, and given my really limited (i.e. none) ability in Python but trying to read Munki code (which is very readable without Python knowledge by the way) gave me the inspiration of what you see above. The article above does give a way to do it in 10.6 (and maybe in 10.7) but I wanted to use PlistBuddy (which I realize I did misspell in the script, gotta love HFS+ for ignoring case in this case I guess) instead of defaults because technically it's not a Apple preferences I was modifying (trying to be a good doobie about "proper" procedures when it comes to Plist editing)

installarray=defaults read /Library/Updates/index ProductPaths | grep -v "[{}]" | awk -F "=" '{print $1}' | grep -o "[^" ]+"
defaults write /Library/Updates/index InstallAtLogout -array "$installarray"

As this evolves, I'll think about putting something together in GitHub. I just hope this helps others who want to keep machines up to date silently, but aren't happy with the built in Apple softwareupdate command on it's own.

I also want to stress that this script should probably be used in environments where you can control what updates get installed since it's going to install all of them from whatever URL is set on that computer to look for updates. Last thing you'd want is Apple pushing an update, you pushing it out to your users, and then having that update be faulty, history tells us this happens more often than it should.

hkim
Contributor II

@Kumarasinghe yes I have seen that in my environment, but since I'm using this as a silent updater for my users, and the end results does the job intended, I didn't really look into why that's happening, nor at this time do I care.

jwojda
Valued Contributor II

this was the result when I ran the script on a test box...

Script result: Installing Updates that require Restart
Software Update Tool
Copyright 2002-2010 Apple


Done.
Packages have been saved to /Library/Updates
Copy: Entry, "CompletedProducts", Does Not Exist
File Doesn't Exist, Will Create: /var/db/.SoftwareUpdateOptions
Unmounting file server...
Running Recon...
Locating mobile device records...

gregneagle
Valued Contributor
softwareupdate[1889]: No alternate URLs found for packageId amds App Store[688]: No alternate URLs found for packageId amds Have you seen this before?

Yes. It has nothing to do with the script; you'd see it if you ran /usr/sbin/softwareupdate manually as well.

jwojda
Valued Contributor II

I ran it on a box last night... when I asked the user if anything unexpected happened when they powered off for the night, they said their system went to a grey screen and sat there. He let it set for about 5minutes and finally powered it off.

hkim
Contributor II

@jwojda - check the files that are being modified by the script, check on the box what softwareupdate -l returns, check if index.plist is being changed properly to reflect what was downloaded versus what was listed as available updates. It looks like initially it found updates that require restart under softwareupdate -l, but when you ran softwareupdate -d -a it didn't find anything to install.

Again, modify it to suit your needs, if you don't want to auto install updates that require restarts, you could comment out those lines.

jwojda
Valued Contributor II

I'm okay with auto-installing updates that require restarts...

Maybe it is working as expected...this is the results of things you said to check. I guess that I was expecting the progress bar to show and that's what never did... I will do s'more testing.

sudo softwareupdate -l
Password:
Software Update Tool
Copyright 2002-2010 Apple

Software Update found the following new or updated software:
   * MacBookProRetinaSMCUpdate1.1-1.1
    MacBook Pro Retina SMC Update (1.1), 165K [recommended] [restart]
   * AirPortUtility-6.3.1
    AirPort Utility (6.3.1), 21104K [recommended]
ls
041-9657        ProductMetadata.plist
091-7170        index.plist
nano index.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs$
<plist version="1.0">
<dict>
        <key>CompleteProducts</key>
        <array>
                <string>041-9657</string>
                <string>091-7170</string>
        </array>
        <key>InstallAtLogout</key>
        <array>
                <string>041-9657</string>
                <string>091-7170</string>
        </array>
        <key>ProductPaths</key>
        <dict>
                <key>041-9657</key>
                <string>041-9657</string>
                <key>091-7170</key>

jwojda
Valued Contributor II

I'm okay with auto-installing updates that require restarts...

Maybe it is working as expected...this is the results of things you said to check. I guess that I was expecting the progress bar to show and that's what never did... I will do s'more testing.

sudo softwareupdate -l
Password:
Software Update Tool
Copyright 2002-2010 Apple

Software Update found the following new or updated software:
   * MacBookProRetinaSMCUpdate1.1-1.1
    MacBook Pro Retina SMC Update (1.1), 165K [recommended] [restart]
   * AirPortUtility-6.3.1
    AirPort Utility (6.3.1), 21104K [recommended]
ls
041-9657        ProductMetadata.plist
091-7170        index.plist
nano index.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs$
<plist version="1.0">
<dict>
        <key>CompleteProducts</key>
        <array>
                <string>041-9657</string>
                <string>091-7170</string>
        </array>
        <key>InstallAtLogout</key>
        <array>
                <string>041-9657</string>
                <string>091-7170</string>
        </array>
        <key>ProductPaths</key>
        <dict>
                <key>041-9657</key>
                <string>041-9657</string>
                <key>091-7170</key>

hkim
Contributor II

I wonder if the SMC firmware updates install differently than other updates, and if the script just doesn't work with those. Haven't run across a computer needing firmware updates but thanks for the feedback, I appreciate it.

Josh_S
Contributor III

I have noticed that many firmware updates will not install unless a laptop is using the power adaptor, versus running on the battery. If you attempt to install the updates via the command line, it will reboot but will not actually install the update. I haven't seen any just hang indefinitely at a grey screen though.

jwojda
Valued Contributor II

It may have been the firmware updates. I just built a machine using an 10.8.3 image, but the machine already had all the firmware updates. it downloaded everything, installed the non-restart updates, and when I shut down it went to a grey screen for about 1-2 seconds then switched to teh apple progress bar..

hkim
Contributor II

Firmware updates might be handled differently that other requires restart updates, since I'm manually triggering the Software Update loginwindow using the SoftwareUpdateAtLogout and SoftwareUpdateOptions, there might be either different options, or different mechanisms that need to be called for that to work properly.

Again thanks for the feedback, it's good food for thought for me to investigate later if I can get my hands on a machine that needs said update (kinda hard to test something that only happens once after all)

mm2270
Legendary Contributor III

Personally I don't know that I'd want to install any Firmware updates on our Macs in an automated way anyhow. We keep those blocked on our SUS for clients for the most part and feed those out in a manual way once they've been through enough testing. So it may be good that it doesn't really handle those type of updates.

Kumarasinghe
Valued Contributor

@hkim
Thanks Han. Please post here if you have made any improvements/logic to the original script.

Kumarasinghe
Valued Contributor

@hkim
Have you tested the script for OS X 10.9?
It doesn't seem to work with OS X 10.9.

Thanks

UESCDurandal
Contributor II

@hkim I really like your approach to software updates. I decided to try your script on 10.9.2 and have found that it does succeed in caching the packages and install them at logout. However, it is producing this error:

May 13 10:43:00 computer_name softwareupdate CLI[1220] : /usr/sbin/softwareupdate: XPC error in __60-[SUCommandLineTool _runSessionWithUpdates:skippingInstall:]_block_invoke (Error Domain=NSCocoaErrorDomain Code=4099 "Couldn’t communicate with a helper application." (The connection was invalidated from this process.) UserInfo=0x7ff5a1c12f90 {NSDebugDescription=The connection was invalidated from this process.})

Any thoughts on this?

chop
New Contributor

Just to chime in and say @UESCDurandal that I too have this error pretty much word for word.
I wonder if the action is trying to spawn the GUI dialog to prompt for a restart, but is being interrupted through the use of the script or JAMF policy...

I am using 10.9.3 with V.8.73 of the JSS.

calumhunter
Valued Contributor

I'd have a look at loceee's patchoo scripts, they handle apple softwareupdates very nicely including different catalogs for different OS versions

alexjdale
Valued Contributor III

We have our own custom patching script (reads in a list of updates we've "blessed" and downloads/installs only those with some CocoaDialog UI elements for user interaction/deferral and a restart timer), but I am definitely going to steal some bits of your script. I like the "install on logout" bit mainly, I would much rather use the native Software Update interface.

Chris
Valued Contributor

Is anyone using this method with Mavericks?
For me, it seems to work only on every 2nd boot, it's like:

- Run script, everything looks fine, reboot -> nothing happens. Install.log says

Software Update.app (0)[1595]: Software Update.app: None of the keys registered for post-logout install () are available

- Run script again, everything looks like the first time, reboot -> Updates are being installed. Install.log:

Software Update.app (0)[989]: Software Update.app: Starting post-logout install of 031-04361 ... ...

Just wondering which "keys" it refers to in the error message...

msimpson
New Contributor

This script works very well. Nice transparent install in the background, or on restart with standard Apple GUI.

Appears to work on 10.8, 10.9 and also tested on a single 10.10 machine.

jthurwood
New Contributor III

@UESCDurandal @chop I am too getting the same error you were getting when installing updates. Did you manage to find a fix for this?

Chris
Valued Contributor

I've revisited this regarding the

Software Update.app (0)[1595]: Software Update.app: None of the keys registered for post-logout install () are available

error i mentioned above.
Turns out that kickstarting softwareupdated makes it work for me on Mavericks and Yosemite.
I've added

launchctl unload /System/Library/LaunchDaemons/com.apple.softwareupdated.plist
launchctl load /System/Library/LaunchDaemons/com.apple.softwareupdated.plist

to the end of the script.

tcandela
Valued Contributor II

msimpson - did you implement this script without making any changes to it when testing on 10.8, 10.9 and 10.10 ?

sunny_s
New Contributor II

msimpson's script was implemented as a run-on-demand from Self Service. Limitations placed on the script to only allow running 10.8.x, 10.9.x, 10.10.x

A slight modification was made to the script at the beginning for removal of our internal update server plist we added to earlier mac builds.
Another difference is slight formatting and use of "`" - probably because the original script was posted as a quote and not script, perhaps breaking the script? HTML does funny things to scripts if not properly attached to a forum post. It breaks.

Below is verbatim what we use.

#!/bin/bash

## Remove swupdate preferences to use default server
jamf removeSWUSettings
rm /Library/Preferences/com.apple.SoftwareUpdate.plist
rm /Library/Managed Preferences/com.apple.SoftwareUpdate.plist
##

SWUL=`/usr/sbin/softwareupdate -l | /usr/bin/awk '{printf "%s", $0}'`
SWULER=`/usr/sbin/softwareupdate -l 2>&1 | /usr/bin/head -1`
NoRestartUpdates=`/usr/sbin/softwareupdate -l | /usr/bin/grep -v restart | /usr/bin/grep -B1 recommended | /usr/bin/grep -v recommended | /usr/bin/awk '{print $2}' | /usr/bin/awk '{printf "%s ", $0}'`
osvers=`sw_vers -productVersion | awk -F. '{print $2}'`

if [[ $osvers -eq 7 ]]; then
/bin/echo "Script only for 10.8 ONLY"
exit 1
elif [ "$SWULER" == "No new software available." ]; then
/bin/echo "$SWULER"
exit 1
elif [[ "$SWUL" == *"[restart]"* ]]; then
echo "Installing Updates that require Restart"
/usr/bin/sudo /usr/sbin/softwareupdate -d -a
/usr/libexec/PListBuddy -c "Copy CompletedProducts InstallAtLogout" /Library/Updates/index.plist
/usr/bin/touch /var/db/.SoftwareUpdateAtLogout
/bin/chmod og-r /var/db/.SoftwareUpdateAtLogout
/usr/libexec/PListBuddy -c "Add -RootInstallMode STRING YES" /var/db/.SoftwareUpdateOptions
/usr/libexec/PListBuddy -c "Add -SkipConfirm STRING YES" /var/db/.SoftwareUpdateOptions
/bin/chmod og-r /var/db/.SoftwareUpdateOptions
elif [[ "$SWUL" == *"[recommended]"* ]]; then
/bin/echo "Installing Updates that does not require Restart"
/usr/bin/sudo /usr/sbin/softwareupdate -i $NoRestartUpdates
fi

exit 0

Iranoma
New Contributor

This is a fantastic approach, and I really appreciate you sharing this innovative solution for managing software updates more efficiently. Your script is a clever workaround that significantly enhances the update process on OS X 10.8, making it more seamless for users and administrators alike. Great job!