This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Updates asset tag information in Jamf Pro. | |
# This script reads a .csv file formatted as follows: | |
# | |
# "Serial number, Asset number" as the first line | |
# | |
# Subsequent lines: | |
# Column 1: A Mac's serial number | |
# Column 2: An inventory asset code | |
# | |
# Example: | |
# | |
# Serial number, Asset number | |
# W8810X481AX,1652 | |
# W89020U8289,1978 | |
# CK1243R4DB6,2011 | |
# | |
# This script is designed to run as shown below: | |
# | |
# /path/to/Jamf_Pro_Inventory_Asset_Tag_Update.sh filename_goes_here.csv | |
# | |
# Once executed, the script will then do the following: | |
# | |
# Skip the first line of the .csv file (this is the "Serial number, Asset number" line.) | |
# Read each subsequent line of the .csv one at a time and assign the values of column 1 | |
# and column 2 to separate variables. | |
# | |
# Use the variables in an API PUT call to identify a Jamf Pro | |
# computer inventory record using the serial number listed in | |
# the .csv file and populate the asset tag information using | |
# the inventory asset code listed in the .csv file. | |
# | |
# Display HTTP return code and API output | |
# | |
# Successful asset update should produce output similar to that shown below: | |
# | |
# Successfully updated computer record with serial number W8810X481AX with asset number 1652 | |
# Successfully updated computer record with serial number W89020U8289 with asset number 1978 | |
# Successfully updated computer record with serial number CK1243R4DB6 with asset number 2011 | |
# | |
# If setting up a specific user account with limited rights, here are the required API privileges | |
# for the account on the Jamf Pro server: | |
# | |
# Jamf Pro Server Objects: | |
# | |
# Computers: Read, Update | |
# If you're on Jamf Pro 10.34.2 or earlier, which doesn't support using Bearer Tokens | |
# for Classic API authentication, set the NoBearerToken variable to the following value | |
# as shown below: | |
# | |
# yes | |
# | |
# NoBearerToken="yes" | |
# | |
# If you're on Jamf Pro 10.35.0 or later, which does support using Bearer Tokens | |
# for Classic API authentication, set the NoBearerToken variable to the following value | |
# as shown below: | |
# | |
# NoBearerToken="" | |
NoBearerToken="" | |
GetJamfProAPIToken() { | |
# This function uses Basic Authentication to get a new bearer token for API authentication. | |
# Use user account's username and password credentials with Basic Authorization to request a bearer token. | |
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then | |
api_token=$(/usr/bin/curl -X POST –silent -u "${jamfpro_user}:${jamfpro_password}" "${jamfpro_url}/api/v1/auth/token" | python -c 'import sys, json; print json.load(sys.stdin)["token"]') | |
else | |
api_token=$(/usr/bin/curl -X POST –silent -u "${jamfpro_user}:${jamfpro_password}" "${jamfpro_url}/api/v1/auth/token" | plutil -extract token raw -) | |
fi | |
} | |
APITokenValidCheck() { | |
# Verify that API authentication is using a valid token by running an API command | |
# which displays the authorization details associated with the current API user. | |
# The API call will only return the HTTP status code. | |
api_authentication_check=$(/usr/bin/curl –write-out %{http_code} –silent –output /dev/null "${jamfpro_url}/api/v1/auth" –request GET –header "Authorization: Bearer ${api_token}") | |
} | |
CheckAndRenewAPIToken() { | |
# Verify that API authentication is using a valid token by running an API command | |
# which displays the authorization details associated with the current API user. | |
# The API call will only return the HTTP status code. | |
APITokenValidCheck | |
# If the api_authentication_check has a value of 200, that means that the current | |
# bearer token is valid and can be used to authenticate an API call. | |
if [[ ${api_authentication_check} == 200 ]]; then | |
# If the current bearer token is valid, it is used to connect to the keep-alive endpoint. This will | |
# trigger the issuing of a new bearer token and the invalidation of the previous one. | |
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then | |
api_token=$(/usr/bin/curl "${jamfpro_url}/api/v1/auth/keep-alive" –silent –request POST –header "Authorization: Bearer ${api_token}" | python -c 'import sys, json; print json.load(sys.stdin)["token"]') | |
else | |
api_token=$(/usr/bin/curl "${jamfpro_url}/api/v1/auth/keep-alive" –silent –request POST –header "Authorization: Bearer ${api_token}" | plutil -extract token raw -) | |
fi | |
else | |
# If the current bearer token is not valid, this will trigger the issuing of a new bearer token | |
# using Basic Authentication. | |
GetJamfProAPIToken | |
fi | |
} | |
InvalidateToken() { | |
# Verify that API authentication is using a valid token by running an API command | |
# which displays the authorization details associated with the current API user. | |
# The API call will only return the HTTP status code. | |
APITokenValidCheck | |
# If the api_authentication_check has a value of 200, that means that the current | |
# bearer token is valid and can be used to authenticate an API call. | |
if [[ ${api_authentication_check} == 200 ]]; then | |
# If the current bearer token is valid, an API call is sent to invalidate the token. | |
authToken=$(/usr/bin/curl "${jamfpro_url}/api/v1/auth/invalidate-token" –silent –header "Authorization: Bearer ${api_token}" -X POST) | |
# Explicitly set value for the api_token variable to null. | |
api_token="" | |
fi | |
} | |
# If you choose to hardcode API information into the script, set one or more of the following values: | |
# | |
# The username for an account on the Jamf Pro server with sufficient API privileges | |
# The password for the account | |
# The Jamf Pro URL | |
# Set the Jamf Pro URL here if you want it hardcoded. | |
jamfpro_url="" | |
# Set the username here if you want it hardcoded. | |
jamfpro_user="" | |
# Set the password here if you want it hardcoded. | |
jamfpro_password="" | |
# If you do not want to hardcode API information into the script, you can also store | |
# these values in a ~/Library/Preferences/com.github.jamfpro-info.plist file. | |
# | |
# To create the file and set the values, run the following commands and substitute | |
# your own values where appropriate: | |
# | |
# To store the Jamf Pro URL in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here | |
# | |
# To store the account username in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here | |
# | |
# To store the account password in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here | |
# | |
# If the com.github.jamfpro-info.plist file is available, the script will read in the | |
# relevant information from the plist file. | |
jamfpro_plist="$HOME/Library/Preferences/com.github.jamfpro-info.plist" | |
filename="$1" | |
exitCode=0 | |
if [[ -r "$jamfpro_plist" ]]; then | |
if [[ -z "$jamfpro_url" ]]; then | |
jamfpro_url=$(defaults read "${jamfpro_plist%.*}" jamfpro_url) | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
jamfpro_user=$(defaults read "${jamfpro_plist%.*}" jamfpro_user) | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
jamfpro_password=$(defaults read "${jamfpro_plist%.*}" jamfpro_password) | |
fi | |
fi | |
# If the Jamf Pro URL, the account username or the account password aren't available | |
# otherwise, you will be prompted to enter the requested URL or account credentials. | |
if [[ -z "$jamfpro_url" ]]; then | |
read -p "Please enter your Jamf Pro server URL : " jamfpro_url | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
read -p "Please enter your Jamf Pro user account : " jamfpro_user | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
read -p "Please enter the password for the $jamfpro_user account: " -s jamfpro_password | |
fi | |
echo "" | |
# Remove the trailing slash from the Jamf Pro URL if needed. | |
jamfpro_url=${jamfpro_url%%/} | |
# If configured to get one, get a Jamf Pro API Bearer Token | |
if [[ -z "$NoBearerToken" ]]; then | |
GetJamfProAPIToken | |
fi | |
if [[ -n $filename && -r $filename ]]; then | |
while IFS=, read serial_number asset_number || [ -n "$serial_number" ]; do | |
if [[ -z "$NoBearerToken" ]]; then | |
CheckAndRenewAPIToken | |
apiResponse=$(/usr/bin/curl -s –header "Authorization: Bearer ${api_token}" "${jamfpro_url}/JSSResource/computers/serialnumber/${serial_number}" -w "<http_status>%{http_code}</http_status>" -H "Content-Type: application/xml" -X PUT -d "<computer><general><asset_tag>${asset_number}</asset_tag></general></computer>") | |
else | |
apiResponse=$(/usr/bin/curl -su "${jamfpro_user}:${jamfpro_password}" "${jamfpro_url}/JSSResource/computers/serialnumber/${serial_number}" -w "<http_status>%{http_code}</http_status>" -H "Content-Type: application/xml" -X PUT -d "<computer><general><asset_tag>${asset_number}</asset_tag></general></computer>") | |
fi | |
responseCode=$(echo "$apiResponse" | /usr/bin/sed -n 's/.*<http_status>\([^<]*\).*/\1/p') | |
if [[ "$responseCode" != "201" ]]; then | |
echo "Update of computer record with serial number $serial_number failed with http error $responseCode" | |
else | |
echo "Successfully updated computer record with serial number $serial_number with asset number $asset_number" | |
fi | |
done < <(tail -n +2 "$filename") | |
else | |
echo "Input file does not exist or is not readable" | |
exitCode=1 | |
fi | |
exit "$exitCode" |