-
Notifications
You must be signed in to change notification settings - Fork 16
Working with Raw Data
Please be advised that this wiki page is deprecated. We have transitioned python-jamf
and jctl
to the jps-api-wrapper project for records interaction. Using jps-api-wrapper
, you can efficiently obtain information about devices, software, and other assets managed by Jamf Pro. Moreover, you can execute various actions, including sending MDM commands to computers and devices.
The information on the following wiki page will be retained for historical purposes.
There are no limitations when working with the raw data. The API
object has get, post, put, and delete methods. They interact with the Jamf Pro server using the get, post, put, and delete HTTP methods. The API
methods return raw data stored as Python dictionaries, arrays, and strings. To see all of the Jamf API endpoints that you can work with, go to the following URL on your server. https://example.com:8443/api
If you would like to try examples on this page, start a python REPL. You should know Python before trying these examples. If you don't know Python and you want to use jamf, please check out jctl.
python3
Import pprint
and jamf
and access the api object.
from pprint import pprint
import jamf
api = jamf.API()
The API
class is a singleton. So if you call jamf.API()
over and over and it will always return the same object. The reason behind this is so that you can access the api and any cached data from anywhere that imports the jamf
module. However, the API
class does not cache the data, the records class does. There might be room to improve this in the future (i.e. making the API not a singleton).
The downside of the API
class being a singleton is that you can not talk to multiple Jamf servers.
The API
get method downloads the associated data from the Jamf Pro server. If you store it in a variable, it does not update itself. If you make changes on the server, you’ll need to run the API
get method again to get the updated data.
Get any information from your Jamf Pro server using the classic API
endpoints. This includes nested dictionaries.
pprint(api.get('accounts'))
pprint(api.get('buildings'))
pprint(api.get('categories'))
pprint(api.get('computergroups'))
pprint(api.get('computers'))
pprint(api.get('departments'))
pprint(api.get('licensedsoftware'))
pprint(api.get('networksegments'))
pprint(api.get('osxconfigurationprofiles'))
pprint(api.get('packages'))
pprint(api.get('patches'))
pprint(api.get('policies'))
pprint(api.get('scripts'))
Get all categories and work with the nested dictionaries
categories = api.get('categories')['categories']['category']
category_names = [x['name'] for x in categories]
print(f"first category: {category_names[0]}")
pprint(category_names)
This example demonstrates using an id in the get request:
computers = api.get('computers')['computers']['computer']
pprint(computers[0])
pprint(api.get(f"computermanagement/id/{computers[0]['id']}"))
pprint(api.get(f"computermanagement/id/{computers[0]['id']}/subset/general"))
Getting computer groups and filtering using list comprehension filtering.
computergroups = api.get('computergroups')['computer_groups']['computer_group']
smartcomputergroups = [i for i in computergroups if i['is_smart'] == 'true']
pprint(smartcomputergroups)
staticcomputergroups = [i for i in computergroups if i['is_smart'] != 'true']
pprint(staticcomputergroups)
computergroupids = [i['id'] for i in computergroups]
pprint(computergroupids)
When creating a new data, in this case a static computer group, the id in the url ("1") is ignored and the next available id is used. The name in the url ("ignored") is also ignored and the name in the data ("realname") is what is actually used with the static computer group.
import json
api.post("computergroups/id/1",json.loads( '{"computer_group": {"name": "test", "is_smart": "false", "site": {"id": "-1", "name": "None"}, "criteria": {"size": "0"}, "computers": {"size": "0"}}}' ))
api.post("computergroups/name/ignored",json.loads( '{"computer_group": {"name": "realname", "is_smart": "false", "site": {"id": "-1", "name": "None"}, "criteria": {"size": "0"}, "computers": {"size": "0"}}}' ))
The following code changes the group "realname" created in the example above to "new name".
import json
api.put("computergroups/name/realname",json.loads( '{"computer_group": {"name": "new name", "is_smart": "false", "site": {"id": "-1", "name": "None"}, "criteria": {"size": "0"}, "computers": {"size": "0"}}}' ))
computergroups = api.get('computergroups')['computer_groups']['computer_group']
newgroup = [i for i in computergroups if i['name'] == 'new name']
And this is how to change the computer group name using the id.
api.put(f"computergroups/id/{newgroup[0]['id']}",json.loads( '{"computer_group": {"name": "newer name", "is_smart": "false", "site": {"id": "-1", "name": "None"}, "criteria": {"size": "0"}, "computers": {"size": "0"}}}' ))
The following example deletes the two groups we just created above:
api.delete("computergroups/name/test")
api.delete(f"computergroups/id/{newgroup[0]['id']}")
This is where the real power of jamf
comes in.
The following example searches all policies for the custom trigger "update_later" and replaces it with "update_now".
#!/usr/bin/env python3
import jamf
api = jamf.API()
all_policies = api.get('policies')['policies']['policy']
for policy_hook in all_policies:
policy = api.get(f"policies/id/{policy_hook['id']}")
name = policy['policy']['general']['name']
custom_trigger = policy['policy']['general']['trigger_other']
print(f"Working on {name}")
if (custom_trigger == "update_later"):
policy['policy']['general']['trigger_other'] = "update_now"
api.put(f"policies/id/{policy_hook['id']}", policy)
print(f"Changed custom trigger from {custom_trigger} to update_now")
The next example prints out the code you'd need to enter into a python3
interpreter to set the custom_triggers. Save the output of this script to a file, then edit the file with the custom triggers you want for each item. Delete the items you don't want to change.
#!/usr/bin/env python3
import jamf
api = jamf.API()
all_policies = api.get('policies')['policies']['policy']
print("""#!/usr/bin/env python3
import jamf
api = jamf.API()
""")
for policy_hook in all_policies:
policy = api.get(f"policies/id/{policy_hook['id']}")
custom_trigger = policy['policy']['general']['trigger_other']
print(f"print(f\"Working on {policy['policy']['general']['name']}\")\n"
f"policy = api.get(\"policies/id/{policy_hook['id']}\")\n"
f"policy['policy']['general']['trigger_other'] = "
f"\"{policy['policy']['general']['trigger_other']}\"\n"
f"api.put(\"policies/id/{policy_hook['id']}\", policy)\n\n")
Save the script named "custom_triggers_1.py" with the following commands:
./custom_triggers_1.py > custom_triggers_2.py
chmod 755 custom_triggers_2.py
Then edit "custom_triggers_2.py" with the custom triggers you want (and remove what you don't want to modify).
Then run "custom_triggers_2.py" script to make modifications.