Examples Pro - Jamf-Concepts/apiutil GitHub Wiki

JAMF Pro Examples

 

A simple "GET"

jamfapi --path "/JSSResource/buildings"

In this example, the only parameter specified is the path. This is the simplest possible invocation of the utility.

  • The --target parameter has been omitted so the command would only work in a setup where just a single target has been configured in the application's keychain.
  • The HTTP --method parameter is omitted so "GET" will be used.
  • The --accept parameter is omitted so "application/json" output will be requested.
  • The --content parameter would not be applicable here since no data is being sent.

If the Jamf Pro server has just one building configured and it's named "Apple Park", the output of the command would be:

[
  {
    "size": 1,
    "building": {
      "id": 1,
      "name": "Apple Park"
    }
  }
]

 

Same request, more parameters

The following command will produce the exact same result as the example above because all of the added parameter values match their defaults. There's no technical reason to specify default values explicitly but some developers like to put them in anyway to make the command more self-documenting. The parameter values in this example are wrapped in quotes. This is only technically required when a value contains an un-escaped shell delimiter character (e.g., a space), but some developers like to quote things anyway to make it easier to see that the enclosed string is the parameter's value. The "\" at the end of all but the last line is the shell script "continuation character". It's used here as an example of how to break a command into multiple lines if you wish to improve your script's readability when a command has many parameters.

jamfapi \
  --target "pro" \
  --method "get" \
  --accept "application/json" \
  --path "/JSSResource/buildings"

 

Retrieving XML

The output returned by the previous examples has been in JSON format because it's the jamfapi command's default and we have not overridden it with an --accept parameter. But if we are using a Classic API path, we also have the choice to request XML output.

jamfapi --target "pro-prod" --path "/JSSResource/buildings" --accept "text/xml"

Historically, many API scripts using Jamf Pro's Classic API would request XML-formatted output because command line utilities for parsing XML (i.e. xpath and xmllint) came pre-installed in macOS while jq, a common tool for parsing JSON, was not. But jq is included in current versions of macOS and is generally considered to be easier to use that xpath.

However, you may require data in XML format when you intend to modify it for re-use as the data for a subsequent POST or PUT to a Classic API path. Jamf Pro's Classic API accepts only XML data for these http methods.

 

Creating a new resource

This example shows how to use Jamf Pro's Classic API to create a new building. Because we're using a classic API path, we supply the data as XML.

jamfapi --method "POST" --path "/JSSResource/buildings" --data "<building><name>Apple Park</name></building>"

The Classic API's buildings path has a sibling in the more modern Jamf Pro API that can be used to accomplish the same thing. But where the Classic API uses XML input, the Jamf Pro API requires JSON. Note that because the data value contains double-quotes and spaces, we wrap the JSON in single quotes.

jamfapi --method "POST" --path "/api/v1/buildings" --data '{"name": "Apple Park"}'

That's probably the most readable way to do it, but if you want to use variables inside your JSON, you'll need to use double-quotes to wrap your JSON body because shells don't expand variables inside single quotes. The double-quotes within the JSON itself now need to be escaped.

BUILDING='Apple Park'

jamfapi --method "POST" --path "/api/v1/buildings" --data "{\"name\": \"${BUILDING}\"}"

Your code will probably be a lot easier to read if you use a here-doc when you need to assign more complicated XML or JSON to a script variable.

BUILDING='Apple Park'

read -r -d '' JSON <<EOF
{
  "name": "${BUILDING}"
}
EOF

jamfapi --method "POST" --path "/api/v1/buildings" --data "${JSON}"

 

Filtering, Sorting, and Pagination of Jamf Pro API results

To improve reliability, Jamf Pro API commands that return large numbers of records will return their results as a series of "pages" rather than attempting to return everything all at once. So a script that wants to process a large group of records typically requires some looping and logic to request multiple pages of data and concatenate the results. The jamfapi utility will take care of that for you, downloading all pages and returning them in a single response. However, if you want your script to process the chunks individually, you can include the pagination parameters in your URL.

This command will returns all computers, though behind the scenes, the API Utility is handling the page calls and concatenation:

jamfapi --path "/api/v1/computers-inventory"

There may be cases, especially if you have many thousands of devices, where you may prefer to receive paginated data so you can process records in batches. To do so, just include the pagination query parameters in your path. You can also include parameters to filter results and/or request that the results be sorted on the server-side, or include a "section" parameter to limit the response to only the kinds of data you need.

Query parameters are especially useful with the computers-inventory and its mobile-devices-detail sibling.

Returns all information for the first 100 computers:

jamfapi --path "/api/v1/computers-inventory?page=0&page-size=100"

Returns only the "General" section for the first 100 computers:

jamfapi --path "/api/v1/computers-inventory?page=0&page-size=100&section=GENERAL"

Returns Network and Hardware information for the first page of 100 mobile devices, sorted by room and device display name, and filtered to only return devices with model names beginning with "iPad":

PATH="/api/v2/mobile-devices/detail"
PATH+="?section=HARDWARE"
PATH+="&section=NETWORK"
PATH+="&page=1"
PATH+="&page-size=100"
PATH+="&sort=room%3Aasc"
PATH+="&sort=displayName%3Aasc"
PATH+="&filter=model%3D%3D%22iPad%2A%22'"

jamfapi --path "${PATH}"

 

Using cached credentials

When creating API targets in the GUI app, you have the option to require a Touch-ID whenever a script tries to access the target's connection information.

That's no problem when you're just making a lone API call in Terminal, but it not so good if your script is making lots of API calls. You'll probably just want to authenticate the first call and then let the remainder of the script run without interruption. We can do that using the --cacheLocalAuth "true" option on our jamfapi calls.

# The extension attribute to update on the devices...
EXTENSION_ATTRIBUTE_ID=23


# A list of the IDs for the device we want to update...
DEVICE_IDS=(7 14 23 31 42 55 63 77 86 99)

# Define the JSON payload with heredoc
read -r -d '' JSON <<EOF
{
  "definitionId": "${EXTENSION_ATTRIBUTE_ID}",
  "extensionAttributes": [
    {
      "values": [
        "foo"
      ]
    }
  ]
}
EOF

# Loop through each ID and make the jamfapi call

# The "pro" target requires a macOS user auth, so we'll be prompted for 
#  touch-ID the first time through the loop. The remainder of the API 
#  calls won't require any additional authentication. 

for ID in "${DEVICE_IDS[@]}"; do
  echo "Updating computer ID ${ID}"
  jamfapi \
    --target "pro" \
    --cacheLocalAuth "true" \
    --method "PATCH" \
    --path "/api/v1/computers-inventory-detail/${ID}" \
    --data "${JSON}"
done

# We're done, so remove the cached user authentication
jamfapi --target "pro" --cacheLocalAuth "false"
⚠️ **GitHub.com Fallback** ⚠️