Create a local record with information from Jamf, for later use in scripting

When running shell scripts on client machines through Jamf, information about the machine and user in question is sometimes needed to get things done right.

Among the most frequently used pieces of information:

The currently logged-in user: Often used to run shell commands as the user using sudo -u $loggedInUser, since many settings and commands will only work as expected if set or executed as the local user. Currently the most common way of getting this information is by using Python, though we should probably be migrating to fetching the information from the macOS System Configuration Daemon. Apple has said they will stop including Python with the default install at some point. The command below has been verified to work in Bash as well as Zsh, the upcoming default shell in macOS Catalina.

loggedInUser=$( /usr/sbin/scutil <<< “show State:/Users/ConsoleUser” | awk -F’: ‘ ‘/[[:space:]]+Name[[:space:]]:/ { if ( $2 != “loginwindow” ) { print $2 }}’ )

The serial number:

serialNumber=$( /usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk ‘/Serial\ Number\ (system)/ {print $NF}’)

Information from Jamf, such as the user email address, department and building, and JSS computer id cannot be fetched as easily.

There is a way to access and use information from Jamf in local scripts, however. It will also provide an alternative way of getting the serial and username (the latter provided your machiness are intended for one user only): Using the Jamf API to create a local record and accessing it when needed. Record creation can be done during initial setup, or on machines already in production:

1. In Jamf Pro User Accounts & Groups, create a Jamf user specifically for accessing the API, with read-only access to computer records only (it should only be necessary to tick one box for this to work). Preferably use a non-standard username and 15-20 character random password. Do not reuse an API user; make a separate one for this use case, and never use an admin user with broad access rights for accessing the API.

2. Get the authentication string to use when fetching the record (replace username:password below with the credentials of the user you just made in Jamf):

printf “username:password” | iconv -t ISO-8859-1 | base64 -i –

3. Use a script like the one below to create a local record. Replace the string after “authorization: Basic” with the output of the above command. Use a Jamf script parameter instead of hard-coding the encoded credentials in the script and optionally add a layer of obfuscation using encrypted script parameters.

#!/bin/bash

# Get computer serial number
serialNumber=$( /usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk ‘/Serial\ Number\ (system)/ {print $NF}’)

# Create a folder for the record
mkdir /usr/local/records

# Get computer information from the JSS using the Jamf API
/usr/bin/curl –tlsv1.2 -X GET https://organization.jamfcloud.com/JSSResource/computers/match/$serialNumber –header ‘authorization: Basic cGeoLe6nuPKwnzwqTAG2WdTLxHzt6Nnd7goV4csz’ –header ‘Accept: text/xml’ -o /usr/local/records/computer_info_raw.xml > /dev/null 2>&1

# Clean up the XML file
/usr/bin/xmllint –format /usr/local/records/computer_info_raw.xml –output /usr/local/records/computer_info.xml

# Delete the raw XML file
rm -f /usr/local/records/computer_info_raw.xml

exit 0

Voila.

You now have a local record in /usr/local/records/computer_info.xml with the Jamf computer id, udid, serial, mac address, asset tag, username, email and department. It will look something like this:

To use information from the record in a script later, use a variable like the one below, which runs cat to display the record, piping the output to sed to get the useful part:

userEmail=$(cat /usr/local/records/computer_info.xml | sed -n -e ‘s/.*<email>\(.*\)<\/email>.*/\1/p’)

To fetch a different piece of information, replace “email” in the above command with username, department or whatever you need from the local record.

Example: Setting the Microsoft Office activation email

Setting the Microsoft Office activation email can be done like this (for more information, see macadmins.software):

#!/bin/bash

# Get local user
userName=$(cat /usr/local/records/computer_info.xml | sed -n -e ‘s/.*<username>\(.*\)<\/username>.*/\1/p’)

# Get email address
userEmail=$(cat /usr/local/records/computer_info.xml | sed -n -e ‘s/.*<email>\(.*\)<\/email>.*/\1/p’)

# Set the Office activation email address as the local user
sudo -u $userName defaults write com.microsoft.office OfficeActivationEmailAddress $userEmail

Provided the email address in Jamf is the same as the Microsoft Office activation email address, setting it this way would work.

Download the script creating a local computer information record on GitHub.

Worth noting:

  • There are several ways to get correct information in Jamf, depending on your setup.
  • Enrolling machines using a QuickAdd package will result in very little extra information in Jamf.
  • If you are enrolling users using Jamf’s Active Directory (AD) integration, having users enter their credentials in a DEP setup or helping them enter them on the webpage, will result in more information being available in Jamf.
  • If you are using AD integration, you will need to create departments in Jamf that have identical names to those in AD under Settings-Network Organization-Departments and add desired LDAP Attributes from AD under Setttings-System Settings-LDAP Servers-[Server Name]-Mappings, before enrolling users.
  • There is also an option to update machines in production with directory information, which it would make sense to try on a separate Jamf Site used for testing before putting into production.

Even though API user credentials are only present in client machine memory at runtime when using Jamf script parameters, public organizations or those with strict security requirements shouldn’t make API calls from client machines. API calls for sensitive data and API write operations should only be conducted on admin workstations or servers.

It would be nice if the agent could access information in the computer record directly. Please upvote this feature request on Jamf Nation.

An example of how you would write an asset tag to the API:

assetTag=
jssid=

curl –tlsv1.2 -X PUT -H ‘authorization: Basic cGeoLe6nuPKwnzwqTAG2WdTLxHzt6Nnd7goV4csz’ -H “Content-Type: text/xml” -d ” ${assetTag} ” https://organization.jamfcloud.com/JSSResource/computers/id/${jssid}

To restrict access to the local record:

/usr/sbin/chown -R root:wheel /usr/local/records
/bin/chmod 600 /usr/local/records/computer_info.xml

2 thoughts on “Create a local record with information from Jamf, for later use in scripting

  1. Nice post. I couldn’t get the sed part to work properly (even when exchanging the smart quotes for standard ones), but it works well with xpath, e.g.:

    username=$(cat /usr/local/records/computer_info.xml | xmllint –xpath ‘//computer/username/text()’ -)

    Like

    1. Thanks for this, that is probably a more correct way to get it. The code should be fixed now, WordPress changed characters around breaking things. Using gists or the code tag would probably be more reliable. Otherwise I will have to get a subscription to customize the design. The code in the linked script should work.

      Like

Leave a comment