Menu Close

Jamf Pro LAPS: Retrieving Password via Terminal

A new function for your ~/.zshrc to retrieve the managed Apple admin account password from Jamf Pro


With the enhancements included in the recently released Jamf Pro 10.49.0, we decided to take a more serious look at Jamf Pro LAPS.

In doing so, we wanted an easy way for authorized administrators to view the managed Apple admin account password via Terminal.


The following should be considered the minimum required reference material before implementing this approach in production (and we’re still testing in our Stage lane):


[l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane


In limited testing, we granted the following privileges to our dedicated API LAPS Jamf Pro account:

  • Jamf Pro Server Objects
    • Computers
      • Read
  • Jamf Pro Server Actions
    • View Local Admin Password
      • Enabled


After adding the lapss function to your ~/.zshrc, quit and re-launch Terminal, then enter:


You should then observe the following:

# [l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane

1. Type "lapss", followed by a [Space]
2. Paste the computer's Serial Number or Jamf Pro Computer ID
3. Press [Return]

(Enter "iaps help" for initial setup.)

But, if you’re like me, you’d say to yourself …

You’re not the boss of me, script!

… and you’d enter the following straightaway:

lapss C86753099TT

Then — if you haven’t followed the help instructions — you’d observe:

# ERROR: Unable to read API credentials

Please run "lapss help" to configure API credentials.

OK! I’ll enter lapss help and follow the on-screen instructions:

# [l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane Help
# (some code inspired by: Joshua Smith)

Use the following commands to create entries in Keychain Access:

    security add-generic-password -s "lapssApiUrl" -a dan -w ""
    security add-generic-password -s "lapssApiUser" -a dan -w "API Username Goes Here"
    security add-generic-password -s "lapssApiPassword" -a dan -w "API Password Goes Here"

Once the Keychain entries have been created …

    1. Enter "lapss", followed by a [Space]
    2. Paste the computer's Serial Number or Jamf Pro Computer ID
    3. Press [Return]


Now, after the configuration in complete, when you enter lapss followed by a Serial Number of Jamf Pro Computer ID, you should observe the following:

❯ lapss C86753099TT
Found 1 nodes in stdin:
-- NODE --

Retrieving 'localadmin' password for:
• Name: Dan's MacBook Air M1 2020
• Serial Number: C86753099TT
• IP Address:
• IP Address (LR):

Via MDM:
• Server:
• Computer ID: 157

localadmin password for S/N C86753099TT
displayed below and copied to the clipboard:



lapss () {    # [l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane


    if [ -z ${1} ]; then
        printf "\n###\n# [l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane\n###\n\n"
        printf "Usage:\n1. Type \"lapss\", followed by a [Space]\n2. Paste the computer's Serial Number or Jamf Pro Computer ID\n3. Press [Return]\n\n"
        printf "(Enter \"lapss help\" for initial setup.)\n\n"

    if [ ${1} = "help" ]; then

        apiURL=$( /usr/bin/defaults read "/Library/Preferences/com.jamfsoftware.jamf.plist" jss_url )
        printf "\n###\n# [l]ocal [a]dministrator [p]assword [s]olution in the [s]tage lane Help\n# (some code inspired by: Joshua Smith)\n###\n\n"
        printf "Use the following commands to create entries in Keychain Access:\n\n"
        printf "    security add-generic-password -s \"lapssApiUrl\" -a ${USER} -w \"${apiURL}\"\n"
        printf "    security add-generic-password -s \"lapssApiUser\" -a ${USER} -w \"API Username Goes Here\"\n"
        printf "    security add-generic-password -s \"lapssApiPassword\" -a ${USER} -w \"API Password Goes Here\"\n\n"
        printf "Once the Keychain entries have been created …\n\n"
        printf "    1. Enter \"lapss\", followed by a [Space]\n    2. Paste the computer's Serial Number or Jamf Pro Computer ID\n    3. Press [Return]\n\n"


        apiURL=$( security find-generic-password -s "lapssApiUrl" -a "${USER}" -w 2>/dev/null )
        apiUser=$( security find-generic-password -s "lapssApiUser" -a "${USER}" -w 2>/dev/null )
        apiPassword=$( security find-generic-password -s "lapssApiPassword" -a "${USER}" -w 2>/dev/null )

        if [ -z ${apiURL} ] || [ -z ${apiUser} ] || [ -z ${apiUser} ]; then
            printf "\n###\n# ERROR: Unable to read API credentials\n###\n\nPlease run \"lapss help\" to configure API credentials.\n\n"

        # Obtain Jamf Pro Bearer Token via Basic Authentication
        apiBearerToken=$( /usr/bin/curl -X POST --silent -u "${apiUser}:${apiPassword}" "${apiURL}/api/v1/auth/token" | /usr/bin/plutil -extract token raw - )
        # echo "apiBearerToken: ${apiBearerToken}"

        # Determine if user provided a Jamf Pro Computer ID (i.e., a number) or a Serial Number (i.e., NOT a number)
        if ! [[ "${1}" =~ "${numberValidation}" ]] ; then
            # Determine the computer's Jamf Pro Computer ID via the computer's Serial Number, "${1}"
            jssID=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -s "${apiURL}"/JSSResource/computers/serialnumber/"${1}"/subset/general | xpath -e "/computer/general/id/text()" )
        # echo "JSS ID: ${jssID}"

        generalComputerInfo=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -H "Accept: text/xml" -sfk "${apiURL}"/JSSResource/computers/id/"${jssID}/subset/General" -X GET )

        # echo "generalComputerInfo: ${generalComputerInfo}"

        computerName=$( echo ${generalComputerInfo} | xpath -q -e "/computer/general/name/text()" )
        computerSerialNumber=$( echo ${generalComputerInfo} | xpath -q -e "/computer/general/serial_number/text()" ) 
        computerIpAddress=$( echo ${generalComputerInfo} | xpath -q -e "/computer/general/ip_address/text()" ) 
        computerIpAddressLastReported=$( echo ${generalComputerInfo} | xpath -q -e "/computer/general/last_reported_ip/text()" )

        printf "\nRetrieving '${expectedLocalAdminAccount}' password for:\n"
        printf "• Name: $computerName\n"
        printf "• Serial Number: $computerSerialNumber\n"
        printf "• IP Address: $computerIpAddress\n"
        printf "• IP Address (LR): $computerIpAddressLastReported\n\n"

        printf "Via MDM:\n"
        printf "• Server: ${apiURL}\n"
        # printf "• Username: ${apiUser}\n"
        printf "• Computer ID: ${jssID}\n\n"

        computerInventoryGeneral=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -s "${apiURL}"/api/v1/computers-inventory/"${jssID}"?section=GENERAL -H "accept: application/json" ) # on-prem
        # computerInventoryGeneral=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -s "${apiURL}/api/v1/computers-inventory?section=GENERAL&filter=id==${jssID}" -H "accept: application/json" -X GET ) # thanks, @Alec V; Jamf Cloud ???

        # echo "computerInventoryGeneral: ${computerInventoryGeneral}"       

        managementId=$( echo "${computerInventoryGeneral}" | awk '/managementId/{print $NF}' | tr -d '",' )
        # echo "managementId: ${managementId}"

        localAdminAccountsRaw=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -s "${apiURL}"/api/v1/local-admin-password/${managementId}/accounts -H "accept: application/json" )
        # echo "localAdminAccountsRaw: ${localAdminAccountsRaw}"

        username=$( echo "${localAdminAccountsRaw}" | awk '/username/{print $NF}' | tr -d '",' )
        # echo "username: ${username}"

        if [[ "${username}" == *"${expectedLocalAdminAccount}"* ]]; then

            # echo "Found Expected Local Admin Account '${expectedLocalAdminAccount}'; proceeding …"

            localAdminPasswordRaw=$( /usr/bin/curl -H "Authorization: Bearer ${apiBearerToken}" -s "${apiURL}"/api/v1/local-admin-password/${managementId}/account/${expectedLocalAdminAccount}/password -H "accept: application/json" )
            # echo "localAdminPasswordRaw: ${localAdminPasswordRaw}"

            password=$( echo "${localAdminPasswordRaw}" | awk '/password/{print $NF}' | tr -d '",' )
            # echo "password: ${password}"

            printf "\n${expectedLocalAdminAccount} password for S/N ${1}\ndisplayed below and copied to the clipboard:\n\n${prefix}${password}\n\n"
            echo "${password}" | tr -d '\n' | pbcopy

            # Invalidate the Bearer Token
            apiBearerToken=$( /usr/bin/curl "${apiURL}/api/v1/auth/invalidate-token" --silent  --header "Authorization: Bearer ${apiBearerToken}" -X POST )

            printf "\n\n"


            echo "Expected Local Admin Account '${expectedLocalAdminAccount}' NOT found; exiting."




Related Posts

Posted in API, Jamf Pro, Scripts, Tips & Tricks

Related Posts