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.