JamfUploader Templates - grahampugh/jamf-upload GitHub Wiki

The following processors rely on XML template files in addition to any required variables:

  • JamfComputerGroupUploader
  • JamfPolicyUploader
  • JamfPatchUploader
  • JamfComputerProfileUploader
  • JamfMacAppUploader

An easy way to create a new template is to create an object in the Jamf Pro GUI, and then download it using the API.

How to download an API object

The easiest way to download a Policy or Smart Group is using ExportJamfXML.html by Gabriel Sroka. This is a web browser extension that allows you to download the XML directly from the GUI page of the object you want.

Other ways to download an API object are using Postman or the command line. You'll need to do this for API object types other than Smart Groups and Policies. To download an object, you first need to generate a Bearer Token (requires Jamf Pro 10.35 or above). Use the following command to obtain a Bearer Token. You can use the same account username and password that you are using with JamfUploader.

curl --request POST --user username:password --silent https://server.name.here/api/v1/auth/token | plutil -extract token raw –

(Source: Der Flounder)

Once you have the token, you can obtain an API item with the following command. You will need to substitute your Jamf Pro URL, the BEARER_TOKEN, the API_OBJECT_TYPE and supply the ID of the item you want to download:

curl --request GET --silent --header "authorization: Bearer BEARER_TOKEN" --header 'Accept: application/xml' https://server.name.here/JSSResource/API_OBJECT_TYPE/id/SOME_ID" --output "/path/to/APIFile.xml"

The appropriate object types are as follows:

Processor API_OBJECT_TYPE
JamfComputerGroupUploader computergroups
JamfPolicyUploader policies
JamfPatchUploader patchpolicies
JamfComputerProfileUploader osxconfigurationprofiles
JamfMacAppUploader macapplications

Example:

curl --request GET --header "authorization: Bearer PASTEDTOKENHERE" --header 'Accept: application/xml' https://server.name.here/JSSResource/policies/id/133 | xmllint - > "~/Downloads/Policy133APIFile.xml"

How to convert a downloaded API object file into a template

Converting a downloaded API object file into a template involves three stages:

  • Remove all id keys
  • Remove unnecessary sections
  • Replace unique names with variables

Editing the XML is a lot easier if you use xmllint to format it. Use the following command to do this:

xmllint --format "/path/to/APIFile.xml" > "/path/to/FormattedAPIFile.xml"

Click here for an example downloaded Policy XML file.

Remove id keys

All id keys need to be removed from the file. Providing id values are not necessary when uploading, and uploads will fail if they are not removed. So remove all id tags completely (note there are no id keys in Smart Groups):

e.g. Before:

    <category>
      <id>2</id>
      <name>Testing</name>
    </category>

After:

    <category>
      <name>Testing</name>
    </category>

Remove unnecessary sections

You only need to provide a small number of keys that are essential to the API object. Everything else can be removed, with the slight caveat that if values in a section had previously been provided, and you remove the entire section before uploading the template to the same ID, the earlier values will remain. You can instead provide an empty tag for that section (Note: there are no unnecessary sections in Smart Groups).

As an example, we will look at the downloaded "Install Latest Adium" policy we linked to above. Here is the user_interaction section:

  <user_interaction>
    <message_start/>
    <allow_users_to_defer>false</allow_users_to_defer>
    <allow_deferral_until_utc/>
    <allow_deferral_minutes>0</allow_deferral_minutes>
    <message_finish/>
  </user_interaction>

If we don't need to set any non-default values in this section, we can delete all these lines. Or, to be extra sure to remove any earlier non-default values, we can replace it with this:

  <user_interaction/>

It's quite common to reduce the keys to a bare minimum. The general section can often be reduced to:

  <general>
    <name>Install Latest Adium</name>
    <enabled>true</enabled>
    <trigger>USER_INITIATED</trigger>
    <frequency>Ongoing</frequency>
    <category>
      <name>Testing</name>
    </category>
  </general>

The scope section may be reduced to:

  <scope>
    <all_computers>false</all_computers>
    <computers/>
    <computer_groups>
      <computer_group>
        <name>Adium-update-smart</name>
      </computer_group>
    </computer_groups>
    <exclusions>
      <computers/>
      <computer_groups/>
    </exclusions>
  </scope>

Or if the policy is to be scoped to all computers, this section can simply be:

  <scope>
    <all_computers>true</all_computers>
  </scope>

Self Service policies can have the self_service section reduced to the following. Note that the self_service_icon section should be removed, because you cannot supply a policy icon directly from a URL (this is handled separately in the JamfPolicyUploader processor - you have to put the icon in your repo):

  <self_service>
    <use_for_self_service>true</use_for_self_service>
    <self_service_display_name>Adium</self_service_display_name>
    <install_button_text>Install 1.5.10.4</install_button_text>
    <reinstall_button_text>Reinstall 1.5.10.4</reinstall_button_text>
    <self_service_description>Popular instant messaging client supports a plethora of services.</self_service_description>
    <force_users_to_view_description>false</force_users_to_view_description>
    <feature_on_main_page>false</feature_on_main_page>
    <self_service_categories>
      <category>
        <name>Testing</name>
        <display_in>true</display_in>
        <feature_in>false</feature_in>
      </category>
    </self_service_categories>
    <notification>false</notification>
    <notification>Self Service</notification>
    <notification_subject/>
    <notification_message/>
  </self_service>

Package configuration:

  <package_configuration>
    <packages>
      <size>1</size>
      <package>
        <name>Adium-1.5.10.4.pkg</name>
      </package>
    </packages>
  </package_configuration>

Scripts (if there are none):

  <scripts>
    <size>0</size>
  </scripts>

And maintenance (if you want a recon after the policy runs):

  <maintenance>
    <recon>true</recon>
  </maintenance>

Click here to see the final edited policy.

Replace unique names with variables

Of course, to become a template, we need to remove the values specific to the item we downloaded and replace them with variables. In AutoPkg, variables are wrapped with percent signs, for example %POLICY_NAME%. So, to replace our unique policy name and category with variables:

Before:

  <general>
    <name>Install Latest Adium</name>
    <enabled>true</enabled>
    <frequency>Ongoing</frequency>
    <category>
      <name>Testing</name>
    </category>
  </general>

After:

  <general>
    <name>%POLICY_NAME%</name>
    <enabled>true</enabled>
    <frequency>Ongoing</frequency>
    <category>
      <name>%POLICY_CATEGORY%</name>
    </category>
  </general>

The package name is provided as follows, since the pkg_name variable is supplied by a parent .pkg recipe:

  <package_configuration>
    <packages>
      <size>1</size>
      <package>
        <name>%pkg_name%</name>
      </package>
    </packages>
  </package_configuration>

Any desired version strings can be replaced with %version%, which should also have been provided in a parent recipe. For example:

    <install_button_text>Install %version%</install_button_text>
    <reinstall_button_text>Reinstall %version%</reinstall_button_text>

Click here for the same policy template with all values substituted for variables. This file is now ready for use as your policy template.

<?xml version="1.0" encoding="UTF-8"?>
<policy>
  <general>
    <name>%POLICY_NAME%</name>
    <enabled>true</enabled>
    <frequency>Ongoing</frequency>
    <category>
      <name>%POLICY_CATEGORY%</name>
    </category>
  </general>
  <scope>
    <all_computers>false</all_computers>
    <computers/>
    <computer_groups>
      <computer_group>
        <name>%GROUP_NAME%</name>
      </computer_group>
    </computer_groups>
    <exclusions>
      <computers/>
      <computer_groups/>
    </exclusions>
  </scope>
  <self_service>
    <use_for_self_service>true</use_for_self_service>
    <self_service_display_name>%SELF_SERVICE_DISPLAY_NAME%</self_service_display_name>
    <install_button_text>Install %version%</install_button_text>
    <reinstall_button_text>Reinstall %version%</reinstall_button_text>
    <self_service_description>%SELF_SERVICE_DESCRIPTION%</self_service_description>
    <force_users_to_view_description>false</force_users_to_view_description>
    <feature_on_main_page>false</feature_on_main_page>
    <self_service_categories>
      <category>
        <name>%POLICY_CATEGORY%</name>
      </category>
    </self_service_categories>
  </self_service>
  <package_configuration>
    <packages>
      <size>1</size>
      <package>
        <name>%pkg_name%</name>
      </package>
    </packages>
  </package_configuration>
  <scripts>
    <size>0</size>
  </scripts>
  <maintenance>
    <recon>true</recon>
  </maintenance>
</policy>

Where to store templates

JamfUploader processors will look in the following locations for your templates (in this order):

  1. The RecipeOverrides directory/ies
  2. The same directory as the recipe
  3. Anywhere in the same repo as the recipe (the repo must be in the RECIPE_SEARCH_DIRS).
  4. Anywhere in the parent recipe's repo, if recipe is an override (the repo must be in the RECIPE_SEARCH_DIRS).
⚠️ **GitHub.com Fallback** ⚠️