Home > Jamf Pro > Uploading Logs to Jamf Pro with the API

Uploading Logs to Jamf Pro with the API

Something I learned early on while doing a large scale deployment is that it is really difficult to get logs off of computers when you either don’t have network access, or you have 10,000 Macs to get logs from. There have been plenty of discussions on Jamf Nation about logging for scripts or gathering logs from users (there has to be a better way than waiting on users to send the logs in).

Somewhere on Jamf Nation I found a method for using the Classic API to upload files to the computer record. This was great because now I could utilize any number of methods for logging data on the Mac and then uploading that to the computer record. This would put the log file close at hand so I could troubleshoot an issue without having to SSH into a machine or ask the user to send it to me.

Once you have figured out how you want to generate logs in your scripts (I’m partial to Dan Snelson’s method here), you’ll want to create a user that has access to upload files to the Jamf Pro Server. If you are a fan of encrypting the credentials you can go grab Jamf’s Encrypted Script Parameters scripts off of GitHub and use that code to scramble the creds. But, if you’re like many, simply creating a use specific user with privileges to do only what that account needs to do (upload files in this case) is sufficient security.

Jamf Pro Setup

So first step is to setup your user. Go into System Settings and then into Jamf Pro User Accounts & Groups on your JPS. Click the New button and choose to create a new Standard Account. Fill in the particulars like Username and Password, and set the Privilege Set to “Custom”:

Now go to the Privileges tab and enable Create, Read, and Update for File Attachments.

Now that we have our user created we can add the necessary API calls to our scripts to upload log files.

Add To Your Scripts

In any script that you wish to log output for, create a logging mechanism that saves to a local file on the system. We will not get into the specifics of which method is better than another. Instead I will show you a down and dirty method for capturing all output to a log file.

Once you have determined where to save the log file, you’ll want to make sure the path is available (unless you are putting this in a standard location like /var/log or even /tmp), and you’ll want to redirect output to the log or echo into the log. The following code will create a log file at /tmp/mylog/ and set the shell to output all commands using the UNIX ‘set’ command.

mylog=$mylogpath/myawesomlog-$(date +%Y%m%d-%H%M).log

[[ ! -d ${mylogpath} ]]; mkdir -p $mylogpath

set -xv; exec 1> $mylog 2>&1

That last line is the magic. That line enables shell debugging with verbosity and re-directs ‘stdout’ (1) and ‘stderr’ (2) into our log file. Anything that our script does below this part will be output to our log file.

Upload our Log

To upload our log file we need to know the JSS ID of the computer. This can be found in the JPS by looking at the URL of a computer or by looking for the “Jamf Pro Computer ID” on the General tab of the comptuer record. We’re going to use the computer serial number and the API to determine the ID.

We first grab the serial number from System Profiler:

serial=$(system_profiler SPHardwareDataType | awk '/Serial\ Number\ \(system\)/ {print $NF}');
view raw gistfile1.txt hosted with ❤ by GitHub

Now we make an API call to get the ID and use ‘xpath’ to sort it all out:

JSS_ID=$(curl -H "Accept: text/xml" -sfku "${jss_user}:${jss_pass}" "${jss_url}/JSSResource/computers/serialnumber/${serial}/subset/general" | xpath /computer/general/id[1] | awk -F'>|<' '{print $3}')
view raw gistfile1.txt hosted with ❤ by GitHub

update: macOS Big Sur introduces a new version of the ‘xpath’ binary, and with it a new format for the query. Rather than explain it here I’ll point you over to Armin Briegel’s excellent blog post about it here. So now instead of just having the above line, somewhere at the top of your script (or just before the line that uses ‘xpath’), you’ll want to have a function block to use the proper ‘xpath’ command based on macOS version. Follow Armin’s instructions in that post for where to put the block and what the block should look like.

Now that we have our ID we use a ‘curl’ call to the API to upload the log file:

curl -sku $apiUser:$apiPass $jpsURL/JSSResource/fileuploads/computers/id/$JSS_ID -F name=@${mylog} -X POST
view raw gistfile1.txt hosted with ❤ by GitHub

And just like that, we have a log file attached to the computer record for troubleshooting.

Computer Record

Where is this stored on the computer record? Well, it’s stored down towards the bottom of the tabs, just past the Printers tab on a tab called “Attachments”.

Screen Shot 2020-04-15 at 10.43.11 PM


That’s it, that’s all that has to be done to get a log file attached to your computer records. You can use this in any of your shell scripts to upload log files. You could even write a Self Service policy that users could run that would ship log files of your choice up to the computer record.

I hope you get something out of this and are able to see the power of this feature.

mylog=$mylogpath/myawesomlog-$(date +%Y%m%d-%H%M).log
[[ ! -d ${mylogpath} ]]; mkdir -p $mylogpath
set -xv; exec 1> $mylog 2>&1
... do some stuff ...
# Upload our log using API
# get computer serial number to lookup the JSS ID of the computer
serial=$(system_profiler SPHardwareDataType | awk '/Serial\ Number\ \(system\)/ {print $NF}');
# get ID of computer
JSS_ID=$(curl -H "Accept: text/xml" -sfku "${jss_user}:${jss_pass}" "${jss_url}/JSSResource/computers/serialnumber/${serial}/subset/general" | xpath /computer/general/id[1] | awk -F'>|<' '{print $3}')
# upload the log to the comptuer record
curl -sku $jss_user:$jss_pass $jpsURL/JSSResource/fileuploads/computers/id/$JSS_ID -F name=@${mylog} -X POST
view raw gistfile1.txt hosted with ❤ by GitHub
Categories: Jamf Pro Tags: , ,
  1. KB
    August 9, 2020 at 11:13 pm

    This is awesome! Can you fix line 23 – your variables are $api and $jps, however you’re calling them jss in lines 12-14. Took me a bit to figure out what I was doing wrong (I’m not super fluent, so feel free to ignore if I’m incorrect)

    • December 26, 2021 at 11:59 am

      Well, a year later, but thanks for finding that. Fixed the gist.

  2. Jeremy Dybash
    January 25, 2021 at 2:14 pm

    Steve, this is very useful and exactly what I was trying to do. This worked exactly as described. Thanks for clearly describing your approach and sharing with others!

    • January 25, 2021 at 2:49 pm

      Thanks Jeremy! Be sure to check out the edit I just made regarding the ‘xpath’ binary and macOS Big Sur.

  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: