Background
Inspired by [~elliotjordan]’s plea to obtain user feedback, we’ve been using a pop-up menu Computer Extension Attribute called “Testing Level” which has three options:
- Alpha (i.e., bleeding-edge test machines)
- Beta (i.e., direct team members)
- Gamma (i.e., opt-in testers from various teams)

We then have Smart Computer Groups for each of the three levels and a fourth for “none” so we can more easily scope policies.

This has been working well, but has required a JSS administrator to manually edit each computer record and specify the desired Testing Level.
After being challenged by [~mike.paul] and [~kenglish] to leverage the API, a search revealed [~seansb]’s Updating Pop-Up Extension Attribute Value via API post and [~mm2270]’s reply about Results of single extension attribute via API we had exactly what we needed.
API Permissions for Computer Extension Attributes
In my rather frustated testing, the API read / write account needs (at least) the following JSS Objects “Read” and “Update” permissions:
- Computer Extension Attributes
- Computers
- User Extension Attributes
- Users
Script: Update Extension Attribute
You’ll need to update the “apiURL” in the following script which leverages parameters 4 though 7 for:
- API Username
- API Password
- EA Name (i.e., “Testing Level”)
- EA Value (i.e., “Gamma” or “None”)

#!/bin/sh #################################################################################################### # # ABOUT # # Set a computer's Extension Attribute via the API # #################################################################################################### # # HISTORY # # Version 1.0, 30-Jul-2016, Dan K. Snelson # #################################################################################################### # Import logging functions source /path/to/logging/script/logging.sh #################################################################################################### ScriptLog "--- Set a computer's Extension Attribute via the API ---" ### Variables apiURL="https://jss.company.com" # JSS URL without trailing forward slash apiUsername="${4}" # API Username apiPassword="${5}" # API Password eaName="${6}" # Name of Extension Attribute (i.e., "Testing Level") eaValue="${7}" # Value for Extension Attribute (i.e., "Gamma" or "None") computerUDID=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Hardware UUID:/ { print $3 }') # Validate a value has been specified for Parameter 4 ... if [ ! -z "${apiUsername}" ] && [ ! -z "${apiPassword}" ] && [ ! -z "${eaName}" ] && [ ! -z "${eaValue}" ]; then # All script parameters have been specified, proceeding ... ScriptLog "* All script parameters have been specified, proceeding ..." ScriptLog "* Extension Attribute Name: ${eaName}" ScriptLog "* Extension Attribute New Value: ${eaValue}" if [ ${eaValue} == "None" ]; then ScriptLog "* Extension Attribute Value is 'None'; remove value ${eaName}" eaValue="" fi # Read current value ... apiRead=`curl -H "Accept: text/xml" -sfku ${apiUsername}:${apiPassword} ${apiURL}/JSSResource/computers/udid/${computerUDID}/subset/extension_attributes | xmllint --format - | grep -A3 "<name>${eaName}</name>" | awk -F'>|<' '/value/{print $3}'` ScriptLog "* Extension Attribute ${eaName}'s Current Value: ${apiRead}" # Construct the API data ... apiData="<computer><extension_attributes><extension_attribute><name>${eaName}</name><value>${eaValue}</value></extension_attribute></extension_attributes></computer>" apiPost=`curl -H "Content-Type: text/xml" -sfu ${apiUsername}:${apiPassword} ${apiURL}/JSSResource/computers/udid/${computerUDID} -d "${apiData}" -X PUT` /bin/echo ${apiPost} # Read the new value ... apiRead=`curl -H "Accept: text/xml" -sfku ${apiUsername}:${apiPassword} ${apiURL}/JSSResource/computers/udid/${computerUDID}/subset/extension_attributes | xmllint --format - | grep -A3 "<name>${eaName}</name>" | awk -F'>|<' '/value/{print $3}'` ScriptLog "* Extension Attribute ${eaName}'s New Value: ${apiRead}" ScriptLog "--- Completed setting a computer's Extension Attribute via the API ---" # Re-direct logging to the JSS exec 1>&3 2>&4 /bin/echo >&1 "${eaName} changed to ${eaValue}" else ScriptLog "Error: Parameters 4, 5, 6 and 7 not populated; exiting." # Re-direct logging to the JSS exec 1>&3 2>&4 /bin/echo >&1 "Error: Parameters 4, 5, 6 and 7 not populated; exiting." exit 3 fi exit 0
Script: Logging
The following script is installed client-side and is then source’d by the above script.
#!/bin/sh #################################################################################################### # # ABOUT # # Standard logging functions which are imported into other scripts # #################################################################################################### # # HISTORY # # Version 1.0, 22-Nov-2014, Dan K. Snelson # Version 2.0, 13-Oct-2015, Dan K. Snelson # #################################################################################################### # LOGGING # Logging variables logFile="/var/log/com.company.log" # Check for / create logFile if [ ! -f "${logFile}" ]; then # logFile not found; Create logFile /usr/bin/touch "${logFile}" fi # Save standard output and standard error exec 3>&1 4>&2 # Redirect standard output to logFile exec 1>>"${logFile}" # Redirect standard error to logFile exec 2>>"${logFile}" # Enable all logging from this point forward # set -xv; exec 1>>"${logFile}" 2>&1 # Logging Function inspired by rtrouton ScriptLog(){ DATE=`date +%Y-%m-%d\ %H:%M:%S` /bin/echo "$DATE" " $1" >> ${logFile} } ####################################################################################################
Opt-in Beta Test Program Self Service Policy
Create an ongoing Self Sevice policy, scoped to “Testing: None” which includes a single Scripts option of “Update Extension Attribute” and specify:
- API Username (Read / Write)
- API Password (Read / Write)
- EA Name (i.e., “Testing Level”)
- EA Value (i.e., “Gamma” or “None”)
Opt-out Beta Test Program Self Service Policy
Clone your Opt-in policy and change EA Value to “None” to unset a computer’s Testing Level; scope to your testing groups.