Skip to main content

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.

This would find the largest framework.



frameWorkPath=$(find "$appPath" -name "KeystoneRegistration.framework" | sort | head -1)

@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"

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)

@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?


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


@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?


Running it as root?


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


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


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


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.


@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,


@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.


@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.


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?


@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.


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

@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.


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

@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.

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

@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.


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


@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.


@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.