Extension Attribute to find out the accounts signed into Google Chrome

adamcodega
Valued Contributor

@rderewianko helped me figure out how to check what account someone is signed in with in Google Chrome. We're a Google for Work shop so want to make sure people are signed in like we recommend so their bookmarks and settings are saved to their account for ease of use. Could also be useful for troubleshooting I suppose. If someone is signed into Chrome with multiple accounts it will display all of them.

Next step I'd like to do is detect when the yellow warning icon appears in Chrome, where an account's password needs to be re-entered and Chrome currently is not saving anything to the account.

I have it on GitHub too.

#!/bin/sh
# 
# check-chrome-users.sh
#
# Extension attribute to report which accounts
# are logged into Google Chrome on a Mac.
# 
# For use as a JAMF Casper Suite extension attribute
#
# Adam Codega, Swipely
#

loggedinuser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`

chromestate=`cat /Users/$loggedinuser/Library/Application Support/Google/Chrome/Local State | grep user_name`

echo "<result>$chromestate</result>"
23 REPLIES 23

ssc
New Contributor II

@adamcodega

Did you have any luck with detecting the yellow warning sign in Chrome? We also rely on users to be logged into Google Chrome and this would be extremely useful!

Thanks!

daniel_ross
Contributor III

Sorry to bump an old topic but wanted to see if you figured this out @ssc or @adamcodega ?

ssc
New Contributor II

No I didn't sorry @daniel_ross. Had to rely on user awareness unfortunately.

daniel_ross
Contributor III

@ssc Thanks for the reply and the update. We're working on something on our side and if it ends up working I'll be sure to post it.

ssc
New Contributor II

No worries @daniel_ross! Good luck, would be very useful to have :)

ryanj
New Contributor III

This should do what what guys want.

edit: Ea1 will count the number of accounts with auth_errors currently logged into google chrome if you specify $email_domain it will only count accounts that belong to your specified domain.
Ea2 will list the google accounts logged into chrome and if you specify $email_domain it will only return accounts that contain that domain.

If you leave pecify $email_domain it will count and list all accounts also it looks like the the JSON where this data is located is refreshed on reboot on chrome.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Extension attribute to report which accounts
# are logged into Google Chrome on a Mac.
# and if there is an account auth error
import sys
import json
import os
from SystemConfiguration import SCDynamicStoreCopyConsoleUser




#############################################################################
# Internal email domain to query for auth_errors
# Leave blank if you want to query all accounts
email_domain = ""
# email_domain = "examplecompany.com"

#############################################################################

# Check if chrome is installed
if not os.path.isdir('/Applications/Google Chrome.app'):
    print "<result>Chrome not installed</result>"
    exit(0)

# open json state file
current_user = SCDynamicStoreCopyConsoleUser(None, None, None)[0]
json_path = "/Users/" + current_user + 
            "/Library/Application Support/Google/Chrome/Local State"

with open(os.path.expanduser(json_path)) as json_data:
    d = json.load(json_data)
    de = d["profile"]["info_cache"]

#### Prints the profile structure for debug
# print json.dumps(de, sort_keys=True, indent=4)

#############################################################################
# Number of auth_errors # ea 1
auth_errors = 0
for item in de:
    if de[item]["user_name"] == "":
        print "local_only_account"
    else:
        if email_domain not in de[item]["user_name"]:
            print "personal_account"
        else:
            try:
                # de[item]["is_auth_error"] is not created until there is one
                is_auth_error = de[item]["is_auth_error"]
            except KeyError:
                is_auth_error = False

            if is_auth_error == True:
                auth_errors += 1

print "<result>" + str(auth_errors) + "</result>"

#############################################################################
# List accounts signed into chrome # ea 2
array = []
for item in de:
    if de[item]["user_name"] == "":
        print "local_only_account"
    else:
        if email_domain not in de[item]["user_name"]:
            print "personal_account"
        else:
            array.append(de[item]["user_name"])

if array == []:
    array.append("No Accounts Signed into Chrome")

### Clean the output, there must be a better way¡?!¿
array = str(array).replace('[u'', '')
array = str(array).replace("', u'", ", ")
array = str(array).replace('']', '')
array = str(array).replace(''', '')
array = str(array).replace('[', '')
array = str(array).replace(']', '')

print "<result>" + array + "</result>"

michaelprice
New Contributor III

Neither of these Extension Attributes worked for me, the first one output the entire Local State and the second one only gave a result of 0.

I wrote this one which is working for me with macOS 10.11 -> 10.14.4

#!/bin/bash

#grab logged in user Google Chrome Accounts

#find currently logged in user
loggedInUser=$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')

#check Chrome Local State file, grep user name, scrub quotes, print email address
GoogleChromeAccount=$(cat /Users/$loggedInUser/Library/Application Support/Google/Chrome/Local State | python -m json.tool | grep user_name | awk '{gsub(/"/, ""); print $2}')


/bin/echo "<result>$GoogleChromeAccount</result>"

stevenjklein
Contributor II

@ryanj : One of your comments seems to be corrupt:

### Clean the output, there must be a better way¡?!¿

I realize it's only a comment, but I am curious how that line is supposed to end!

jamesandre
Contributor

I added another grep to find the email address from the local state.

chromestate=cat /Users/James/Library/Application Support/Google/Chrome/Local State | grep user_name | grep -E -o "[A-Za-z0-9._%-]@[A-Za-z0-9.-]+.[A-Za-z]{2,6}"

mgeorgecv
New Contributor III

I added awk -F'"' '{print $4}' to get just the profile.

#!/bin/bash
#
# check-chrome-users.sh
#
# Extension attribute to report which accounts
# are logged into Google Chrome on a Mac.
#
# For use as a JAMF Casper Suite extension attribute
#
# Adam Codega, Swipely
#

loggedinuser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "\n");'`

chromestate=`cat /Users/$loggedinuser/Library/Application\ Support/Google/Chrome/Local\ State | python -m json.tool | grep user_name | awk -F'"' '{print $4}'`

echo "<result>$chromestate</result>"

iOllie
New Contributor II

There is one more method in how to extract the accounts signed into Google Chrome: 

chromeUser=$(jq -r '.profile.info_cache.Default.user_name' /Users/${localAccount}/Library/Application\ Support/Google/Chrome/Local\ State | awk -F@ '{print $1}')

iOllie
New Contributor II

If you need to have exact 'FirstName LastName', it can be like that:

chromeFirstLastName=$(jq -r '.profile.info_cache.Default.gaia_name' /Users/${localAccount}/Library/Application\ Support/Google/Chrome/Local\ State)

iOllie
New Contributor II

Forgot to say that the jq - command line JSON processor has to be installed by Homebrew.

ryan_ball
Valued Contributor

If anybody is looking to remove the python dependency from the extension attribute scripts posted above (before macOS 12.3 drops), here is what I came up with:

#!/bin/bash

# Google Chrome Default User

# This attribute returns the default user logged into Google Chrome

# Created by Ryan Ball at Alectrona

loggedInUser=$( echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' )
loggedInHome=$(/usr/bin/dscl . -read "/Users/$loggedInUser" NFSHomeDirectory 2> /dev/null | /usr/bin/awk '{print $NF}')
chromeLocalStateFile="${loggedInHome}/Library/Application Support/Google/Chrome/Local State"
osVersMajor=$(/usr/bin/sw_vers -productVersion | /usr/bin/awk -F '.' '{print $1}')
unset chromeLocalState chromeUserName plist

# Exit if nobody is logged in or ef Chrome's Local State file does not exist
[[ -z "$loggedInUser" ]] || [[ ! -e "$chromeLocalStateFile" ]] && exit 0

# Convert the Chrome Local State file to plist and extract the Default user_name
plist=$(/bin/cat "$chromeLocalStateFile" 2> /dev/null | /usr/bin/plutil -convert xml1 -o - -- -)

# Use plutil's raw format if macOS 12 or later, otherwise fall back to xmllint
if [[ "$osVersMajor" -ge 12 ]]; then
    chromeUserName=$(echo "$plist" | /usr/bin/plutil -extract profile.info_cache.Default.user_name raw -o - -- - | /usr/bin/grep -vE 'error[\ ]?:')
else
    chromeUserName=$(echo "$plist" | /usr/bin/plutil -extract profile.info_cache.Default.user_name xml1 -o - -- - | /usr/bin/grep -vE 'error[\ ]?:' | /usr/bin/xmllint --xpath '/plist/string/text()' --format - 2> /dev/null)
fi

# Print the user name if it exists
if [[ -n "$chromeUserName" ]]; then
    echo "<result>$chromeUserName</result>"
fi

exit 0

 

mgeorgecv
New Contributor III

That didn't work for me.  So I edited it and this works for me:

 

 

#!/bin/bash

# Google Chrome Default User

# This attribute returns the default user logged into Google Chrome

# Altered by MGeorgeCV, Original Created by Ryan Ball at Alectrona https://community.jamf.com/t5/jamf-pro/extension-attribute-to-find-out-the-accounts-signed-into-google/m-p/260780/emcs_t/S2h8ZW1haWx8dG9waWNfc3Vic2NyaXB0aW9ufEwwSzJETEw4T05VSjhDfDI2MDc4MHxTVUJTQ1JJUFRJT05TfGhL#M240593

loggedInUser=$( echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' )
loggedInHome=$(/usr/bin/dscl . -read "/Users/$loggedInUser" NFSHomeDirectory 2> /dev/null | /usr/bin/awk '{print $NF}')
chromeLocalStateFile="${loggedInHome}/Library/Application Support/Google/Chrome/Local State"
osVersMajor=$(/usr/bin/sw_vers -productVersion | /usr/bin/awk -F '.' '{print $1}')
unset chromeLocalState chromeUserName plist

# Exit if nobody is logged in or ef Chrome's Local State file does not exist
[[ -z "$loggedInUser" ]] || [[ ! -e "$chromeLocalStateFile" ]] && exit 0

# Convert the Chrome Local State file to plist and extract the Default user_name
plist=$(/bin/cat "$chromeLocalStateFile" 2> /dev/null | /usr/bin/plutil -convert xml1 -o - -- -)

# Extract User Name
    chromeUserName=$(echo "$plist" | /usr/bin/grep -A 1 user_name | /usr/bin/grep string | /usr/bin/sed -e 's/<[^>][^>]*>//g' | /usr/bin/awk '{print $1}')


# Print the user name if it exists
if [[ -n "$chromeUserName" ]]; then
    echo "<result>$chromeUserName</result>"
fi

exit 0

 

 

Thanks a bunch for this. Confirmed working on macOS 12.3.1.

MatG
Contributor III

@mgeorgecv 

This is great, thanks.... only thing I'm seeing is if the user has logged into Google with company and personal address or addresses its shows them all in the EA so for example for some users I see

myname@companydomain.com
name@gmail.com
nameb@gmail.com

Any way (sed?) to only show the @companydomain


mgeorgecv
New Contributor III

Yes, I would just add a grep @companydomain.com on the the end of the Extract User Name like so:

#!/bin/bash

# Google Chrome Default User

# This attribute returns the default user logged into Google Chrome

# Altered by MGeorgeCV, Original Created by Ryan Ball at Alectrona https://community.jamf.com/t5/jamf-pro/extension-attribute-to-find-out-the-accounts-signed-into-google/m-p/260780/emcs_t/S2h8ZW1haWx8dG9waWNfc3Vic2NyaXB0aW9ufEwwSzJETEw4T05VSjhDfDI2MDc4MHxTVUJTQ1JJUFRJT05TfGhL#M240593

loggedInUser=$( echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' )
loggedInHome=$(/usr/bin/dscl . -read "/Users/$loggedInUser" NFSHomeDirectory 2> /dev/null | /usr/bin/awk '{print $NF}')
chromeLocalStateFile="${loggedInHome}/Library/Application Support/Google/Chrome/Local State"
osVersMajor=$(/usr/bin/sw_vers -productVersion | /usr/bin/awk -F '.' '{print $1}')
Domain="@companydomain.com"
unset chromeLocalState chromeUserName plist

# Exit if nobody is logged in or ef Chrome's Local State file does not exist
[[ -z "$loggedInUser" ]] || [[ ! -e "$chromeLocalStateFile" ]] && exit 0

# Convert the Chrome Local State file to plist and extract the Default user_name
plist=$(/bin/cat "$chromeLocalStateFile" 2> /dev/null | /usr/bin/plutil -convert xml1 -o - -- -)

# Extract User Name
    chromeUserName=$(echo "$plist" | /usr/bin/grep -A 1 user_name | /usr/bin/grep string | /usr/bin/sed -e 's/<[^>][^>]*>//g' | /usr/bin/awk '{print $1}' | /usr/bin/grep $Domain)


# Print the user name if it exists
if [[ -n "$chromeUserName" ]]; then
    echo "<result>$chromeUserName</result>"
fi

exit 0

MatG
Contributor III

@mgeorgecv  Thats great and here was me trying to sed when it was a grep 😂

One thing I also see and I'm not sure why is the same email address multiple times so for some devices EA shows

user@companyname.com
user@companyname.com
user@companyname.com
user@companyname.com

I wonder what is happening here and why the the file the script is getting the email address from has multiple entries of the same email address 🤔


mgeorgecv
New Contributor III

I don't know, I don't get the same results, but if you want to only show one instance of each account you could try playing with:

awk '!seen[$0]++'

As suggested on this page: https://stackoverflow.com/questions/1444406/how-to-delete-duplicate-lines-in-a-file-without-sorting-...

davidacland
Honored Contributor II
Honored Contributor II

Looks like the Default State is in JSON format. Same result as above, but a different approach, using the jq binary:

#/bin/zsh

# Get the current macOS logged in username
loggedInUser=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }')

# Read the Chrome local state data into a variable
data=$(cat "/Users/$loggedInUser/Library/Application Support/Google/Chrome/Local State")

# Use jq to read the user logged in to Chrome
chromeUser=$(/usr/local/bin/jq '. | .profile.info_cache.Default.gaia_name' <<< $data | sed 's/"//g')

# Output the Chrome user into the EA
echo "<result>$chromeUser</result>"

 

 

I get nothing when I do this script

davidacland
Honored Contributor II
Honored Contributor II

Hey, it looks like it's dependant on a few more things like whether profiles are being used in Chrome, so the script probably needs a bit more work to accommodate all scenarios.