Archive

Archive for the ‘AutoPkg’ Category

Building distribution packages using AutoPkg

February 4, 2024 Leave a comment

I’ve been thinking about the issue of building installer packages using AutoPkg which are ready for installation using MDM commands. Installing an installer package via MDM command requires packages to have the following attributes:

  1. Signed with an Apple Developer ID Installer certificate
  2. Be a distribution installer package

For criteria #2, this references the fact that there are two kinds of modern installer packages for macOS:

  • Component packages: these are the standard type of installer package, which contain an archive of files to install and the information on where the files should be installed.
  • Distribution packages: These packages can contain one or more component packages, and may also include additional resources to customize and control the user interface shown in the Installer application.

By default, AutoPkg will build component packages using the PkgCreator processor or the AppPkgCreator processor. But there is a relatively straightforward way to create a a distribution package while using an existing component package as a source, using the productbuild command. To create a distribution installer package from an existing component installer package, you would use a command similar to the one shown below:


/usr/bin/productbuild –package /path/to/package_being_converted_to_distribution.pkg /path/to/new_distribution_package.pkg

view raw

gistfile1.txt

hosted with ❤ by GitHub

Note: If using a signed component installer package as a source, the resulting new distribution package will not be signed. If needed, you will need to sign the distribution package following its creation.

For those who want to create distribution packages as part of an AutoPkg workflow, I’ve written a DistributionPackageCreator AutoPkg processor which is designed to perform the following tasks:

  1. Rename the existing AutoPkg-generated component package.
  2. Create a new distribution package from the AutoPkg-generated component package.
  3. Set the newly-created distribution package to have the original name of the AutoPkg-generated component package.

For more details, please see below the jump.

Read more…

Categories: AutoPkg, Packaging

Using AutoPkg to build a Cisco Secure Client installer

January 27, 2024 1 comment

Fraser Hess recently posted about automating the creation of Cisco Secure Client installers. Similar to my earlier post on using AutoPkg to build a Cisco AnyConnect installer, it’s possible to replicate this packaging workflow, including generating an installer choices XML file, using AutoPkg. For more details, please see below the jump.

Read more…

Categories: AutoPkg, Packaging

AutoPkg recipes for NexThink Collector

May 28, 2023 Leave a comment

A while back, I posted about how to build an installer for NexThink Collector, but my preference is to not do manual packaging if I can avoid it. Instead, my preference is to have AutoPkg handle packaging tasks whenever possible for the following reasons:

  1. I can ensure that the packaging task is handled the same way every time.
  2. Once I have the correct recipe written for AutoPkg, all I should need to do for future versions of the app is to run the AutoPkg recipe, wait a few minutes and then collect a properly-built installer.

With that in mind, I decided to revisit building an installer for NexThink Collector but this time build AutoPkg recipes which handle the following:

  1. Creating an installer package for NexThink Collector
  2. Creating an uninstaller for NexThink Collector

I was able to do this, so for those interested, please see below the jump for more details.

Read more…

Using AutoPkg to build installers for Palo Alto’s GlobalProtect VPN software

December 11, 2022 Leave a comment

As part of some recent testing, I needed to do some work with Palo Alto’s GlobalProtect VPN software. Palo Alto provides an installer package for GlobalProtect, but it has some interesting characteristics as the installer includes three installation options. One is enabled by default and the other two are disabled by default.

The first configuration is the option to install GlobalProtect, the default enabled configuration:

Screenshot 2022 12 08 at 3 47 44 PM

The second configuration is the option to uninstall GlobalProtect, which is disabled by default:

Screenshot 2022 12 08 at 3 49 18 PM

The third configuration is the option to enable the System Extension for GlobalProtect, which is disabled by default:

Screenshot 2022 12 08 at 3 50 35 PM

Note: In the image above, I’ve done some photoshopping because checking the third option to enable the System Extension for GlobalProtect also enables the option to install GlobalProtect. I made the change to the image to hopefully make more clear which option I was discussing.

The options to uninstall GlobalProtect and enable the System Extension for GlobalProtect can be managed by using an installer choices XML file to selectively enable only the desired option. For example, here’s the installer choices XML file for enabling only the option to uninstall GlobalProtect:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
<plist version="1.0">
<array>
<dict>
<key>attributeSetting</key>
<integer>1</integer>
<key>choiceAttribute</key>
<string>selected</string>
<key>choiceIdentifier</key>
<string>second</string>
</dict>
<dict>
<key>attributeSetting</key>
<integer>1</integer>
<key>choiceAttribute</key>
<string>selected</string>
<key>choiceIdentifier</key>
<string>com.paloaltonetworks.globalprotect.uninstall.pkg</string>
</dict>
</array>
</plist>

Here’s the installer choices XML file for enabling only the option to enable the System Extension for GlobalProtect:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
<plist version="1.0">
<array>
<dict>
<key>attributeSetting</key>
<integer>1</integer>
<key>choiceAttribute</key>
<string>selected</string>
<key>choiceIdentifier</key>
<string>third</string>
</dict>
<dict>
<key>attributeSetting</key>
<integer>1</integer>
<key>choiceAttribute</key>
<string>selected</string>
<key>choiceIdentifier</key>
<string>com.paloaltonetworks.globalprotect.systemext.pkg</string>
</dict>
</array>
</plist>

Using these options, I was able to build recipes for AutoPkg which would automatically build three installer packages:

  • An installer which installs GlobalProtect.
  • An installer which uninstalls GlobalProtect.
  • An installer which enables the System Extension for GlobalProtect.

The reason I chose to do this is that using AutoPkg to create these additional installer packages should help ensure any changes that Palo Alto makes to GlobalProtect’s uninstall and System Extension enablement will automatically be available whenever a new version of GlobalProtect is picked up by AutoPkg. In turn, this should save work for those deploying GlobalProtect because now they don’t need to figure out what may have changed between GlobalProtect releases. For more details, please see below the jump.

Read more…

autopkg-conductor updated to support reporting to Slack and Microsoft Teams

November 19, 2022 Leave a comment

When the autopkg-conductor tool was first written, one of its primary functions was to send the output of JSSImporter to a Slack channel. With JSSImporter being deprecated in favor of JamfUploader, I’ve decided to do the following:

  1. Drop support for JSSImporter.
  2. Add additional reporting options for JamfUploader.

As of the current version to the tool, autopkg-conductor can send output from JamfUploader to the following:

For more details, please see below the jump.

Read more…

Using AutoPkg to build a Cisco AnyConnect installer

May 23, 2022 Leave a comment

HCS Technology Group posted a white paper recently, showing how to deploy Cisco AnyConnect using Jamf Pro. As part of that documentation, HCS described how to create an installer choices XML file and then use it to create a custom Cisco AnyConnect installer package.

It’s possible to replicate this packaging workflow, including generating an installer choices XML file, using AutoPkg. For more details, please see below the jump.

Read more…

Categories: AutoPkg

Building a Privileges installer package using AutoPkg

April 20, 2022 Leave a comment

In working with folks who want to build installer packages to install the Privileges app, I’ve noticed that a number of them have experienced problems with manually building an installer package for Privileges which correctly installs the Privileges app’s helper tool.

The result of an installer which does not install the helper tool correctly is that when a user requests administrator privileges using the Privileges app, the app prompts them to install the helper tool. This requires administrative rights, which sets up a chicken and egg situation where admin privileges are being required to get admin privileges.

Screen Shot 2022 04 20 at 3 45 38 PM

Fortunately, there is an automated method for building the installer package which (so far) has worked correctly in each case I’m familiar with. There are AutoPkg recipes available for creating a Privileges installer package and AutoPkg is able to build a correctly working Privileges installer package.


computername:~ username$ autopkg search com.github.rtrouton.Privileges
Name Repo Path
—- —- —-
Privileges.munki.recipe apfelwerk-recipes Privileges/Privileges.munki.recipe
Privileges.install.recipe rtrouton-recipes Privileges/Privileges.install.recipe
Privileges.munki.recipe rtrouton-recipes Privileges/Privileges.munki.recipe
Privileges.jss.recipe rtrouton-recipes JSS/Privileges.jss.recipe
Privileges.pkg.recipe rtrouton-recipes Privileges/Privileges.pkg.recipe
Privileges.download.recipe rtrouton-recipes Privileges/Privileges.download.recipe
To add a new recipe repo, use 'autopkg repo-add <repo name>'
computername:~ username$

view raw

gistfile1.txt

hosted with ❤ by GitHub

For more details, please see below the jump.

Read more…

Using custom variables in an AutoPkg recipe to set version information

February 22, 2022 1 comment

As part of a recent task to build an AutoPkg recipe which creates an installer package for a screen saver, I ran into an issue. The vendor, for reasons that no doubt make sense to them, split the version information for the screen saver across two separate keys:

  • Major part of the version number: Stored in the CFBundleShortVersionString key of the screen saver’s Info.plist file
  • Minor part of the version number: Stored in the CFBundleVersion key of the screen saver’s Info.plist file

What this meant is that for version 1.4 of the screen saver, the version information was stored as follows:

  • CFBundleShortVersionString key: 1
  • CFBundleVersion key: 4

Getting this information was not the problem. AutoPkg includes a PlistReader processor which allows multiple values to be read from one plist file, so I used it as shown below to read the CFBundleShortVersionString key’s and the CFBundleVersion key’s values and store them in the following variables:

  • CFBundleVersion key: minor_version
  • CFBundleShortVersionString: major_version


<dict>
<key>Arguments</key>
<dict>
<key>info_path</key>
<string>%pathname%/Carousel Cloud.saver/Contents/Info.plist</string>
<key>plist_keys</key>
<dict>
<key>CFBundleVersion</key>
<string>minor_version</string>
<key>CFBundleShortVersionString</key>
<string>major_version</string>
</dict>
</dict>
<key>Processor</key>
<string>PlistReader</string>
</dict>

view raw

gistfile1.txt

hosted with ❤ by GitHub

So now I had the version info (in separate pieces) and now I needed to put them together. The problem I was seeing was that my usual solution, AutoPkg’s Versioner processor is set up to read one value from a plist file. I had two values and neither were in a plist file.

Fortunately, there are multiple ways to solve this problem. The first I thought of was to build a new plist as part of the recipe’s run and put the version information in. The workflow works like this:

1. Use the PlistReader processor to read the desired information.
2. Use the FileCreator processor processor to create a new plist file with the version information formatted as needed.
3. Use the PlistReader processor to read the version information out of the newly-created plist file.


<dict>
<key>Arguments</key>
<dict>
<key>info_path</key>
<string>%pathname%/Carousel Cloud.saver/Contents/Info.plist</string>
<key>plist_keys</key>
<dict>
<key>CFBundleVersion</key>
<string>minor_version</string>
<key>CFBundleShortVersionString</key>
<string>major_version</string>
</dict>
</dict>
<key>Processor</key>
<string>PlistReader</string>
</dict>
<dict>
<key>Processor</key>
<string>FileCreator</string>
<key>Arguments</key>
<dict>
<key>file_path</key>
<string>%RECIPE_CACHE_DIR%/com.companyname.carouselcloudscreensaver.plist</string>
<key>file_mode</key>
<string>0755</string>
<key>file_content</key>
<string>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
&lt;plist version="1.0"&gt;
&lt;dict&gt;
&lt;key&gt;complete_version&lt;/key&gt;
&lt;string&gt;%major_version%.%minor_version%&lt;/string&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</string>
</dict>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>info_path</key>
<string>%RECIPE_CACHE_DIR%/com.companyname.carouselcloudscreensaver.plist</string>
<key>plist_keys</key>
<dict>
<key>complete_version</key>
<string>version</string>
</dict>
</dict>
<key>Processor</key>
<string>PlistReader</string>
</dict>

view raw

gistfile1.txt

hosted with ❤ by GitHub

This approach works, but now you have a plist file to clean up later. Another approach is to use custom variable assigning as part of another AutoPkg processor’s run. In this case, you’re using an AutoPkg processor and adding a separate argument which is probably unrelated to the other work the processor is doing, but does the value assignment work you couldn’t accomplish otherwise.

A pretty safe processor to use for this is the EndOfCheckPhase processor. The reason is that by itself, the EndOfCheckPhase processor takes no actions. Instead, it’s used as a marker in AutoPkg recipes to tell AutoPkg to stop checking for new information as part of a recipe’s run. However, even though the EndOfCheckPhase processor doesn’t take actions and doesn’t by default include Arguments values, AutoPkg will still process Arguments values if they’re defined for the EndOfCheckPhase processor. That allows custom variables to be set with values that you couldn’t otherwise set and pass them to AutoPkg. The workflow in this case looks like this:

1. Add the EndOfCheckPhase processor to the very end of the recipe.
2. Perform the desired variable assignment as an Arguments value

The reason to add it to the end is to make sure that all of the other tasks the recipe is performing are completed by the time this processor runs.

In this case, I used this method with the the EndOfCheckPhase processor in the screen saver’s .download recipe to assign the version variable to use the values of the major_version and minor_version variables, separated by a period.


<dict>
<key>Processor</key>
<string>EndOfCheckPhase</string>
<key>Arguments</key>
<dict>
<key>version</key>
<string>%major_version%.%minor_version%</string>
</dict>
</dict>

view raw

gistfile1.txt

hosted with ❤ by GitHub

The result for the latest version of the screen saver software is that the version variable is assigned the following value:


'version': '1.4'

view raw

gistfile1.txt

hosted with ❤ by GitHub

I’ve posted the recipes which use this technique for setting version information to GitHub. They’re available via the link below:

https://github.com/autopkg/rtrouton-recipes/tree/master/CarouselCloudScreenSaver

Categories: AutoPkg, macOS

Using AutoPkg to get the latest Jamf Protect installer and uninstaller from your Jamf Protect tenant

February 17, 2022 Leave a comment

Jamf has enabled a new feature on Jamf Protect tenants, where you can generate a download URL for the latest Jamf Protect client installer and uninstaller. These download URLs do not require authentication, but a security identifier unique to the Jamf Protect tenant needs to be included as part of the download URL:

Screen Shot 2022 02 17 at 4 47 20 PM

Once generated, the download links are formatted similar to this:

Installer:

Screen Shot 2022 02 17 at 4 49 33 PM

 

Uninstaller:

Screen Shot 2022 02 17 at 4 51 30 PM

 

For example, if the Jamf Protect tenant and security identifier were as shown below, the curl commands would look like this:

  • Jamf Protect tenant: companyname.protect.jamfcloud.com
  • Security token: c1f0d1cb-8ddc-4f36-9578-58a7388053d5

Installer:

Uninstaller:

Since the Jamf Protect installer and uninstaller can be downloaded from your Jamf Protect tenant, this means that it’s now possible to use AutoPkg to get the latest Jamf Protect client installer and uninstaller as soon as they are available from your Jamf Protect tenant. For more details, please see below the jump.

Read more…

Categories: AutoPkg, Jamf Protect

autopkg-conductor updated to support both JamfUploaderSlacker and Slacker AutoPkg processors

February 12, 2022 Leave a comment

As part of my preparations for Jamf’s planned authentication changes to the Classic API, I’ve been working more with the JamfUploader AutoPkg processors for Jamf Upload. These processors have emerged as a successor to JSSImporter, the original tool available to upload installer packages and other components to Jamf Pro using AutoPkg.

As part of my work with Jamf Upload, I’ve also updated my autopkg-conductor script to allow the use of either Jamf Upload’s JamfUploaderSlacker AutoPkg processor or JSSImporter’s Slacker AutoPkg processors. For more details, please see below the jump.

Read more…