Extension Attribute - Primary User

New Contributor III

Hey All,

I'm looking to create an extension attribute that emulates the "Primary User" functionality that is available in ZENworks or SCCM.

ZENworks and/or SCCM do this based on the user that has had the most console time.

I found the following post from MarcosMunoz that kind of accomplishes this, except it does so by the user that has had the most logins, from what I can tell.

What I'd really like to do is add up the total console time for each user and set the "User and Location" fields (Username, Full Name, Email Address) in inventory to the values for the user with the most console time (probably pulling from AD) similar to this:

Is an extension attribute able to write to the "User and Location" fields in Jamf Pro?

If not, I'm thinking I could probably achieve most of this already and just do a regular 'ol extension attribute, but I'd prefer the data to be in the standard locations instead of the custom Extension Attributes section of inventory on the computer record.

I also came across this post where someone did essentially the same thing, but again it's based on the login frequency rather than console time:

Perhaps I'm just being a little too picky?

Thanks for any assistance!

Have a great day!



New Contributor III


I've done some chatting with @nkoval whom was kind enough to share a script developed by @bvrooman.

I've snipped out the appropriate section of the script that calculates the primary user by the one logged in the most:

ac -p | sort -nk 2 | grep -v reboot | grep -v shutdown | grep -v root | grep -v _mbsetupuser | grep -v adobeinstall | awk '/total/{print x};{x=$1}'

Now I'm going to build on this in order to populate the values in User and Location based on Active Directory information.

I'll share what I come up with once I have it all put together.


Valued Contributor

@pitcherj Using that ac command, this is probably what you'd want. This will populate the "Username" field in the computer record and will populate the other fields from the LDAP server if those fields are mapped correctly.


# Pass in user credentials in parameters 4 and 5

jssURL=$(defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url | sed s'/.$//')
serial=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
userName=$(ac -p | sort -nk 2 | grep -v reboot | grep -v shutdown | grep -v root | grep -v _mbsetupuser | grep -v adobeinstall | awk '/total/{print x};{x=$1}')

id=$(curl -sku "$apiUser:$apiPass" "$jssURL/JSSResource/computers/serialnumber/$serial" | xmllint --xpath xmllint --xpath '/computer/general/id/text()' - 2>/dev/null)
if [[ -z "$id" ]]; then
    echo "Could not determine Mac's Jamf Pro ID; exiting."
    exit 1
    curl -sku "$apiUser:$apiPass" -H "content-type: text/xml" "$jssURL/JSSResource/computers/id/$id" -X PUT -d "<computer><location><username>$userName</username></location></computer>"

exit 0

EDIT: I'd run this as a policy at recurring check-in once a week, not as an EA.

New Contributor III

@ryan.ball Thanks for sharing that! I'll definitely look into it as populating the other fields automatically from LDAP would be useful.

Here's what I ended up with, which is a combination of all of the sources above.

The only problem is if the account doesn't have a full name attribute, which is typically only with test accounts anyway, but in that case it reads what is on the next line (doesn't break it, but does end up with "ecordName: accountname" on the line, where account name is the name of the account, but I can deal with that for the few test accounts we have.

This script can also function as an EA, or just as a script that writes to the API, depending on what is/isn't commented out.

Also apparently having permissions to "Update" the "Computers" Jamf Pro Server Object isn't enough to write via the API to the User and Location section of a computer record, so I'm still sorting out exactly which permission is required to do that.


mostFrequentUser=`ac -p | sort -nk 2 | grep -v reboot | grep -v shutdown | grep -v root | grep -v _mbsetupuser | grep -v adobeinstall | awk '/total/{print x};{x=$1}'`

FULLNAME=$(dscl localhost -read /Active Directory/ENTER_YOUR_DOMAIN_HERE/All Domains/Users/$mostFrequentUser | sed -n '/RealName/{n;p;}' | cut -c 2-)

emailAddress=$(dscl localhost -read /Active Directory/ENTER_YOUR_DOMAIN_HERE/All Domains/Users/$mostFrequentUser | sed -n '/EMailAddress/{p;}' | cut -d' ' -f2-)

### API write only below. Uncomment out result lines below and delete everything under if you want it to be an Extension Attribute
#echo "<result>$mostFrequentUser</result>"
#echo "<result>$FULLNAME</result>"
#echo "<result>$emailAddress</result>"

# Function to decrypt the string
function DecryptString() {
    # Usage: ~$ DecryptString "Encrypted String" "Salt" "Passphrase"
    echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"

# Enter API Username and password here

# Enter your Jamf Pro URL Here
# Create a new Extension Attribute (empty) and put its name here

# hardware info for API
udid=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Hardware UUID:/ { print $3 }')

xmlString="<?xml version="1.0" encoding="UTF-8"?><computer><location><username>$mostFrequentUser</username><real_name>$FULLNAME</real_name><email_address>$emailAddress</email_address></location></computer>

# Identify the location of the jamf binary for the jamf_binary variable.
CheckBinary (){
# Identify location of jamf binary.
jamf_binary=$(/usr/bin/which jamf)

if [[ "$jamf_binary" == "" ]] && [[ -e "/usr/sbin/jamf" ]] && [[ ! -e "/usr/local/bin/jamf" ]]; then
elif [[ "$jamf_binary" == "" ]] && [[ ! -e "/usr/sbin/jamf" ]] && [[ -e "/usr/local/bin/jamf" ]]; then
elif [[ "$jamf_binary" == "" ]] && [[ -e "/usr/sbin/jamf" ]] && [[ -e "/usr/local/bin/jamf" ]]; then

# Update the $ea_name Extention Attribute
UpdateAPI (){
    -u ${apiUser}:${apiPass} 
    -X PUT 
    -H "Content-Type: text/xml" 
    -d "${xmlString}" "${apiURL}/JSSResource/computers/udid/$udid"