├── 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/