├── README.md ├── download-extension-attributes.sh └── update-extension-attributes.sh /README.md: -------------------------------------------------------------------------------- 1 | Casper Suite - Update Extension Attributes 2 | ========================= 3 | 4 | ## Description 5 | This set of scripts was designed to work with the Casper Suite for Mac management. 6 | The purpose of the scripts is to allow a Mac Casper Suite administrator to update any number of Extension Attribute values on their managed Macs, on as frequent a basis as they want, without needing to perform a full inventory collection. 7 | 8 | ## Compatibility 9 | - The **update-extension-attributes.sh** bash script will work in the Casper Suite 8 and 9 series. 10 | - The companion **download-extension-attributes.sh** bash script will only work in the Casper Suite 9 series. 11 | 12 | ## Requirements and Workflow 13 | The requirements to enable this functionality is as follows 14 | - A JSS API account with both **read** and **write** privileges to your JSS 15 | - A copy of any or all Extension Attributes scripts that can be distributed to your clients
16 | Note: Each Extension Attribute script must contain a line indicating the EA Display Name as it appears in the JSS (see [**Setting up your EA scripts**](https://github.com/mm2270/UpdateExtensionAttributes#setting-up-your-ea-scripts) below for details) 17 | 18 | ### General Workflow: 19 | - A directory is distributed to your Mac clients containing any number of Extension Attribute scripts 20 | - The **update-extension-attributes.sh** script is run on Macs that contain this directory, typically using a Casper Suite policy 21 | - The script will cycle through all scripts in the given directory, capturing their results 22 | - Each result is placed into a final xml file that is then uploaded to the Mac's JSS record using the Casper Suite API PUT function 23 | 24 | Note that the Extension Attribute scripts directory can be protected by making it hidden and/or protected by having it owned by the root account, as long as the "update" script is running with root privileges. 25 | 26 | ### Setting up your EA scripts: 27 | In order for the script to properly set up the final xml file for upload, it needs to know the correct EA Display Name for each script as it encounters it. 28 | To do this, you will need to edit each script to contain a single commented out line in the following format: 29 | ``` 30 | #ea_display_name Actual Display Name 31 | ``` 32 | 33 | The whitespace between **#ea_display_name** and **Actual Display Name** is a single tab character. This is important. A space will not be recognized correctly. This line can be anywhere in the script. The **update-extension-attributes** script will look for the line and pull the EA Display Name to use for the xml file. The readable display name can contain spaces and most special characters, such as dashes, colons, etc. (see the Known Issues section for more) 34 | 35 | In general, this should be the only necessary change to your Extension Attribute scripts. However there are some known issues in relation to the results the scripts may output. See the [**Known Issues**](https://github.com/mm2270/UpdateExtensionAttributes#known-issues) section below for more information. 36 | 37 | ### Using the **download-extension-attributes** companion script: 38 | The **download-extension-attributes.sh** script is a companion script that can be used in conjunction with a Casper Suite 9 series JSS to pull down all Extension Attributes into discrete script files to a given directory. The script will also verify each script by running them against the Mac and checking both the output and exit status. Any scripts that fail will be moved to a sub directory. Any scripts that contain illegal characters in the output will be moved into a separate sub directory. 39 | 40 | For usage information, run the scrpt on the command line as follows: 41 | ``` 42 | /path/to/script/download-extension-attributes.sh -h 43 | ``` 44 | 45 | ## Known Issues 46 | The following are the current known issues with these scripts 47 | 48 | **Illegal characters**
49 | There are several illegal characters that, while they may work without errors in your regular Extension Attribute scripts, can cause a failure of the resulting xml file when the upload is attempted. 50 | Here are the currently known characters: 51 | - ```< & >``` *(Less than, Greater than)* When used in the format of ``````, will cause the xml upload to fail as it sees these as xml tags and believes the xml file to be malformed 52 | - ```%``` *(Percent symbol)* Cannot be used in the result. Causes the upload to fail with an error 53 | - ```,``` *(Comma)* Cannot be used in the result. Causes the upload to fail with an error 54 | - ```*``` *(Asterisk)* Cannot be used in the result. Causes the upload to fail with an error 55 | 56 | The **download-extension-attributes** script will make a best effort to identify scripts that contain any of the above characters in the results and move these scripts into a **Problem_scripts** sub directory.
57 | Any problem or failed scripts will remain in these directories, so you'll have an opportunity to examine them and rectify any issues if desired. Once confirmed working, you'll need to move the scripts into the top level of the scripts directory. The **update-extension-attributes** script only searches one level deep for script files to run at execution time. 58 | 59 | **Multi line results display**
60 | Depending on the specific version of the JSS you're using, multi line Extension Attribute results may not appear properly when viewed in the JSS.
61 | This often turns out to be a bug in the JSS version and not necessarily an issue with the script. Early versions of Casper Suite 9.x had this issue, but has been resolved in at least version 9.3, but possibly earlier releases. 62 | -------------------------------------------------------------------------------- /download-extension-attributes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Script name: download-extension-attributes.sh 4 | ## Author: Mike Morales (@mm2270 on JAMFNation) 5 | ## https://jamfnation.jamfsoftware.com/viewProfile.html?userID=1927 6 | ## Last change: 2014-05-14 7 | 8 | ## Description: Script to download all Extension Attribute scripts from a 9 | ## Casper Suite version 9.x JSS. For more detailed information, 10 | ## run the script in Terminal with the -h flag 11 | 12 | ## The following section contains the only variables that should be manually edited in 13 | ## the script. They can also be assigned to the script as Casper Suite parameters. 14 | ## Read the descriptions for more info. 15 | 16 | ## If you choose to hardcode API information into the script, set the API Username and 17 | ## API Password here. Note: The API account only needs 'read' privileges to pull 18 | ## Extension Attribute scripts 19 | 20 | apiUser="" ## Set the API Username here if you want it hardcoded 21 | apiPass="" ## Set the API Password here if you want it hardcoded 22 | jssURL="" ## Set the JSS URL here if you want it hardcoded 23 | 24 | ## Set the script downloads folder path here. 25 | ## Default path is within the JAMF directory in "extension_attributes" 26 | scriptDownloadDir="/Library/Application Support/JAMF/extension_attributes" 27 | 28 | ################################ DO NOT EDIT BELOW THIS LINE ################################ 29 | 30 | script=$(basename $0) 31 | directory="$( cd "$( dirname "$0" )" && pwd )" 32 | 33 | ## Help / Usage function 34 | usage () 35 | { 36 | cat << EOF 37 | SYNOPSIS 38 | sudo script.sh -a "api_user" -p "api_password" -s "server" 39 | or 40 | sudo jamf runScript -script "script.sh" -path "/path/to/" -p1 "api_user" -p2 "api_password" -p3 "server" 41 | 42 | COMPATIBILITY: 43 | Casper Suite version 9.x 44 | 45 | OPTIONS: 46 | -h Show this usage screen 47 | -a API account username 48 | -p API account password 49 | -s JSS Server address [optional] 50 | 51 | DESCRIPTION: 52 | This script can be used to download a copy of all Extension Attribute scripts 53 | located on the Casper Suite server specified in the server option. 54 | The Casper Suite server URL is optional. If not specified at run time, the script 55 | will attempt to obtain the JSS address from the client's settings. 56 | 57 | The script can be run in two primary ways. 58 | 1. Calling the script directly on the shell 59 | 60 | Example: 61 | sudo "$0" -a "api_username" -p "api_password" -s "https://jss.server.com:8443" 62 | 63 | 2. Using the jamf binary 64 | 65 | Example: 66 | sudo jamf runScript -script "$script" -path "$directory" -p1 "api_username" -p2 "api_password" -p3 "https://jss.server.com:8443" 67 | 68 | You may also use the script directly in a JSS policy, specifying the API username, 69 | API password and (optionally) the JSS URL in parameters 4 through 6, respectively. 70 | 71 | NOTES: 72 | It is recommended to enclose the API username, API password and JSS URL in double quotes 73 | to protect the script against any special characters or spaces in the strings. 74 | 75 | EOF 76 | exit 77 | } 78 | 79 | ## Run loop to check for passed args on the command line 80 | while getopts ha:p:s option; do 81 | case "${option}" in 82 | a) apiUser=${OPTARG};; 83 | p) apiPass=${OPTARG};; 84 | s) jssURL=${OPTARG};; 85 | h) usage;; 86 | esac 87 | done 88 | 89 | ## Check to see if the script was passed any script parameters from Casper 90 | if [[ "$apiUser" == "" ]] && [[ "$4" != "" ]]; then 91 | apiUser="$4" 92 | fi 93 | 94 | if [[ "$apiPass" == "" ]] && [[ "$5" != "" ]]; then 95 | apiPass="$5" 96 | fi 97 | 98 | if [[ "$jssURL" == "" ]] && [[ "$6" != "" ]]; then 99 | jssURL="$6" 100 | fi 101 | 102 | ## Finally, make sure we got at least an apiUser & apiPass variable, else we exit 103 | if [[ -z "$apiUser" ]] || [[ -z "$apiPass" ]]; then 104 | echo "API Username = $apiUser\nAPI Password = $apiPass" 105 | echo "One of the required variables was not passed to the script. Exiting..." 106 | exit 1 107 | fi 108 | 109 | ## If no server address was passed to the script, get it from the Mac's com.jamfsoftware.jamf.plist 110 | if [[ -z "$jssURL" ]]; then 111 | jssURL=$( /usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url 2> /dev/null | sed 's/\/$//' ) 112 | if [[ -z "$jssURL" ]]; then 113 | echo "JSS URL = $jssURL" 114 | echo "Oops! We couldn't get the JSS URL from this Mac, and none was passed to the script" 115 | exit 1 116 | else 117 | echo "JSS URL = $jssURL" 118 | fi 119 | else 120 | ## Make sure to remove any trailing / in the passed parameter for the JSS URL 121 | jssURL=$( echo "$jssURL" | sed 's/\/$//' ) 122 | fi 123 | 124 | ## Set up the JSS Extension Attribute URL 125 | jssEAURL="${jssURL}/JSSResource/computerextensionattributes" 126 | 127 | ## Run quick check on access to the JSS API 128 | curl -skfu "${apiUser}:${apiPass}" "${jssEAURL}" 2>&1 > /dev/null 129 | 130 | if [[ "$?" != "0" ]]; then 131 | echo "There was an error retrieving information from the JSS. 132 | Please check your API credentials and/or the JSS URL, and ensure the JSS is accessible from your location. Exiting now..." 133 | exit 1 134 | fi 135 | 136 | ## Create the extension_attributes directory if not present 137 | if [[ ! -d "$scriptDownloadDir" ]]; then 138 | mkdir "$scriptDownloadDir" 139 | fi 140 | 141 | ## Begin Extension Attribute script download process 142 | echo "Step 1: Gathering all Extension Attribute IDs from the JSS..." 143 | ## Generate a list of all Extension Attribute IDs we can pull from the JSS using the API 144 | allExtAttrIDs=$( curl -skfu "${apiUser}:${apiPass}" "${jssEAURL}" | xpath /computer_extension_attributes/computer_extension_attribute/id[1] 2>&1 | sed -e 's///;s/<\/id>//;s/-- NODE --//' | sed -e '/Found/d;/^$/d' | sort -n ) 145 | 146 | ## Now read through each ID gathered and get specific information on each EA from the JSS 147 | echo "Step 2: Pulling down each Extension Attribute from the JSS..." 148 | 149 | downloadCount=0 150 | while read ID; do 151 | ## Get the EA name from its JSS ID 152 | ea_Name=$( curl -sku "${apiUser}:${apiPass}" "${jssEAURL}/id/${ID}" | xpath /computer_extension_attribute/name[1] 2>&1 | sed -e 's///;s/<\/name>//;s/-- NODE --//' | sed -e '/Found/d;/^$/d' ) 153 | ## Get the actual script contents from the API record for the EA 154 | ea_Script=$( curl -sku "${apiUser}:${apiPass}" "${jssEAURL}/id/${ID}" | xpath /computer_extension_attribute/input_type/script[1] 2>&1 | sed -e 's/