A while back, I had to build an installer for NexThink Collector which could be deployed via Jamf Pro. NexThink can be interesting to deploy because the installation process:
Involves an application named csi.app, which has a command line tool.
The referenced csi app’s command line tool configures and runs an installer package.
The command line tool also needs to reference a license file, which NexThink refers to as a CustomerKey file.
The CustomerKey file should look similar to what’s shown below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
All the needed components with the exception of the CustomerKey file, which is different for each customer, ship on a disk image.
NexThink’s install documentation for the macOS version of the Collector software assumes that a human is doing one of the following:
Graphical installation: Mounting the disk image, double-clicking on the installer package and following the prompts, entering the correct configuration information were needed.
Command line installation: Mounting the disk image, opening the Terminal application and using the csi app’s command line tool to configure the installer package and run the installation process.
For the Enterprise Deployment section of the application, the NexThink documentation says they support it but doesn’t provide information on how to do it.
In my case, I decided to do the following to deploy it via Jamf Pro:
Wrap the disk image and CustomerKey file inside a separate installer package.
Use a postinstall script to perform the following actions:
A. Identify the location of the disk image stored inside the installer package.
B. Mount the disk image
C. Identify the location of the csi.app on the mounted disk image.
D. Identify the location of the CustomerKey file stored inside the installer package.
E. Use the csi app’s command line tool to configure and run the NexThink-provided installer package on the mounted disk image, to install the NexThink Collector software.
F. Unmount the disk image.
For more details, please see below the jump.
Note:The details of installing and configuring NexThink are going to vary between shops, because different shops are going to configure different options for NexThink. Please consider what’s shown below as a general example, not something that will work for all environments.
Vendor-provided NexThink disk image with the NexThink Collector installer for macOS
Vendor-provided CustomerKey text file
Before building the package, you’ll need to create a directory named CustomerKeys somewhere convenient.
Once the CustomerKeys directory has been created, add the CustomerKey file to it. The CustomerKey file is a plaintext file, where the filename must end in the .txt file extension. For this example, the CustomerKey file is named Company-Name-customer-key.txt.
Building the NexThink Collector installer
1. Set up a new Packages project and select Raw Package.
2. In this case, I’m naming the project NexThink Collector Install 22.9.1.14.
3. Once the Packages project opens, click on the Project tab. You’ll want to make sure that the your information is correctly set here (if you don’t know what to put in, check the Help menu for the Packages User Guide. The information you need is in Chapter 4 – Configuring a project.)
In this example, I’m not changing any of the options from what is set by default.
4. Next, click on the Settings tab. In the case of my project, I want to install with root privileges and not require a logout, restart or shutdown.
To accomplish this, I’m choosing the following options in the Settings section:
In the Tag section:
Identifier: set as appropriate (for my installer, I’m using com.nexthink.pkg.collector)
Version: set as appropriate (for my installer, I’m using 22.9.1.14 )
In the Post-installation Behavior section:
On Success: should be set to Do Nothing.
In the Options section:
Require admin password for installation should be checked
Relocatable should be unchecked
Overwrite directory permissions should be unchecked
Follow symbolic links should be unchecked
5. Select the Payload tab. Nothing here should be changed from the defaults.
6. Select the Scripts tab.
Under the Additional Resources section, add the following file and directory:
The NexThink disk image
The CustomerKeys directory containing the CustomerKey file.
The last part is telling the NexThink installer to run, using the csi app’s command line tool. For this, you’ll need a postinstall script.
Here’s the postinstall script being used for this example installer package:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If not already selected, select the postinstall script and add it to the project.
Note:The options shown in the postinstall script for configuring NexThink are not going to work for all shops, because different shops are going to configure different options for NexThink. Please consider what’s shown above as a general example, not something that will work for all environments.
For more details on the available configuration options, please see the Command-line installation section of the NexThink documentation available via the link below:
7. Build the package. (If you don’t know to build, check the Help menu for the Packages User Guide. The information you need is in Chapter 3 – Creating a raw package project and Chapter 10 – Building a project.)
Testing the installer
Once the package has been built, test it by installing it on a test machine which has the following:
Does not have the NexThink Collector software installed
The end result should be that the NexThink Collector software installs onto the Mac and is registered with the NexThink server.
As a follow-up to my previous post on building an installer for NexThink Collector which could be deployed via Jamf Pro, I also needed to build an uninstaller for this software. Fortunately, NexThink ships an uninstaller script on the same disk image that it uses to ship its installer.
NexThink’s install documentation for the macOS version of the Collector software assumes that a human is doing the following to run the uninstall process:
A. Mounting the disk image B. Opening the Terminal application C. Using the uninstaller script to run the uninstallation process.
In my case, I decided to do the following to deploy the uninstaller via Jamf Pro:
Wrap the disk image inside a separate installer package.
Use a postinstall script to perform the following actions:
A. Identify the location of the disk image stored inside the installer package. B. Mount the disk image C. Use the uninstall script to uninstall the NexThink Collector software. D. Unmount the disk image.
Vendor-provided NexThink disk image with the NexThink Collector uninstaller script
Building the NexThink Collector uninstaller
1. Set up a new Packages project and select Raw Package.
2. In this case, I’m naming the project NexThink Collector Uninstaller 22.9.1.14.
3. Once the Packages project opens, click on the Project tab. You’ll want to make sure that the your information is correctly set here (if you don’t know what to put in, check the Help menu for the Packages User Guide. The information you need is in Chapter 4 – Configuring a project.)
In this example, I’m not changing any of the options from what is set by default.
4. Next, click on the Settings tab. In the case of my project, I want to install with root privileges and not require a logout, restart or shutdown.
To accomplish this, I’m choosing the following options in the Settings section:
In the Tag section:
Identifier: set as appropriate (for my uninstaller, I’m using com.nexthink.pkg.collector.uninstaller.)
Version: set as appropriate (for my uninstaller, I’m using 22.9.1.14. )
In the Post-installation Behavior section:
On Success: should be set to Do Nothing.
In the Options section:
Require admin password for installation should be checked
Relocatable should be unchecked
Overwrite directory permissions should be unchecked
Follow symbolic links should be unchecked
5. Select the Payload tab. Nothing here should be changed from the defaults.
6. Select the Scripts tab.
Under the Additional Resources section, add the following file:
The NexThink disk image
The last part is telling the NexThink uninstall script to run. For this, you’ll need a postinstall script.
Here’s the postinstall script being used for this example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If not already selected, select the postinstall script and add it to the project.
7. Build the package. (If you don’t know to build, check the Help menu for the Packages User Guide. The information you need is in Chapter 3 – Creating a raw package project and Chapter 10 – Building a project.)
Testing the installer
Once the package has been built, test it by installing it on a test machine which has the following:
The NexThink Collector software installed
The end result should be that the NexThink Collector software is removed from the Mac.
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:
The second configuration is the option to uninstall GlobalProtect, which is disabled by default:
The third configuration is the option to enable the System Extension for GlobalProtect, which is disabled by default:
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Here’s the installer choices XML file for enabling only the option to enable the System Extension for GlobalProtect:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.
There is an existing AutoPkg .download recipe for GlobalProtect, available via the link below:
Since that part of the recipe setup is already done, I focused on building AutoPkg .pkg recipes. For the example recipe shown below which handles creating the installer which installs GlobalProtect, the recipe won’t make any changes to the downloaded installer package beyond renaming it. This is because by default, the GlobalProtect installer package installs GlobalProtect.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
<string>Downloads the latest version of Palo Alto's GlobalProtect installer package and renames the package with version. Requires the use of HOSTNAME to point at your GlobalProtect instance. Use pkg_path in parent recipes for package with version.</string>
The second and third .pkg recipes will wrap the downloaded installer package inside a second installer package, along with the following files which will also be stored in the second installer package:
An installer choices XML file
A postinstall script which will install the downloaded installer using the options configured by the installer choices XML file.
AutoPkg recipe to create an installer package which uninstalls GlobalProtect:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
<string>Downloads the current release version of the Global Protect VPN client and builds an installer package which uninstalls Global Protect.</string>
AutoPkg recipe to create an installer package which enables the System Extension for GlobalProtect:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
<string>Downloads the current release version of the Global Protect VPN client and builds an installer package which enables the Global Protect system extension.</string>
Upgrading to macOS Ventura from macOS Monterey or earlier seems like it should be a straightforward process.
1. Open System Preferences
2. Click on Software Update.
3. If the macOS Ventura upgrade is listed there, click on the Upgrade Now button.
However, you may get different upgrade experiences depending on whether you are running macOS 12.3 or later, or if you’re running macOS 12.21 or earlier.
macOS 12.3 or later:
1. You see a macOS Ventura installer which is around 6 GBs or less.
2. When you click Upgrade Now, you are asked to authenticate as a user. Not as a user with administrator privileges, just as a user.
macOS 12.21 or earlier
1. You see a macOS Ventura installer which is around 12 GBs or more.
2. It downloads an Install macOS Ventura app to your Mac and installs it in /Applications.
3. The Install macOS Ventura app automatically launches once download and installation of the application completes.
4. Running the Install macOS Ventura app will prompt for a user with administrator privileges to authenticate before the upgrade proceeds.
Why the difference? The reason is that Apple has developed a new software upgrade path to macOS Ventura for Macs running macOS 12.3 or later which doesn’t require the following:
The need to run the macOS Ventura full installer
The requirement to authenticate as an administrator before upgrading from macOS Monterey to macOS Ventura.
Apple did include additional logic for macOS Ventura upgrades for upgrading to Ventura 13.0.0 and 13.0.1, where if a Mac running macOS Monterey 12.3 or later was enrolled with an MDM management solution and was thus in supervised mode, the new software upgrade path was disabled for those Macs.
As of the release of macOS 13.1, this logic no longer applies and supervised Macs may be offered the new upgrade path (which doesn’t require admin rights to upgrade.)
For more details about this, and information on how to block the macOS Ventura upgrade from appearing in Software Update if your organization needs more time, please see the Apple KBase article linked below:
My colleague Robert Hammen has also written on the topic of delaying upgrades, so if you’re interested in that topic, please see his Medium post linked below:
Every so often, it may be necessary for Mac admins to deploy a script that can apply different settings to Mac desktops and laptops. A good example may be using the pmset command to apply Energy Saver settings, where you may want to apply one set of power management settings to laptops and a different set to desktops.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
In the example above, the Model Identifier information from the system_profiler command is used to help identify if the Mac is a desktop or laptop. In this case, the Model Identifier information is checked to see if the model identifier contains “Book”.
If it does, it’s a laptop. Otherwise, it’s a desktop:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
What’s an alternative way to check? One way is to use the ioreg command to see if the Mac in question has a built-in battery or not. Laptops will have a built-in battery and desktops will not. For more details, please see below the jump.
You can use the ioreg command shown below to query the information for the AppleSmartBattery hardware driver (currently used by macOS for its battery management) and check whether the Mac has a built-in battery or not:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
On a laptop, the following command should return Yes:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
On a desktop, the same command should return no output:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You should be able to use this command to update the example script for setting power management to correctly identify laptops vs. desktops again:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Note:The AppleSmartBattery hardware driver is being queried by the ioreg command to gather this information. If Apple ever changes the name or the functionality of the AppleSmartBattery hardware driver, this method may stop working and need to be updated for the new name or functionality.
As mentioned previously, Charles Edge and I are releasing a new Second Edition of our Apple Device Management book. I’m delighted to announce it’s available for pre-ordering on Amazon via the link below:
This quality publication, just like First Edition, is stuffed with useful information, sure to be a collectors’ item and suitable for any gift-giving occasion. Please order yours today!
macOS on Apple Silicon Macs includes a concept known as volume ownership. You must be a volume owner to perform the following tasks on an Apple Silicon Mac:
How do you get volume ownership though? It turns out that Apple has this currently set up on macOS as a two-fer deal: If an account account has Secure Token, it is also granted volume ownership. For more details, please see below the jump.
To see which users on the Mac have Secure Token, run the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The user accounts with Secure Token assigned should appear listed with the following information:
Type: Local Open Directory User
Volume Owner: Yes
In place of the account’s username, the account’s assigned UUID identifier (also referred to as a GeneratedUID) is listed. To get the account username, run the following command with the UUID identifier in the appropriate place:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If the account you want to be a Volume Owner isn’t listed, you can check the account’s Secure Token status by running the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If the account does not have Secure Token assigned, the output of the command should tell you this.
To assign Secure Token (and Volume Owner) to the desired account, run the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If you want to be prompted for passwords in place of including them as part of the command in plaintext, enter a dash ( – ) where you would otherwise enter the relevant account’s password when running the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Once this has been done, you can verify that Secure Token has been assigned to the desired account by running the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The output should now tell you that Secure Token has been assigned to the account.
To verify that the desired account is now also a Volume Owner, run the following command:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You should see a new entry listed with the following information:
Type: Local Open Directory User
Volume Owner: Yes
To get the account username, run the following command with the UUID identifier in the appropriate place:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The sysdiagnose tool is used for gathering a large amount of diagnostic files and logging, and it’s often very useful when it comes to figuring out why a problem is happening. However, it can sometimes be challenging to get a sysdiagnose-generated file from someone who is not comfortable with using the Terminal as the usual method for generating a sysdiagnose file involves opening the Terminal and running commands there.
Fortunately, there’s also a way to generate a sysdiagnose file using Activity Monitor. This may be an alternate way to help get you the desired sysdiagnose file from someone who normally wouldn’t ever use the Terminal on macOS. For more details, please see below the jump.
2. Choose a method to generate the sysdiagnose file. There’s an option available in the View menu, where you can choose Run System Diagnostics…
Another option is click the System diagnostics options pop-up menu (…) and select System Diagnostics…
3. Click OK at the privacy agreement screen.
After agreeing at the privacy agreement screen, a sysdiagnose file will be generated. This is a process that may take a few minutes to complete.
Once the sysdiagnose file has been created, a Finder window will appear showing the location of the sysdiagnose file, which will be a compressed file named something similar to what’s shown below:
I’m a frequent user of macOS’s Open With functionality, where I can control-click on a file and select what app I want to open the file with.
Among the files I’m used to doing this with are installer package files. However, I noticed that as of macOS 13.3, this mostly stopped working as the only choice I now had for installer packages was the Installer app. Here’s how it looks on macOS 13.2.1, on a Mac with the Suspicious Package application installed:
As of macOS 13.3, a new LaunchServices key in the CFBundleDocumentTypes dictionary, named LSIsAppleDefaultNoOverrideForType, appears to have been introduced. This new key so far only appears in the following file:
This key is applied to all three package document types used by the Installer app, which means it covers all known macOS installer package files (both flat packages and bundle-style packages.)
The new key appears to affect how LaunchServices manages the Open With functionality specifically in the context of installer packages.
There are still ways outside of the Open With functionality to open an installer package in a desired application. One of the ways is to use the open command in Terminal. For example, if you had an installer package named example.pkg stored on your desktop and you wanted to open the installer package in the Suspicious Package application, you could run the command below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
As part of a recent change, I needed to migrate an APNS certificate from being associated with one Apple ID to now being associated with another Apple ID. Apple has a KBase article available which provides contact information for this, which is available via the link below:
For those folks with AppleCare support plans, you can also submit a ticket to AppleCare. That’s the route I took. Regardless of which support avenue you pursue, Apple will request the following information from you.
2. Make a note of the current certificate’s expiration date.
3. Click the ( i ) button to display the certificate information.
4. Make a note of the APNS certificate’s serial number.
5. Make a note of the APNS certificate’s Certificate Subject DN.
Note: Even though it may be displayed in the Portal site as being multiple lines, the Certificate Subject DN should be a one-line entry when you send it to Apple.
6. Make a note of the APNS certificate’s CN.
Note: The CN is included as part of the Certificate Subject DN information. It will be a string with information similar to this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
For example, if you have an APNS certificate with the following information:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You would convert that to the following information for Apple:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
The last part is identifying the Apple ID you want to migrate from, and the Apple ID you want to migrate to. For example, if you want to migrate an APNS certificate with the information listed above from an Apple ID of oldappleid@company.com to an Apple ID of newappleid@company.com, you could send in the following request via email:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Email subject: [Apple Push Notification Service] Transferring APNS certificate with serial number 3bb763753df5d8dd from one Apple ID to another Apple ID
Email body:
I need to transfer the following APNS certificate from one Apple ID to another Apple ID:
One of the issues Mac admins may face is working with JSON files as part of shell scripting. There are several solutions to this problem, including using the third-party jq command line tool and Apple’s JavaScript for Automation (JXA) interface. For posts on using these solutions, please see the links below:
Another available option is to use the plutil command line tool on macOS Monterey and later to do the following:
Read values from JSON files
Convert plist files in XML format to JSON
For more details, please see below the jump.
If you want to read JSON values from a file, you can use the raw option of plutil‘s -extract function in some cases to extract values from keys in JSON files. For example, you may have a JSON file with the following keys and values:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You could use the following command to extract the value for the createStartupScript key in the JSON file:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
In that case, you should see the following output:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
In cases like this, where you’re dealing with a JSON file with a fairly simple format (without arrays or otherwise nested values), plutil is a good tool which is built into macOS that you can call on to extract the data you need.
Another option is using the plutil tool to write what you need to an XML file, then use plutil‘s -convert functionality to turn it into a JSON file. For folks more experienced with using plutil to write XML to a file than they are with writing JSON, this option may help with a lot of use cases. For example, you could run the following command to accomplish the following:
1. Create an XML file using the plutil tool
2. Add the following key and value, with the value stored in an array as a string:
Key: MyKeyHere
Value: MyGreatValue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You would then run the following command to have plutil convert the XML in the file into the equivalent JSON:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Something to be aware of is that there will be some limitations to this technique. plutil is designed to work with plist files, which means that if something isn’t formatted like it expects, plutil may not know how to handle it. Two limitations I know of are these:
NULL values in JSON files – There’s no equivalent for NULL in plist files, so the plutil tool will fail to convert JSON files with NULL values to a plist file in XML format.
Plists which contain date or data values – There’s no JSON equivalent of the date or data values in plist files, so plutil will fail to convert plist files in XML format with these values to JSON files.
Hat tip to Pico in the MacAdmins Slack for telling me about these limitations.
Payload-free packages are something I’ve discussed from time to time, as I’ve found them to be very useful additions to my Mac admin toolkit. For those not familiar with the concept, payload-free installer packages are installer packages that exist only to run scripts. They don’t install any files, which would be referred to as the installer package’s payload. With no payload included with these installer packages, the installer packages built by this tool are referred to as payload-free.
A while back, I wrote a tool that would let me easily create them from existing scripts named Payload-Free Package Creator.app. The general idea was that you could use this tool to select a script, and then Payload-Free Package Creator.app would create an unsigned payload-free installer package which would run the selected script.
I’m happy to say that my team at work has expanded on that idea and has both built and open-sourced a tool for building payload-free packages named Script2Pkg. Script2Pkg includes the following functions:
Building an unsigned payload-free installer package
Building a signed payload-free installer package
Building a signed and notarized payload-free installer package
Verifying signing and notarization status of any installer package
For more details, please see below the jump.
Using Script2Pkg
You can use the following procedure to create a payload-free installer package using Script2Pkg.
1. Launch the app.
2. Click the Select scripts button.
3. In the window which appears, select the script(s) you want to use and click the Build button.
Note: You can select multiple scripts. Script2Pkg will create one installer package per selected script.
New payload-free installer package(s) will be created and stored in the same location as the script(s) which were selected.
Each installer package will have the same name as the source script.
By default, installer packages created by Script2Pkg will have the following characteristics:
Installer packages created by this tool will not leave an installer package receipt when the package is installed.
Installer packages created by this tool will create the installer package in the same location as the selected script.
Package version will be the following: 1.0.0
Package identifier used by the app will begin with the following: corp.sap.Script2Pkg
Note: The remainder of the identifier will be a UUID. For example, using the default settings will may result in a package with the following package identifier:
To sign an installer package using a code signing certificate, you will need a Developer ID Installer certificate installed in a keychain on your Mac. Once the Developer ID Installer certificate is installed in a keychain on your Mac, it should be listed next to Development team: in the main app window.
Once you have your Developer ID Installer singing certificate listed in the Script2Pkg window, check the Sign packages checkbox and subsequent installer packages created by Script2Pkg will be signed using the selected signing certificate.
Once Script2Pkg has been configured for signing and notarization, check the Sign packages and the Notarize packages checkboxes. Subsequent installer packages created by Script2Pkg will be signed using the selected signing certificate and notarized.
Verifying installer packages
Script2Pkg is able to check any installer package and report on the following:
If the installer package is signed with a valid code signing certificate
If the installer package is signed with a valid code signing certificate and notarized
To check an installer package, using the following procedure to validate its status:
1. Under the File menu, select Validate Package Signature…
2. Select the package you want to check and click the Validate button.
Script2Pkg will then report back on the package signing and notarization status.
Package not signed or notarized
Package signed with a valid certificate and not notarized
Package signed with a valid certificate and notarized
When managing user settings with a profile, you often need to define what the preference domain is in order to specify which settings to manage. Usually you can check the CFBundleIdentifier of an application to get the unique identifier used to define the preference domain.
Normally, these unique IDs (and corresponding preference domains) use a reverse-DNS-lookup scheme. For example, the preference domain for Apple’s web browser Safari is the following:
b. The application in question being named Safari.
Note: This is a convention, rather than a hard and fast requirement, but most applications’ unique identifiers and corresponding preference domains will use this naming convention.
However, there’s an exception to be aware of. macOS uses a special domain to identify settings which should apply to all applications started by the same user. This preference domain is called the NSGlobalDomain, but unlike most preference domains, you don’t use NSGlobalDomain to define the preference domain when trying to manage their settings with a profile. This can cause some confusion when trying to manage these settings. The preference domain in this case is the following:
I noticed that I first wrote an entry on this blog twenty years ago. I figured that deserved some commemoration and recognition.
The blog started out as a personal blog (as evidenced by its early entries) and gradually morphed into being what it is today. I plan to keep writing it because it’s still fun for me and I can see that it’s helped folks out. First blog entry was naturally about starting the blog:
At the time, I was using LiveJournal as they had a client app for Mac OS X and that made it easy for me to get started with blogging. Over the years, the blog moved a few times:
I moved to WordPress.com in September 2008 and they’ve been graciously hosting me ever since. Thanks, folks.
I’ve been using MarsEdit for at least the last six years to write my blog posts, so thanks also to Daniel Jalkut at Red Sweater for putting out a quality product that helps me stay focused on the writing of a blog post and not the fiddly bits of how to post it.
For my past, present and future readers:
Thank you. This place wouldn’t be what it is without you.
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:
I can ensure that the packaging task is handled the same way every time.
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:
Creating an installer package for NexThink Collector
Creating an uninstaller for NexThink Collector
I was able to do this, so for those interested, please see below the jump for more details.
I’ve built several AutoPkg recipes for NexThink Collector:
NexThinkCollector.download: Downloads the latest NexThink Collector installer disk image
NexThinkCollector.pkg: Builds an installer package for NexThink Collector
NexThinkCollectorUninstaller.pkg: Builds an uninstaller package for NexThink Collector
NexThinkCollector.sign: Signs the installer package produced by the NexThinkCollector.pkg recipe
NexThinkCollectorUninstaller.sign: Signs the uninstaller package produced by the NexThinkCollectorUninstaller.pkg recipe
All the recipes are available at the following location:
The one which needs the most configuration via an AutoPkg override is the following:
NexThinkCollector.pkg
This is because the details of installing and configuring NexThink are going to vary between shops, because different shops are going to configure different options for NexThink. The various Input variable options will provide hopefully all the possible configuration options needed.
To map between the Input variables and the NexThink command line installation configuration options, please see the table below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Since the rootca option doesn’t seem to be required at all and there’s no documentation available on how to configure it for the NexThink Collector software on macOS, I’m leaving it out of the AutoPkg recipe.
For the key command line installation configuration option, this functionality is covered by the following required Input variables:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
If both Input variables are filled in, then the postinstall script used by the installer package generated by this AutoPkg recipe will call the key command line installation configuration option and use it to configure the NexThink Collector software with the proper Customer Key information.
To see how this looks in a recipe override of the NexThinkCollector.pkg recipe, let’s create one with the following Input variables set:
NTSERVERADDRESS: server.nexthink.com
NTTCPPORT: 443
NTREMOTEACTIONS: disabled
NTENGAGE: disable
NTASSIGNMENT: enable
NTDATAOVERTCP: enable
NTCUSTOMERKEYNAME: nexthink-customer-key.txt
NTCUSTOMERKEYDATA:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
With those variables set, the AutoPkg recipe override should look similar to what’s shown below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Once configured, the NexThinkCollector.pkg AutoPkg recipe should work with the NexThinkCollector.download recipe to do the following:
Download the latest NexThink Collector installer disk image
Wrap the disk image and CustomerKey file inside a separate installer package.
Use a postinstall script to perform the following actions:
Identify the location of the disk image stored inside the installer package.
Mount the disk image
Identify the location of the csi.app on the mounted disk image.
Identify the location of the CustomerKey file stored inside the installer package.
Use the csi app’s command line tool to configure and run the NexThink-provided installer package on the mounted disk image, to install the NexThink Collector software.
Unmount the disk image.
The other .pkg AutoPkg recipe I wrote is NexThinkCollectorUninstaller.pkg and it is much simpler in terms of operation. It uses the same technique described in my earlier post on how to build a NexThink Collector uninstaller and should not need configuration of any Input variables. The NexThinkCollectorUninstaller.pkg recipe works with the NexThinkCollector.download recipe to do the following:
Download the latest NexThink Collector installer disk image
Wrap the disk image inside a separate installer package.
Use a postinstall script to perform the following actions:
Identify the location of the disk image stored inside the installer package.
Mount the disk image
Use the uninstall script to uninstall the NexThink Collector software.
Unmount the disk image.
The AutoPkg recipe override should look similar to what’s shown below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This week, like 2020, 2021 and 2022, I’m attending Apple’s WWDC 2023 conference from the comforts of home. As part of this, I’m taking notes during the labs and session videos. Due to wanting to stay on the right side of Apple’s NDA, I’ve been posting my notes to Apple’s developer forums rather than to here.
To make it easier for Mac admins to access them, I’ve set up a post in the forums where I’ve linking the various forum posts with my notes. It’s available via the link below:
On Apple Silicon Macs, VMware Fusion does not yet support running macOS in a VM, so on my Apple Silicon Macs I have switched from using Fusion to using UTM for running macOS VMs. One feature missing until recently was the ability to boot into macOS Recovery in a VM in UTM.
UTM uses’s Apple’s Virtualization framework, which has a startup option for booting into Recovery, but until recently UTM had not implemented this start option for macOS VMs. As of UTM 4.2.5 (the current version as of June 23, 2023), it looks like this option has now been added. For more details, please see below the jump.
To boot a macOS VM into Recovery mode in UTM, please use the procedure shown below.
When you enroll a Mac with Jamf Pro, the first profile the Mac receives is named MDM Profile.
It is valid for two years.
After two years, the MDM profile is supposed to automatically renew but sometimes this renewal process is either not triggered or is triggered and does not succeed.
On Jamf Pro, there’s a couple of ways you can manually trigger the MDM renewal to occur. The first is a manual process which uses the Jamf Pro admin console. The second uses both of Jamf Pro’s APIs and can be automated via a Jamf Pro policy. For more details, please see below the jump.
Manually triggering MDM profile renewal using the Jamf Pro admin console
To manually trigger MDM profile renewal using the admin console, please use the procedure shown below.
1. Run a search for the computers you want to renew the MDM profile on.
2. Once you have the desired list, click the Action button.
3. Select Send Remote Commands and click the Next button.
4. Select Renew MDM profile and click the Next button.
5. Once the MDM command has been sent, click the Done button.
Manually triggering MDM profile renewal using Jamf Pro’s APIs
You can also use Jamf Pro’s APIs to script an MDM profile renewal at whatever interval is desired. My approach is the following:
1. Write a script designed to run via a Jamf Pro policy on individual Macs to perform the following tasks:
Get the Jamf Pro UDID number of the Mac the script is running on.
Use the UDID to send a “Renew MDM profile” MDM command via the API.
Note: This approach uses both the Jamf Pro Classic API and the Jamf Pro API, as the command I’m using to get the Jamf Pro UDID number is using the Classic API and the command used to trigger the MDM profile renewal MDM command is using the Jamf Pro API.
For those who haven’t used the Jamf Pro APIs before, you will need to provide a username and password to the script. This is a security risk, so my recommendation is to carefully evaluate if the risk is worth it for your environment. If it’s not, don’t use this approach.
One way to mitigate this risk is to set up a dedicated account with the least privileges necessary. This method does not eliminate the risk, but it may reduce it to one acceptable in your environment. In my testing, the least privileges are the following:
In Jamf Pro Server Objects:
Computers: Read
In Jamf Pro Server Actions:
Send Command to Renew MDM Profile
2. Create a smart group with the following criteria:
Name: MDM Certificate Expiration in Five Days or Less
Criteria: MDM Profile Expiration Date
Operator: in less than X days
Value: 5
Note: You may choose different criteria, but in this example I want to run the script on Macs whose MDM profile expiration dates are five days or less.
3. Set up a Jamf Pro computer policy with the following components:
Script: The script to trigger MDM profile renewal
Trigger: Recurring Check-In
Execution Frequency: Once every day
Scoped to: the MDM Certificate Expiration in Five Days or Less smart group.
Note:Execution Frequency can be set as desired for a longer interval, like Once every week or Once every month.
The script is available from following address on GitHub:
Using either method (admin console triggered renewal or API triggered renewal), the expected behavior is that the MDM profile for Jamf Pro is renewed and shows an install date of when the MDM renewal was triggered.