Archive

Archive for the ‘Scripting’ Category

Using the Jamf Pro API to delete computers from Jamf Pro

February 28, 2026 2 comments

Using printf to write variable values to JSON strings in Bash scripts

December 22, 2025 Leave a comment

As part of my personal changeover from using the Jamf Pro Classic API to using the Jamf Pro API, I’ve needed to change from using XML for the Jamf Pro Classic API to now using JSON for the Jamf Pro API. In particular, one of my issues has been figuring out how to properly write variables to JSON when updating something on the Jamf Pro server using the Jamf Pro API. As always when writing scripts, there’s usually multiple ways to solve a problem and I figured out a solution to mine using the printf command. For more details, please see below the jump.

Read more…

Updating management status in Jamf Pro computer inventory records using the Jamf Pro API

December 12, 2025 1 comment

A while back, I wrote a post on how to set Jamf Pro computer inventory records to be managed using a script. I recently revisited this script as part of a general effort on my part to update scripts which have been using the now-deprecated computers Classic API endpoint, to now use the Jamf Pro API’s computers-inventory-detail API endpoint.

As part of this effort, I decided to not only update my existing script for setting the management status in Jamf Pro computer inventory records to be managed but also write a second script for setting the management status to be unmanaged. For more details, please see below the jump.

Read more…

Using the mdfind command line tool to find duplicate copies of an application on macOS Sequoia

July 28, 2025 2 comments

A common issue faced by Mac admins is that users can have multiple copies of an application on their system. This can be the result of users having standard user rights and running applications out of the home directories, or users reorganizing the Applications directory in a way that makes more sense to them for their needs. Meanwhile, when Mac admins need to report on whether the apps on the fleet are up to date, these additional or reorganized apps may not be patched but do show up in the software reporting as being out of date.

When you run into these situations, how to handle them? The first step is finding where the duplicates are and reporting on them. To do this, you can use the mdfind command line tool, using the kMDItemCFBundleIdentifier metadata attribute. This metadata attribute reports on the bundle identifier used by an application, so it should pick up all copies of an app which are using that unique identifier for that app. For more details, please see below the jump.

Read more…

Payload-Free Package Creator 2.5 now available

July 15, 2025 Leave a comment

Payload-Free Package Creator.app, an Automator application that allows the selection of an existing script and then creates a payload-free package that runs the selected script, has been updated to version 2.5.

The user experience and operations of the app have not changed from previous versions of Payload-Free Package Creator.app. The changes to Payload-Free Package Creator 2.5 are the following:

  • Payload-Free Package Creator.app creates distribution installer packages using productbuild in place of the previous method, which used pkgbuild to create component installer packages.
  • Payload-Free Package Creator.app is signed with current Developer ID: Application certificate.
  • Payload-Free Package Creator.app is notarized.
  • Installer package is now signed with current Developer ID: Installer certificate.
  • Installer package is notarized.

Payload-Free Package Creator 2.5, along with all components and scripts, is available on GitHub via the link below:

https://github.com/rtrouton/Payload-Free-Package-Creator

You can download the Payload-Free Package Creator 2.5 installer via the GitHub release page for Payload-Free Package Creator 2.5:

https://github.com/rtrouton/Payload-Free-Package-Creator/releases/tag/2.5

Using the Jamf Pro API to download IPA files from a JCDS2 distribution point

A while back, I wrote about how you could use the Jamf Pro API to download installer packages from a JCDS2 distribution point

However, installer packages are not the only items which may be stored on a JCDS2 distribution point. The IPA files used by in-house iOS, iPadOS and tvOS devices may also be stored for distribution on a JCDS2 distribution point. IPA files stored on a JCDS2 distribution point can be accessed for download in the same way that installer packages can.

 

For those who want to use this capability, I’ve written a script which uses the Jamf Pro Classic API and Jamf Pro API to get the list of IPA files on a Jamf Pro server, retrieve the associated download links and download the IPA files to a directory on my Mac. For more details, please see below the jump.

Read more…

Jamf Pro Classic API computer inventory endpoint deprecated as of Jamf Pro 11.15.0

March 21, 2025 5 comments

As part of the release of Jamf Pro 11.15.0, the computers Classic API endpoint is being deprecated. This endpoint has been used to gather and update information on managed macOS computers for more than 10 years, but it is being replaced over time by the Jamf Pro API’s computers-inventory API endpoint. For more information, please see the link below:

https://developer.jamf.com/jamf-pro/docs/deprecation-of-classic-api-computer-inventory-endpoints

To minimize the disruption caused by this change, there will be a one year period of continued support for the computers Classic API endpoint in order to give folks time to switch to using the computers-inventory Jamf Pro API endpoint.

Probably the biggest adjustment for most folks will be that while the Classic API supports providing output in both XML and JSON, the Jamf Pro API only provides output in JSON. Another change is that the computers-inventory API endpoint supports lookup by Jamf Pro ID number and does not currently offer the ability to directly lookup devices by providing the serial number, MAC address or the other criteria offered by the computers Classic API endpoint. That said, the computers-inventory API endpoint does offer a number of filtering options, including the ability to filter by serial number to get the Jamf Pro ID of a device. For more information, please see below the jump.

Read more…

Determining update source for Microsoft Office 365 applications

March 6, 2025 5 comments

On macOS, Microsoft has made its Office 365 applications available via three different channels:

  • Directly from Microsoft (available for folks via office.com and other Microsoft resources.)
  • Apple’s Mac App Store (available for folks using their personal Apple Accounts)
  • Apple’s Volume Purchase program (available via Apple Business Manager and Apple School Manager)

In turn, this means updates for these apps may be coming from a variety of sources:

Depending on how tightly an organization controls the ability of its users to install applications, it’s possible to have a scenario like this:

  • Microsoft Excel: Installed using an installer from Microsoft’s office.com site.
  • Microsoft Outlook: Installed using a personal Apple Account from the Mac App Store.
  • Microsoft Word: Installed by the organization’s MDM using a Volume Purchase license.

This can lead to challenges with keeping the apps updated, since there are three different update mechanisms for the three separate apps.

  • Microsoft Excel: Updates coming via Microsoft’s AutoUpdate application.
  • Microsoft Outlook: Updates coming via the Mac App Store.
  • Microsoft Word: Updates coming via commands sent by the organization’s MDM service to the managed device which tell the managed device to connect back to Apple and get the latest update.

To help with figuring this out, it’s possible to query the application’s metadata using the mdls command line tool to see if the app has an associated App Store receipt. If it does, it’s possible to further figure out if the App Store receipt in question is for a Volume Purchase program (VPP) license or for a Mac App Store (MAS) license.

To check, you can run the following command and examine the output you get back:


/usr/bin/mdls -name kMDItemAppStoreReceiptType /path/to/application_name_goes_here.app | awk '{print $3}' | tr -d '"'

view raw

gistfile1.txt

hosted with ❤ by GitHub

For example, here’s the output you should see for Microsoft Outlook.app installed using an installer from office.com or other Microsoft resources:


username@computername ~ % /usr/bin/mdls -name kMDItemAppStoreReceiptType "/Applications/Microsoft Outlook.app" | awk '{print $3}' | tr -d '"'
(null)
username@computername ~ %

Note: The (null) result is because the app does not have an associated App Store receipt.

Here’s the output you should see for Microsoft Outlook.app installed via the Mac App Store by someone using their personal Apple Account:


username@computername ~ % /usr/bin/mdls -name kMDItemAppStoreReceiptType "/Applications/Microsoft Outlook.app" | awk '{print $3}' | tr -d '"'
Production
username@computername ~ %

Here’s the output you should see for Microsoft Outlook.app installed by an organization’s MDM using a Volume Purchase license:


username@computername ~ % /usr/bin/mdls -name kMDItemAppStoreReceiptType "/Applications/Microsoft Outlook.app" | awk '{print $3}' | tr -d '"'
ProductionVPP
username@computername ~ %

For more information, please see below the jump.

Read more…

Using Privileges post-actions

December 1, 2024 4 comments

One of the options available in Privileges 2.x is the capability of running an action once admin rights have been granted or removed.

This action can be launching an app or running a script and is set by the Run after privilege change setting.

This action can be further customized by choosing to only run the action once admin rights have been granted. This can be set by the Run only if administrator privileges have been granted setting.

Something to be aware of is that when using an action is that the script or application in question will be run within the context of the logged-in user. This means it will have the same level of access rights that the logged-in user currently has (standard versus admin.) This may be important if running the script or launching the application includes functionality which works for a user with admin rights but not for a user with standard rights. An example of this is running the following command using the log command line tool:


log show –style syslog –predicate 'process BEGINSWITH "Privileges"' –last 1m

view raw

gistfile1.txt

hosted with ❤ by GitHub

If the logged-in user has admin rights, the log command shown above runs without issues and without requesting authentication.

If the logged-in user has standard rights, you get an error that the log command operation is not permitted.

Privileges 2.x includes management options for setting post-actions, so that their operation and configuration can be set using configuration profiles. For more details, please see below the jump.

Read more…

Using certificate public keys to create dummy MDM configuration profiles for Jamf Pro device smart group scoping

October 14, 2024 Leave a comment

My teammates at Jamf who support Jamf’s own IT (known as Jamf @ Jamf) have developed an innovative method for allowing computer and mobile device smart groups to figure out device membership based on users and groups from an identity provider (like Okta or Entra ID) or an LDAP service (like Active Directory).

Normally, figuring out user and group membership is not a capability of computer and mobile device smart groups but the method the Jamf @ Jamf folks developed leverages MDM configuration profiles to bridge that functionality gap in the following way:

  1. User is assigned an application with compliance policy in the organization’s identity provider.
  2. A Jamf @ Jamf automation system adds User Extension Attribute criteria to a username in scope of a group provided by the identity provider.
  3. A smart user group in Jamf Pro uses that criteria to populate group membership.
  4. The new smart user group is used to scope a configuration profile.

The configuration profile referenced in step 4 above is then deployed to devices that match the smart user group’s membership. Once the profile is deployed, the profile being installed on a device is criteria which can be used by computer and mobile device smart groups. This allows the profile to be the bridge functionality to connect users and user groups from an identity provider or an LDAP service.

In the post I linked to earlier, the configuration profiles created for this purpose are referred to as “dummy profiles”, which are in turn a reference to “dummy receipts”. Dummy receipts are a method for creating a receipt for an installer package installed by Jamf Pro, which likewise can be used as criteria which can be used by computer smart groups.

But what goes in that dummy profile? Ideally, it should be something that deploys no settings at all. The dummy profile’s existence on a device is enough to accomplish the goal of bridging the gap between user and device scoping and for the sake of causing no complications, the profile should exist on the device and otherwise do nothing. Meanwhile, this should be an approach which can be used on all Apple platforms so we need something which can be deployed to all Apple platforms.

After thinking about this for a bit and discussing it with colleagues, it looks like the best way to accomplish this is to build a configuration profile with the following characteristics:

  1. Profile with certificate payload
  2. Certificate payload should have the following:
  • Self-signed certificate’s public key
  • Certificate lifespan should be set to an extended period of time, to allow the use of the profile over a long period of time without worrying about the certificate expiring.

The reason to use a self-signed certificate’s public key is that a certificate can only be used for something if you have both the public and private key available. Without the private key being available at some point in the communication process to authenticate the public key as being valid, the public key is effectively useless.

In this case, that’s exactly what we want – we want something useless in the profile’s certificate payload because something useless can’t be used! Using this approach will mean that our configuration profile will deploy no settings to a Mac or mobile device, and a malicious third party won’t be able to use the certificate either because only the public key for it will be available. For more details, please see below the jump.

Read more…