Skip to content

2023 demo A Overview

Chris Lasell edited this page Aug 24, 2023 · 5 revisions

Hands On, Real-time Jamf APIs Using ruby-jss

Welcome to ruby-jss

TOC           Next


NOTE: 
  While there are two APIs, 'Classic' and 'Jamf Pro', ruby-jss takes care of most of 
  differences under the hood, so throughout this demo, I'll refer to both of them 
  collectively as 'the API'

Jamf Pro's REST API provides programmatic access to much of what's available in the Jamf Pro web interface.

While the API's existence is a boon for automating Jamf Pro-related tasks, using it via bash scripts can be unwieldy, hard to grasp, and difficult to troubleshoot and maintain.

ruby-jss is a framework or 'SDK' for the working with the API in the ruby programming language. It makes using the API much simpler, faster, and more fun.

Take, for example, the task of changing the assigned user for all computers in a smart group

bash:

GROUP_NAME='myGroupName'
NEW_COMPUTER_USER='jbleaux'
NEW_COMPUTER_USER_REAL_NAME='Jeaux Bleaux'

API_USER="api_username"
read -p "API pw for $API_USER: " api_pw

API_URL_BASE="https://jss.server:8443/"
CLASSIC_API_URL_BASE="$API_URL_BASE3/JSSResource"

authToken=$( /usr/bin/curl --request POST -silent --url "$API_URL_BASE/api/v1/auth/token" --user "$API_USER:$api_pw" )

token=$( /usr/bin/plutil -extract token raw - <<< "$authToken" )

raw_group_xml=$( curl -H 'Accept: application/xml' -sk --header "Authorization: Bearer $token" -X GET "${CLASSIC_API_URL_BASE}/computergroups/name/${GROUP_NAME}" )

member_count=`echo "$raw_group_xml" | xmllint --xpath 'count(/computer_group/computers/computer)' -`

for (( i=1; i <= $member_count; i++ )); do
  computer_id=`echo "$raw_group_xml" | xmllint --xpath "/computer_group/computers/computer[$i]/id/text()" -`
  change_xml="<computer><location><username>$NEW_COMPUTER_USER</username><realname>$NEW_COMPUTER_USER_REAL_NAME</realname></location></computer>"
  curl -H 'Content-Type: application/xml' -u "${API_USER}:${API_PW}" -X PUT "${API_URL_BASE}/computers/id/${computer_id}" -d "$change_xml"
done

ruby using ruby-jss:

require 'ruby-jss'

GROUP_NAME = 'myGroupName'
NEW_COMPUTER_USER = 'jbleaux'
NEW_COMPUTER_USER_REAL_NAME = 'Jeaux Bleaux'
API_USER = "api_username"

Jamf.connect "https://#{API_USER}@myjss.server:8443/"

computer_group = Jamf::ComputerGroup.fetch name: GROUP_NAME

computer_group.member_ids.each do |comp_id|
  computer = Jamf::Computer.fetch id: comp_id
  computer.username = NEW_COMPUTER_USER
  computer.real_name = NEW_COMPUTER_USER_REAL_NAME
  computer.save
end

Which one would your mother understand more easily?

Not only your mother, which one will you understand more easily in 2 years, when you need to make some changes to the script or adapt it for some other purpose? Or your co-workers who need to work with it while you're on vacation trekking in the Himalayas?


When using ruby-jss, you don't have to worry about the details like connection headers, tokens, parsing or formatting XML or JSON, GET vs PUT vs POST, the URL paths for related API items, and so on.

All of that is handled 'under the hood' for you. You can focus on the objects in your JSS - the computers, devices, groups, policies, packages, profiles, etc, and their properties and actions. Your code will reflect them and their attributes at a conceptual level, increasing writability, readability, and maintainability.

Ruby's syntax may be a bit different from Bash, but it isn't hard to learn, especially when you have API tasks to automate. If you have experience with Python or Javascript, it'll be even easier.

Not only will it be easier to write programs to automate repeated tasks, you can also use ruby-jss with Interactive Ruby, a.k.a. irb to act as a sort of live 'shell' to your Jamf Pro server. This allows you to easily perform all sorts of one-off tasks using the API in real-time.


TOC           Next

Clone this wiki locally