Skip to main content
Jamf Nation, hosted by Jamf, is a knowledgeable community of Apple-focused admins and Jamf users. Join us in person at the ninth annual Jamf Nation User Conference (JNUC) this November for three days of learning, laughter and IT love.

How to update Chrome automatically

I have just written a blog post on how to automatically update Google Chrome using Jamf if anyone is interested. You can find my blog post here:

https://lew.im/2017/03/auto-update-chrome/

I have seen a few different methods posted here, but most require some admin intervention (uploading new packages, changing version numbers etc.) but this method is fully automated. Create the Extension Attribute, Smart Group and Policy and you're good to go! Every time Google release a new version of Chrome, this script will automatically grab it and install it on your Macs.

Like Comment
Order by:
SOLVED Posted: by bpavlov

I haven't implemented this, but just reading through the script, it looks like you are literally overwriting the Google Chrome.app on the client already. In my experience having done this with a package in the past, this has the effect of causing issues when new tabs are opened and not being able to navigate to new websites. So in essence if you want to do this, you need to make sure Google Chrome is not opened otherwise the user may run into that issue. Again, I haven't tested your workflow so I'm going off what I'm reading in that script. Curious to hear how long you've been using this workflow and what your experience has been from the end-user side.

Like
SOLVED Posted: by LewisLebentz

We have been using this method (less the automated version part) for around a year now, and haven't had any issues. With a few hundred Macs reporting in, I'd probably have heard a complaint or two if it was causing issues with new tabs!

I tested it when we initially deployed it and all seemed fine, but Chrome has changed a lot since then, so I'll do some further testing when I'm back in the office and will update you.

Like
SOLVED Posted: by LewisLebentz

@bpavlov just did some further testing, ran the script a few times deleting Chrome whilst using it, open new tabs, browsing etc. and didn't notice anything whatsoever.

So can confirm there is still no noticeable effect for the end user if you run this.

Like
SOLVED Posted: by RobertBasil

Saw your post on Reddit about this script. Going to install it today and give it a run.

Thanks for sharing.

Like
SOLVED Posted: by mm2270

@LewisLebentz Thanks for your post, and showing your work. If nothing else, you pointed me to a resource I was previously unaware of. I'm not sure who developed or maintains the omahaproxy pages, but I looked it up to see more on it. It doesn't appear to be something Google maintains, but I'm not completely sure on that.

In any event, I've been looking for a more reliable way to get the Google Chrome current release number, since it seems Google obscurs it to the point of being impossible to get. I also have an "update" script that can update several products on the fly, doing live version checking, and incorporating Google Chrome into it has been a bear, because it was such a moving target to locate the latest version.

I found the team at omahaproxy have a simple plain csv file they host as well and was able to come up with the following very simple bash code to pull the current Mac version release from that. Posting it here so others can benefit.

curl -s https://omahaproxy.appspot.com/history | awk -F',' '/mac,stable/{print $3; exit}'

The above prints

56.0.2924.87

which is the current version. I'll need to see if that still works when they release an update.
Hopefully those pages won't up and disappear someday, or go stale from lack of maintenance.

Like
SOLVED Posted: by mm2270

LOL! No sooner did I post the above and Google released an update. Didn't need to wait long! The code above (and I assume your python EA as well) is working to show the new version, 57.0.2987.98, which means those pages get updated simultaneously along with new releases. Wow! Impressive!

Like
SOLVED Posted: by LewisLebentz

@mm2270 just noticed the update too! Most of my Macs have already picked up the update because of the script, which is great!

I believe the OmahaProxy site is officially Google, I've seen it referred to in a few different places by Google. So I think it's safe to rely on, it's been around for a while too.

Just found some code that references it on Google's site: https://chromium.googlesource.com/chromium/chromium/+/trunk/tools/omahaproxy.py

Script is pretty similar to mine!

Thanks for sharing your code too. Much shorter than mine! Need to learn how to use awk at some point.

I did notice that Jamf haven't yet updated their patch reporting, so our pie chart is all red saying that the version number is 'Other' and in the list it reports it as 'Unknown' which isn't great.

Like
SOLVED Posted: by cbrewer

Why use this work flow over Google's own system wide automatic updater? Especially when it can be enabled with a script.

Like
SOLVED Posted: by LewisLebentz

@cbrewer ours users are all admins, so can override settings we push out. Even if they don't they may not restart Chrome.

This script forces an update on check in, without the user even noticing. It runs in the background, and doesn't require a restart of Chrome.

Like
SOLVED Posted: by rayabril

So with @mm2270 new script, what should final Extension Attribute code look like? Sorry i'm new to this and pretty green when it comes to coding.

Like
SOLVED Posted: by bpavlov

@cbrewer what's the script you're referring to use the internal update tool from Google?

Like
SOLVED Posted: by cdenoia

Hey @LewisLebentz

Excellent post!

Like
SOLVED Posted: by May

Thanks ! @LewisLebentz @mm2270

What a time saver! i've seen no issues using it whilst Chrome is open,
it will also install the latest Chrome if it's not installed, here's the EA i'm using to report,

#!/bin/sh

if [ ! -f "/Applications/Google Chrome.app/Contents/Info.plist" ] ; then
echo "<result>Chrome isn't installed</result>"
exit 0
fi

INSTALLEDVERSION=$( defaults read "/Applications/Google Chrome.app/Contents/Info.plist" CFBundleShortVersionString )
CURRENTVERSION=$( curl -s https://omahaproxy.appspot.com/history | awk -F',' '/mac,stable/{print $3; exit}' )

if [[ "$INSTALLEDVERSION" == "$CURRENTVERSION" ]]; then

echo "<result>latest - $CURRENTVERSION</result>"

else

echo "<result>old</result>"

fi
Like
SOLVED Posted: by Kyuubi

@mm2270 @LewisLebentz pardon my ignorance but I would love to get this working at my site. I saw the curl command that @mm2270 put above and i saw it incorporated into the EA that @May wrote. What I don't understand is how that curl command pulls down the latest version and installs it. What am I missing.

Thanks,

Like
SOLVED Posted: by mm2270

@Kyuubi The script above from @May is an Extension Attribute, not the script that updates Chrome. The EA is part of the whole workflow put together by @LewisLebentz in his original post up top. You would use an EA similar, or identical to the one May posted above to gather Macs that are out of date according to what is noted on the omahaproxy pages for the latest Chrome version. This can then be used to gather out of date Macs in a Smart Group, which can in turn be scoped to the policy that would update them. Refer to Lewis' OP at top for his script that updates Chrome. There are others posted on the forums here as well. Essentially any script that would pull Google Chrome down, mount the DMG, copy over the app (overwriting the old one) and so on and so forth.

Hope that helps.

Like
SOLVED Posted: by Kyuubi

@mm2270 Thanks for the response. I understand all you wrote above, I'm just having trouble finding the actual script that does the pulling and installing. I've checked @LewisLebentz blog and github pages but can't find the script. Making me feel stupid.

Like
SOLVED Posted: by Kyuubi

.......found it

Like
SOLVED Posted: by mm2270

@Kyuubi OK, good! Was just about to post a more direct link to the script if I could for you. :)

Like
SOLVED Posted: by ryan.ball

I actually incorporate the chrome_enable_autoupdates.py as a postinstall in my AutoPKG Chrome recipe now and this seems to be working well.

Like
SOLVED Posted: by tld75000

@LewisLebentz Not working for me, maybe missing a step or something. When Lewis says " I made a Smart Group targeting all Macs where Chrome Version = Old" how does that translate into the Smart Group, how do you create it.
Thanks

Like
SOLVED Posted: by JeffA

@LewisLebentz Any update on creating the Smart Group? This would be great to implement but I am in the position as @tld75000. How do you create a Smart Group with the Criteria of "Chrome = Old"? Any help would be appreciated. Thanks.

Like
SOLVED Posted: by tep

@JeffA you can do a smart group with the criteria "Chrome like old"

Like
SOLVED Posted: by mackjohn

The windows pop up message when the new version of chrome launch. I don't think so you need to go for automatic chrome update.

Like
SOLVED Posted: by Andy_W

@JeffA You've probably figured this out already. For anyone who creates the Extension Attribute, you would create a Smart Group and there will be a "New Criteria" with whatever you named the EA. For example, I named mine Chrome Version, so I have a new criteria option called Chrome Version, then I just use the value is "old".

Like
SOLVED Posted: by rhooper

I still cannot get the Chrome Version Smart group to post any devices.
Added the EA script. and then created the smart group with Version = Old. Still nothing there after 1 hr. Any help or direction is appreciated.

The actual Chrome updater script works awesome! Thank you.

Like
SOLVED Posted: by merps

@rhooper EAs update when device inventory updates - during a jamf recon. From what I understand, most environments will run recon daily or once a week.

I'd take a system, do a manual recon, and then check the computer record in the category you used for the EA. This will help you verify whether the EA is working for you. You also may need to use a lowercase "o" in Version = old.

Like
SOLVED Posted: by rhooper

@merps OH yeay, the ol' Recon weekly thing.
Thanks for the reminder.
I wonder, can I use a recon policy to push and receive more devices? so far only 2 show.....

Problems logging into JAMF Pro right now... errors galore!

Like
SOLVED Posted: by vvujcic

This great @LewisLebentz . Thanks for sharing! I added an extra if/else in the original EA script to also detect/output if Chrome is not installed all together similar to @May

#!/usr/bin/python
import json
import urllib2
import os.path
import plistlib

url = 'http://omahaproxy.appspot.com/all.json'
resp = urllib2.urlopen(url)


data = json.loads(resp.read())

for each in data:
    if each.get("os") == "mac":
        versions = each.get("versions")
        for version in versions:
            if version.get("channel") == "stable":
                latest = (version.get("current_version"))
                print latest

chromeExists = os.path.exists("/Applications/Google Chrome.app")

print chromeExists

if chromeExists:

    plistloc = "/Applications/Google Chrome.app/Contents/Info.plist"

    pl = plistlib.readPlist(plistloc)
    pver = pl["CFBundleShortVersionString"]
    print pver

    if latest == pver:
            print "<result>Latest</result>"

    else:
            print "<result>Old</result>"

else:
    print "<result>NotInstalled</result>"

Fairly new to python and JAMF so any criticisms are more than welcome. Thanks!

Like
SOLVED Posted: by josh.perlman

Thanks for this info @LewisLebentz! One thing I minor edge case that could be a security problem is your script installs /Volumes/Google Chrome/Google Chrome.app regardless of if that path already exists or not.

I added the following prior to the rest of your install script:

if [ -d "/Volumes/Google Chrome" ]; then
  /bin/echo "`date`: Chrome image already mounted" >> ${logfile}
  exit 1
fi
Like
SOLVED Posted: by brunerd

Since updating Chrome is in the news these days, making sure AutoUpdates are on brought me here...

Google's Manage Chrome updates (Mac) page totally underplays what's needed saying you just need to set a key:

We recommend that you keep auto-updates turned on so your users receive critical security fixes and new features as they become available. Open the com.google.Keystone.plist file in your preferred XML editor. Under the updatePolicies key, add the Chrome Browser UpdateDefault key entry, and set the key value to 0. The following example shows settings for Chrome Browser (com.google.Chrome) that turns on auto-updates: <key>updatePolicies</key> <dict> <key>global</key> <dict> <key>UpdateDefault</key> <integer>0</integer> </dict> </dict> Save your changes.

Which is annoying for two reasons: 1) It's assuming you have the Keystone daemon running and 2) Their snippet leads to authoring errors, in some other thread it's in a plist but not properly formatted, you have to have the whole thing enclosed in a dictionary like so...

<?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>updatePolicies</key>
    <dict>
      <key>global</key>
      <dict>
        <key>UpdateDefault</key>
        <integer>0</integer>
      </dict>
    </dict>
</dict>
</plist>

Which is still useless from my testing, even if this plist is deployed to the domain com.google.Keystone as a Config Profile, and you make sure Google Software Updates is installed it will STILL ask the end user to enable updates... and auth as an admin.

I took the Python script found in this thread: Auto update Google Chrome script? and BASH-ified it, streamlined it taking out keyname variables and such and added in a couple script that get run when the button is manually clicked in Chrome and I have this:

#!/bin/sh
#Joel Bruner

#specify a custom path in parameter $4 or just take the default
appPath="${4:-/Applications/Google Chrome.app}"

#no exist? exit.
[ ! -e "${appPath}/Contents/Info.plist" ] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework/Resources/ksinstall" --install "${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2

Use it in good health!

Like
SOLVED Posted: by G.M.

@brunerd Your script worked well for me!! Greatly appreciated!!

Like
SOLVED Posted: by piagetblix

@LewisLebentz Instead of creating the EA, couldn't you have your smart groups (one for up to date and another for out of date) use Criteria: patch reporting, Google Chrome.

Like
SOLVED Posted: by chris.kemp

@piagetblix I was just looking at this today, but unfortunately the "Latest Version" seems unreliable - Patch Reporting says that 80% of our fleet is on the current version, but Smart Groups flagged more than this as "Is not" "Latest Version"...

Like
SOLVED Posted: by larry_barrett

Keep in mind there needs to be a recon before everything is accurate. Once all the devices check in you'll have a clearer picture. If you do not have todays inventory you don't have the full picture.

Like
SOLVED Posted: by msw-sa

I've been using the python script @brunerd linked for years to enable auto-updates after installing the latest version of Chrome during imaging. It's been working flawlessly for ages. I was just testing something unrelated this morning and saw that when I launched Chrome on a freshly-imaged device, I got the 'Google Chrome may not be able to keep itself updated' banner. Likewise if I go to Settings > About, I get a warning "Google Chrome may not be able to keep itself updated"

I found this thread on the topic. The relevant portion from @gzilla13 is here:

The problem has to do with GoogleSoftrwareUpdate. In newer versions of Google Chrome, GoogleSoftwareUpdate is not downloaded until Chrome has been launched once. On first launch, Chrome will install GoogleSoftwareUpdate in the current user's Library. This causes the prompt if the app is not owned by that user. Changing ownership of Google Chrome to the user will only fix the problem for that user. If anyone else logs in, the prompt will appear again. When you click "Set up automatic updates" from that prompt. The system will move GoogleSoftwareUpdate to the /Library/Google folder and remove it from the current user's Library, it will also update and create all relevant LaunchAgents and Daemons to point to GoogleSoftwareUpdate in /Library/Google.

He later says in the same thread that the Auto Update python script solved the problem for him but I'm still having it. Just in case, I tried brunerd's script since I'm more familiar with bash, and still have the same issue. There appear to be two problems:

  • there's no /Applications/Google Chrome.app/Contents/Versions folder (Chrome version 75.0.3770.80)
  • Because the Version folder isn't there, the keystone scripts aren't present, and (maybe as a result) there isn't a /Library/Google folder, just a ~/Library/Google folder

Can't quite figure out what's broken here. Anyone else running into similar issues?

Like
SOLVED Posted: by psliequ

I've always had very good success packaging Chrome and its auto update components.

Packaging;

/Applications/Google Chrome.app
/Library/Google/
/Library/LaunchDaemons/com.google.keystone.daemon.plist
/Library/LaunchAgents/com.google.keystone.agent.plist
/Library/LaunchAgents/com.google.keystone.xpcservice.plist

does the trick.
You could add a post install script to load the daemons and agents in the current session or just wait for the next reboot for them to be loaded.

Like
SOLVED Posted: by msw-sa

I'm installing Chrome with a script like this:

#!/bin/sh

echo "Installing the current stable version of Google Chrome..."
echo "Downloading..."
curl -k --silent --retry 3 --retry-max-time 6 --fail https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg --output /googlechrome.dmg

echo "Mounting DMG..."
hdiutil attach -quiet -nobrowse /googlechrome.dmg -mountpoint /Volumes/GC/

echo "Installing..."
cp -r /Volumes/GC/Google\ Chrome.app/ /Applications/Google\ Chrome.app/

echo "Cleaning up..."
hdiutil detach /Volumes/GC/
rm -rf /googlechrome.dmg

chrome_version=`defaults read /Applications/Google\ Chrome.app/Contents/Info CFBundleShortVersionString`
echo "Chrome $chrome_version installed..."

A computer I imaged about a week ago with Chrome 74.0.3729.169 installed with auto-updates enabled, and no user gets the 'enable automatic updates?' prompt on first launch. In /Applications/Google Chrome.app/Contents/, the expected Versions folder is there.

Today, I am getting Chrome 75.0.3770.80, and there isn't a Versions folder in the app bundle, so none of keystone/auto-update scripts are present. Did Google change something about the app architecture? Just to confirm I wasn't losing my mind, I re-downloaded the dmg from https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg and from https://www.google.com/chrome/ — in both cases, the .app bundle in the dmg doesn't contain /Contents/Versions.

So...I guess I've identified the problem but I have no idea what to do about it.

Like
SOLVED Posted: by ekrizon

I'm in the same boat, we use the install latest version script and the enable auto-updates.py and am seeing the same issue.

Like
SOLVED Posted: by ryan.ball

@msw-sa and @ekrizon I have a PR in with hjuutilainen that will fix it.

See my fork here:
https://github.com/ryangball/adminscripts/blob/master/chrome-enable-autoupdates.py

I would only use mine temporarily, as he might merge my changes into his.

Like
SOLVED Posted: by ryan.ball

Okay my changes are merged into the original and I've deleted my fork, so the updated script that will work for versions above and below Chrome 75 is here:
https://github.com/hjuutilainen/adminscripts/blob/master/chrome-enable-autoupdates.py

Like
SOLVED Posted: by msw-sa

huge thanks @ryan.ball — much appreciated! i've confirmed this script works in my environment.

Like
SOLVED Posted: by CorpIT_eB

Hello Jamf Nation,

I am getting the following Error when Google try's to update:

Script result: /Library/Application Support/JAMF/tmp/Update Google Chrome: line 15: /Applications/Google Chrome.app/Contents/Versions/75.0.3770.80/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework/Resources/ksinstall: No such file or directory

Does anyone know if Google has changed anything on there end?

#!/bin/sh
#specify a custom path in parameter $4 or just take the default
appPath="${4:-/Applications/Google Chrome.app}"

#no exist? exit.
[ ! -e "${appPath}/Contents/Info.plist" ] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework/Resources/ksinstall" --install "${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2

This was working and updating Google flawlessly till today.

Like
SOLVED Posted: by sdagley

@CorpIT_eB It does appear Google has borked something with version 75.0.3770.80. The script is using the version number in the path to call ksinstall, but on my Mac if I look in /Applications/Google Chrome/Contents/Versions/ there is no directory named 75.0.3770.80, just one named 74.0.3729.169.

Like
SOLVED Posted: by CorpIT_eB

@sdagley Lovely!

Let't see how else I can fix this now, with Catalina around the corner I don't want to start adding Python scripts in the mix.

Keep in mind I install using another policy with this:

dmgfile="googlechrome.dmg"
volname="Google Chrome"
logfile="/Library/Logs/GoogleChromeInstallScript.log"

url='https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg'

# Are we running on Intel?
if [ '`/usr/bin/uname -p`'="i386" -o '`/usr/bin/uname -p`'="x86_64" ]; then
        /bin/echo "--" >> ${logfile}
        /bin/echo "`date`: Downloading latest version." >> ${logfile}
        /usr/bin/curl -s -o /tmp/${dmgfile} ${url}
        /bin/echo "`date`: Mounting installer disk image." >> ${logfile}
        /usr/bin/hdiutil attach /tmp/${dmgfile} -nobrowse -quiet
        /bin/echo "`date`: Installing..." >> ${logfile}
        ditto -rsrc "/Volumes/${volname}/Google Chrome.app" "/Applications/Google Chrome.app"
        /bin/sleep 10
        /bin/echo "`date`: Unmounting installer disk image." >> ${logfile}
        /usr/bin/hdiutil detach $(/bin/df | /usr/bin/grep "${volname}" | awk '{print $1}') -quiet
        /bin/sleep 10
        /bin/echo "`date`: Deleting disk image." >> ${logfile}
        /bin/rm /tmp/"${dmgfile}"
else
    /bin/echo "`date`: ERROR: This script is for Intel Macs only." >> ${logfile}
fi

exit 0
Like
SOLVED Posted: by msw-sa

@CorpIT_eB all of the items that were in Google Chrome.app/Contents/Versions have been moved and the Versions folder is gone starting with version 75.

Let this section of the python script be your guide

def keystone_registration_framework_path():
    """Returns KeystoneRegistration.framework path"""
    if LooseVersion(chrome_version()) >= LooseVersion("75"):
        keystone_registration = os.path.join(chrome_path, 'Contents/Frameworks/')
        keystone_registration = os.path.join(keystone_registration, 'Google Chrome Framework.framework/Versions')
        keystone_registration = os.path.join(keystone_registration, chrome_version())
        keystone_registration = os.path.join(keystone_registration, 'Frameworks/KeystoneRegistration.framework')
    else:
        keystone_registration = os.path.join(chrome_path, 'Contents/Versions')
        keystone_registration = os.path.join(keystone_registration, chrome_version())
        keystone_registration = os.path.join(keystone_registration, 'Google Chrome Framework.framework')
        keystone_registration = os.path.join(keystone_registration, 'Frameworks/KeystoneRegistration.framework')
    return keystone_registration

The python version is nice, because it has loose version comparison, but you can easily compare versions with bash too. Do a defaults read to get the chrome major version from info.plist, and if 75+, use the path with the /Versions folder, if 74 or below, use the /Frameworks path.

It's Friday afternoon so don't feel like bashing this out myself, but I might do next week. Also, if you don't care about the script to enable auto-updates working on older versions of Chrome than the current one, you don't even need to add version logic, you can just use the Frameworks path instead of the Versions path.

Like
SOLVED Posted: by CorpIT_eB

@msw-sa Just read your post, from yesterday. I might bother you again next week then. I want it to auto update for sure the first time so I don't have to relive updating it again, and trying to really move away from Python in light of Catalina. (Trying to future proof)

So if you wouldn't mind next week I can totally use the Assist. And I appreciate you in advance!

Thanks

Like
SOLVED Posted: by sdagley

@CorpIT_eB I took @msw-sa's explanation of the changes and updated @brunerd's script to accommodate Chrome 75 (here's hoping they don't change back):

#!/bin/bash
#Joel Bruner
#Updated by @sdagley for Chrome 75 changes based on comments by @msw-sa

appPath="${4:-/Applications/Google Chrome.app}"

#no exist? exit.
[ ! -e "${appPath}/Contents/Info.plist" ] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
majorVersion=$(echo "$appVersion" | awk -F. '{ print $1; }')
if [[ $majorVersion -ge 75 ]] ; then
    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
fi

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${frameWorkPath}/Versions/A/Resources/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"${frameWorkPath}/Versions/A/Resources/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2
Like
SOLVED Posted: by CorpIT_eB

@sdagley You're awesome!

I will give this a try and see how it works.

Thanks Again.

Like
SOLVED Posted: by CorpIT_eB

@sdagley I got a 127.

Script exit code: 127
Script result: 2019-06-10 08:58:49.469 ksinstall[39014/0x11c7685c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.agent: return code 3 (3: No such process).
    Standard output:


    Standard error:

2019-06-10 08:58:49.477 ksinstall[39014/0x11c7685c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.xpcservice: return code 3 (3: No such process).
    Standard output:


    Standard error:


Error running script: return code was 127.
Like
SOLVED Posted: by ryan.ball

This would find the largest framework.

frameWorkPath=$(find "$appPath" -name "KeystoneRegistration.framework" | sort | head -1)
Like
SOLVED Posted: by CorpIT_eB

@ryan.ball What Variable would this code replace in the script?

    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
Like
SOLVED Posted: by ryan.ball

Instead of this:

majorVersion=$(echo "$appVersion" | awk -F. '{ print $1; }')
if [[ $majorVersion -ge 75 ]] ; then
    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
fi

You could do this:

frameWorkPath=$(find "$appPath" -name "KeystoneRegistration.framework" | sort | head -1)
Like
SOLVED Posted: by CorpIT_eB

@ryan.ball

#!/bin/sh
appPath="${4:-/Applications/Google Chrome.app}"

#no exist? exit.
[ ! -e "${appPath}/Contents/Info.plist" ] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
frameWorkPath=$(find "$appPath" -name "KeystoneRegistration.framework" | sort | head -1)

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${frameWorkPath}/Versions/A/Resources/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"${frameWorkPath}/Versions/A/Resources/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2

That look about right?

Like
SOLVED Posted: by ryan.ball

Yes. I don't know about the rest of the script's functionality, but that part should work.

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball Same 127 Error.
Script exit code: 127
Script result: 2019-06-10 09:46:11.924 ksinstall[42792/0x11881e5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.agent: return code 3 (3: No such process). Standard output:

Standard error:

2019-06-10 09:46:11.931 ksinstall[42792/0x11881e5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.xpcservice: return code 3 (3: No such process). Standard output:

Standard error:

Error running script: return code was 127.

@msw-sa Any ideas?

Like
SOLVED Posted: by ryan.ball

Running it as root?

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball Should there be a sudo? or su somewhere I don't know about?

Like
SOLVED Posted: by ryan.ball

"${frameWorkPath}/Versions/A/Resources/keystone_promote_preflight.sh" that does not seem to exist. Do you see that in the framework file?

Like
SOLVED Posted: by ryan.ball

It has to run as root.
sudo bash script.sh

Like
SOLVED Posted: by ryan.ball

It is here:
/Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/75.0.3770.80/Resources/keystone_promote_preflight.sh

So instead of A, you need to put the version of the app.

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball I am a tool, can't believe I didn't see that let me fix that syntax and give it shot again.

Thank You,

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball

Script result: 2019-06-10 10:12:42.558 ksinstall[44903/0x1142db5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.agent: return code 3 (3: No such process). Standard output: Standard error:
2019-06-10 10:12:42.888 ksinstall[44903/0x1142db5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.xpcservice: return code 3 (3: No such process). Standard output: Standard error:

Same 127 Error mate.

Like
SOLVED Posted: by sdagley

@ryan.ball Nice trick with the find command but won't the variability with the # of digits in each node of the version number cause problems? Matching the path to the version number of the app bundle is less risky IMO.

Like
SOLVED Posted: by kwiggins

I am very new to JAMF Pro and a lot of what you guys are discussing here is above my head, but I want to try it out. Unfortunately, because of the changes Google made in the product in the middle of the thread, I'm not sure after reading over this what will work and what doesn't. Would anyone be willing to summarize at this point what the approach should be today, post Chrome v. 75?

Like
SOLVED Posted: by CorpIT_eB

@sdagley && @ryan.ball

Even though, I think "find" is much cleaner in terms of coding I am going to stick with @sdagley 's method the problem still lies that it wont Install because It can't seem to find a processes.

So no matter where it's pointing to it never executes. I am guessing Keystones.tbz as its the first --Install request.

Like
SOLVED Posted: by ryan.ball

This worked for me. However, I did get a return code 3 twice, but it did enable auto updates.

#!/bin/bash
appPath="/Applications/Google Chrome.app"

#no exist? exit.
[[ ! -e "${appPath}/Contents/Info.plist" ]] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
frameWorkPath=$(find "$appPath" -name "KeystoneRegistration.framework" | sort | head -1)
preflightPath=$(find "$appPath" -name keystone_promote_preflight.sh | sort | head -1)
postflightPath=$(find "$appPath" -name keystone_promote_postflight.sh | sort | head -1)

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"$preflightPath" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"$postflightPath" "${appPath}" 2>/dev/null 1>&2
Like
SOLVED Posted: by kwiggins

@ryan.ball Are you creating the above as a Script and then running it based on your EA? Just trying to grasp what's going on here.

Like
SOLVED Posted: by ryan.ball

Without the finds you'll also need to restructure the path where the preflight/postflight scripts are like so:

#!/bin/bash
appPath="/Applications/Google Chrome.app"

#no exist? exit.
[[ ! -e "${appPath}/Contents/Info.plist" ]] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
majorVersion=$(echo "$appVersion" | awk -F '.' '{print $1}')
if [[ $majorVersion -ge 75 ]] ; then
    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Resources"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Version/A/Resources"
fi

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${scriptsPath}/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin --register --productid "${productID}" --version "${appVersion}" --xcpath "${appPath}" --url "${updateURL}" --tag-path "${appPath}/Contents/Info.plist" --tag-key "KSChannelID" --brand-path "/Library/Google/Google Chrome Brand.plist" --brand-key "KSBrandID" --version-path "${appPath}/Contents/Info.plist" --version-key "KSVersion"
"${scriptsPath}/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2
Like
SOLVED Posted: by CorpIT_eB

@ryan.ball If we can just figure out what that Code 3 error it's basically stoping the installation of the new version. And showing as "Failed" in JAMF.

Executing Policy Computer Check-in
Running script Update Google Chrome...
Script result: 2019-06-10 10:12:42.558 ksinstall[44903/0x1142db5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.agent: return code 3 (3: No such process). Standard output: Standard error:
2019-06-10 10:12:42.888 ksinstall[44903/0x1142db5c0] [lvl=3] -[KeystoneInstallBackend runImpersonatedLaunchControlWithCommand:asUser:inProcess:] Error impersonating 327506609/96 and running command stop com.google.keystone.user.xpcservice: return code 3 (3: No such process). Standard output: Standard error:
Script exit code: 127
Script result: 
Error running script: return code was 127.
Like
SOLVED Posted: by ryan.ball

I've modified this a bit for easier reading. When I run this (even without suppressing errors on the ksinstall line) I did receive output, but the exit code on the ksinstall line was still 0, not 127. I've suppressed the error here, as that seems to be a false positive related to the --force command, as I receive no output if I leave off the --force from ksinstall.

#!/bin/bash
appPath="/Applications/Google Chrome.app"

#no exist? exit.
[[ ! -e "${appPath}/Contents/Info.plist" ]] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
majorVersion=$(echo "$appVersion" | awk -F '.' '{print $1}')
if [[ $majorVersion -ge 75 ]] ; then
    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Resources"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Version/A/Resources"
fi

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${scriptsPath}/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force 2>/dev/null
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin \
    --register \
    --productid "${productID}" \
    --version "${appVersion}" \
    --xcpath "${appPath}" \
    --url "${updateURL}" \
    --tag-path "${appPath}/Contents/Info.plist" \
    --tag-key "KSChannelID" \
    --brand-path "/Library/Google/Google Chrome Brand.plist" \
    --brand-key "KSBrandID" \
    --version-path "${appPath}/Contents/Info.plist" \
    --version-key "KSVersion"
"${scriptsPath}/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2
Like
SOLVED Posted: by CorpIT_eB

@ryan.ball

Thank You for this very clean, I am still getting 127 on some of my machines when I flush all the errors.

But did get a 0 when I ran it locally on my tester with JAMF Policy command.

Interesting situation we have here with Google Now.

Like
SOLVED Posted: by ryan.ball

Can you check on your devices where it has failed the version of Chrome installed? Above or below 75?

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball These machines are one version below 75 same as my tester version 74.0.3729.169

The way it was before it would install Chrome, then later at Check-In it would run this script to check if it had an older version of chrome uninstall the older version and then install and the new one with automatic updates enabled.

I am wondering if the 127 may be due to the clients being open and in an actively working state on at the time of execution. I was not on my test machine.

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball I just double checked my tester machine and I was wrong it is currently on build 75.0.3370.80 hence why it gave code 0.

So code 127 is coming from the machines on the build prior: 74.0.3729.169 if that helps.

Like
SOLVED Posted: by ryan.ball

Okay, there seemed to have been an oversight in the below 74 path settings. Try this:

#!/bin/bash
appPath="/Applications/Google Chrome.app"

#no exist? exit.
[[ ! -e "${appPath}/Contents/Info.plist" ]] && exit

appVersion=$(defaults read "${appPath}/Contents/Info.plist" CFBundleShortVersionString)
majorVersion=$(echo "$appVersion" | awk -F '.' '{print $1}')
if [[ $majorVersion -ge 75 ]] ; then
    # Framework will be in ../Content/Frameworks
    frameWorkPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Frameworks/Google Chrome Framework.framework/Versions/${appVersion}/Resources"
else
    # Framework will be in ../Contents/Versions
    frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Frameworks/KeystoneRegistration.framework"
    scriptsPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources"
fi

updateURL=$(defaults read "${appPath}/Contents/Info.plist" KSUpdateURL)
productID=$(defaults read "${appPath}/Contents/Info.plist" KSProductID)

"${scriptsPath}/keystone_promote_preflight.sh" 2>/dev/null 1>&2
"${frameWorkPath}/Resources/ksinstall" --install "${frameWorkPath}/Resources/Keystone.tbz" --force 2>/dev/null
/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin \
    --register \
    --productid "${productID}" \
    --version "${appVersion}" \
    --xcpath "${appPath}" \
    --url "${updateURL}" \
    --tag-path "${appPath}/Contents/Info.plist" \
    --tag-key "KSChannelID" \
    --brand-path "/Library/Google/Google Chrome Brand.plist" \
    --brand-key "KSBrandID" \
    --version-path "${appPath}/Contents/Info.plist" \
    --version-key "KSVersion"
"${scriptsPath}/keystone_promote_postflight.sh" "${appPath}" 2>/dev/null 1>&2
Like
SOLVED Posted: by kwiggins

I'm getting code 127 errors too. @ryan.ball

Like
SOLVED Posted: by CorpIT_eB

@ryan.ball I don't notice the changes in your script here from the one prior?

Like
SOLVED Posted: by ryan.ball

Was:

frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Frameworks/KeystoneRegistration.framework"
scriptsPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Version/A/Resources"

Now:

frameWorkPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Frameworks/KeystoneRegistration.framework"
scriptsPath="${appPath}/Contents/Versions/${appVersion}/Google Chrome Framework.framework/Versions/A/Resources"
Like
SOLVED Posted: by CorpIT_eB

@ryan.ball That gave me a Code 0

I will let you know if this updates the current version of Chrome and toggles on auto updates after a recon push.

Thanks again for all your hard work @ryan.ball

Like
SOLVED Posted: by rqomsiya

I'm getting this error with @ryan.ball 's script:

KSInstallAction install script failure. Exit code: 12. Standard error output: "goobspatch: old hash mismatch: ee3b7cc8d6e24be4a5cd4bf41330bc783aac1411 != 08a53d4ffe4dd04384ff193b609c604b99af24f0\ndirpatcher.sh: couldn't create /Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/75.0.3770.90/Google Chrome Framework by applying /tmp/KSInstallAction.5kcwe9seHm/m/.patch/framework_75.0.3770.80_75.0.3770.90.dirpatch/Google Chrome Framework$gbs to /Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions/75.0.3770.80/Google Chrome Framework\n.keystone_install: dirpatcher of versioned directory failed, status 13\n".

Anyone seen this?

Like
SOLVED Posted: by sdagley

@rqomsiya Notice the mix of version numbers in that output

Like
SOLVED Posted: by rqomsiya

@sdagley I only have one version installed, why do you think it might be pulling different versions?

Thanks!

Like
SOLVED Posted: by sdagley

@rqomsiya Take a look inside the Google Chrome.app package (right-click on the Google Chrome.app icon select Show Package Contents from the popup menu that will be displayed). Dig down into Contents/Frameworks/Google\ Chrome\ Framework.framework/Versions and you'll see there are actually multiple versions present.

I suspect either @ryan.ball's script has a problem running when there is more than 1 version present, the v75 Chrome updater mechanism has a problem when more than 1 version is present, or your install of Chrome was corrupted.

Like
SOLVED Posted: by ryan.ball

Somehow this became my script, so I took it upon myself to add error checking and some output that might help people. I'm afraid that adding multiple versions to the thread has probably caused some confusion for folks, so I've posted a version on my github for the community to try.

Like
SOLVED Posted: by msw-sa
Written by Ryan Ball after somehow becoming responsible for it

@ryan.ball Hah I know the feeling — thanks for your work on this. I'm sure it will be used by many 👍

Like
SOLVED Posted: by Dr_Jones

This method has worked perfectly for me over the past year

  1. https://grahamgilbert.com/blog/2018/03/14/google-chrome-update-notifications-with-yo/
  2. https://github.com/grahamgilbert/chrome_update_notifier
Like
SOLVED Posted: by CorpIT_eB

@Dr_Jones You mean in terms of Notifications correct not a script for updating and keeping It's self updated.

Like

Jamf would like feedback on User Enrollment and General Settings within your Pro instance!