Home > FileVault 2, Jamf Pro, Jamf Pro API, Jamf Pro Classic API, Mac administration, macOS, Scripting > Using the Jamf Pro API to retrieve FileVault personal recovery keys

Using the Jamf Pro API to retrieve FileVault personal recovery keys

As part of Jamf Pro 10.43’s release, Jamf has added the ability to access and retrieve FileVault personal recovery keys via the Jamf Pro API:

For those who want to use this new capability, I’ve written a script which uses the Jamf Pro Classic API and Jamf Pro API to take a list of Jamf Pro computer IDs from a plaintext file, retrieve the associated Macs’ FileVault personal recovery keys and generate a report in .tsv format.

For more details, please see below the jump.

Pre-requisites:

If setting up a specific Jamf Pro user account for this purpose with limited rights, here are the required API privileges for the account on the Jamf Pro server:

Jamf Pro Server Objects:

  • Computers: Read

Jamf Pro Server Actions:

  • View Disk Encryption Recovery Key

For authentication, the script can accept manual input or values stored in a ~/Library/Preferences/com.github.jamfpro-info.plist file. The plist file can be created by running the following commands and substituting 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

view raw

gistfile1.txt

hosted with ❤ by GitHub

To store the account username in the plist file:


defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here

view raw

gistfile1.txt

hosted with ❤ by GitHub

To store the account password in the plist file:


defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here

view raw

gistfile1.txt

hosted with ❤ by GitHub

This script imports a list of Jamf Pro computer ID numbers from a plaintext file and uses that information to generate a report about the FileVault personal recovery keys associated with those computers. The plaintext file format should look like this:


13
86
87
85

Usage: 

/path/to/generate_filevault_recovery_key_report_from_jamf_pro_id_numbers /path/to/jamf_pro_id_numbers.txt

Screenshot 2023 01 25 at 4 27 23 PM

Once the Jamf Pro computer ID numbers are read from in from the plaintext file, the script takes the following actions:

1. Uses the Jamf Pro API to download all information about the matching computer inventory record in XML format.

2. Pulls the following information out of the inventory entry:

  • Manufacturer
  • Model
  • Serial Number
  • Hardware UDID

3. Runs a separate API call to retrieve the following in JSON format.

  • FileVault personal recovery key

4. Create a report in tab-separated value (.tsv) format which contains the following information about the deleted Macs

  • Jamf Pro ID
  • Manufacturer
  • Model
  • Serial Number
  • Hardware UDID
  • FileVault personal recovery key if available
  • Jamf Pro URL for the computer inventory record

The resulting report in .tsv format will contain information similar to what’s shown below:



Jamf Pro ID Number Make Model Serial Number UDID FileVault Recovery Key Available FileVault Recovery Key Jamf Pro URL
13 Apple Mac mini (Mid 2011) C07GM01TDJD0 00BC7701-6791-573D-B461-470B44D16DF6 No NA https://jamfpro.pretendco.com:8443/computers.html?id=13
86 Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VM0N0WRc4EjC 564D33BC-AF4C-86CF-1DFB-AF6EDFC395A3 Yes 3CZZ-OB8K-HXCF-5O3D-ZPQR-AFP2 https://jamfpro.pretendco.com:8443/computers.html?id=86
87 Apple iMac Pro Intel (Retina 5k, 27-inch, Late 2017) VMWmmR2FJqk3 564D4A6F-280F-1EC0-5E66-178DB2D45A8A Yes KGPW-DE8Q-ACHK-OCHX-CG52-JNHT https://jamfpro.pretendco.com:8443/computers.html?id=87
85 Apple VMware Virtual Platform VMD4TkB2CNtn 564D6125-8B99-47F1-9867-F92CD80BF0C9 Yes TLFA-PEUM-6G5W-4MBF-XG7U-BL24 https://jamfpro.pretendco.com:8443/computers.html?id=85

This script is available below and also from GitHub at the following location:

https://github.com/rtrouton/rtrouton_scripts/tree/main/rtrouton_scripts/Casper_Scripts/generate_filevault_recovery_key_report_from_jamf_pro_id_numbers


#!/bin/bash
# This script imports a list of Jamf Pro ID numbers from a plaintext file
# and uses that information to generate a report about the matching computers'
# FileVault personal recovery keys.
#
# Usage: /path/to/generate_filevault_recovery_key_report_from_jamf_pro_id_numbers.sh jamf_pro_id_numbers.txt
#
# Once the Jamf Pro ID numbers are read from in from the plaintext file, the script takes the following actions:
#
# 1. Uses the Jamf Pro API to download all information about the matching computer inventory record in XML format.
# Once the Jamf Pro ID numbers are read from in from the plaintext file, the script takes the following actions:
#
# 1. Uses the Jamf Pro API to download information about the matching computer inventory record in XML format.
# 2. Pulls the following information out of the inventory entry:
#
# Manufacturer
# Model
# Serial Number
# Hardware UDID
#
# 3. Runs a separate API call to retrieve the following in JSON format.
#
# FileVault personal recovery key
#
# 4. Create a report in tab-separated value (.tsv) format which contains the following information
# about the relevant Macs
#
# Jamf Pro ID
# Manufacturer
# Model
# Serial Number
# Hardware UDID
# If FileVault personal recovery key is available
# Jamf Pro URL for the computer inventory record
report_file="$(mktemp).tsv"
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
}
FileVaultRecoveryKeyValidCheck() {
# Verify that a FileVault recovery key is available by running an API command
# which checks if there is a FileVault recovery key present.
#
# The API call will only return the HTTP status code.
filevault_recovery_key_check=$(/usr/bin/curl –write-out %{http_code} –silent –output /dev/null "${jamfpro_url}/api/v1/computers-inventory/$ID/filevault" –request GET –header "Authorization: Bearer ${api_token}")
}
FileVaultRecoveryKeyRetrieval() {
# Retrieves a FileVault recovery key from the computer inventory record.
if [[ $(/usr/bin/sw_vers -productVersion | awk -F . '{print $1}') -lt 12 ]]; then
filevault_recovery_key_retrieved=$(/usr/bin/curl -sf –header "Authorization: Bearer ${api_token}" "${jamfpro_url}/api/v1/computers-inventory/$ID/filevault" -H "Accept: application/json" | python -c 'import sys, json; print json.load(sys.stdin)["personalRecoveryKey"]')
else
filevault_recovery_key_retrieved=$(/usr/bin/curl -sf –header "Authorization: Bearer ${api_token}" "${jamfpro_url}/api/v1/computers-inventory/$ID/filevault" -H "Accept: application/json" | plutil -extract personalRecoveryKey raw –)
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.
jamf_plist="$HOME/Library/Preferences/com.github.jamfpro-info.plist"
if [[ -r "$jamf_plist" ]]; then
if [[ -z "$jamfpro_url" ]]; then
jamfpro_url=$(defaults read "${jamf_plist%.*}" jamfpro_url)
fi
if [[ -z "$jamfpro_user" ]]; then
jamfpro_user=$(defaults read "${jamf_plist%.*}" jamfpro_user)
fi
if [[ -z "$jamfpro_password" ]]; then
jamfpro_password=$(defaults read "${jamf_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
filename="$1"
# Remove the trailing slash from the Jamf Pro URL if needed.
jamfpro_url=${jamfpro_url%%/}
# Get Jamf Pro API bearer token
GetJamfProAPIToken
progress_indicator() {
spinner="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
while :
do
for i in $(seq 0 7)
do
echo -n "${spinner:$i:1}"
echo -en "\010"
sleep 0.10
done
done
}
echo "Report being generated. File location will appear below once ready."
progress_indicator &
SPIN_PID=$!
trap "kill -9 $SPIN_PID" $(seq 0 15)
while read -r ID; do
if [[ "$ID" =~ ^[0-9]+$ ]]; then
CheckAndRenewAPIToken
ComputerRecord=$(/usr/bin/curl -sf –header "Authorization: Bearer ${api_token}" "${jamfpro_url}/JSSResource/computers/id/$ID" -H "Accept: application/xml" 2>/dev/null)
if [[ ! -f "$report_file" ]]; then
touch "$report_file"
printf "Jamf Pro ID Number\tMake\tModel\tSerial Number\tUDID\tFileVault Recovery Key Available\tFileVault Recovery Key\tJamf Pro URL\n" > "$report_file"
fi
FileVaultRecoveryKeyValidCheck
if [[ ${filevault_recovery_key_check} == 200 ]]; then
FileVaultKeyAvailable="Yes"
FileVaultRecoveryKeyRetrieval
if [[ -n "$filevault_recovery_key_retrieved" ]]; then
FileVaultRecoveryKey="$filevault_recovery_key_retrieved"
else
FileVaultRecoveryKey="Error retrieving FileVault recovery key"
fi
else
FileVaultKeyAvailable="No"
FileVaultRecoveryKey="NA"
fi
Make=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/make/text()'2>/dev/null)
MachineModel=$(echo "$ComputerRecord" | xmllint –xpath '//computer/hardware/model/text()'2>/dev/null)
SerialNumber=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/serial_number/text()'2>/dev/null)
UDIDIdentifier=$(echo "$ComputerRecord" | xmllint –xpath '//computer/general/udid/text()'2>/dev/null)
JamfProURL=$(echo "$jamfpro_url"/computers.html?id="$ID")
if [[ $? -eq 0 ]]; then
printf "$ID\t$Make\t$MachineModel\t$SerialNumber\t$UDIDIdentifier\t${FileVaultKeyAvailable}\t${FileVaultRecoveryKey}\t${JamfProURL}\n" >> "$report_file"
else
echo "ERROR! Failed to read computer record with id $ID"
fi
fi
done < "$filename"
kill -9 "$SPIN_PID"
if [[ -f "$report_file" ]]; then
echo "Report on Macs available here: $report_file"
fi
exit 0

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: