Quantcast
Channel: Mac administration – Der Flounder
Viewing all 490 articles
Browse latest View live

Payload-Free Package Creator 2.4 now available

$
0
0

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

The functionality and operations of the app have not changed from Payload-Free Package Creator 2.3. The main change is that Payload-Free Package Creator.app is now a Universal app, allowing it to run natively on both Intel and Apple Silicon Macs.

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

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


Building a Privileges installer package using AutoPkg

$
0
0

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.


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


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.

For those not familiar with using AutoPkg, please follow the process below to build a working Privileges installer package:

Note: If you do not want to install AutoPkg on your own Mac, AutoPkg also runs fine in a macOS virtual machine.

1. If Git is not already installed, install Git.

Note: Git must be installed before installing AutoPkg because AutoPkg uses Git for many of AutoPkg’s functions.

Git is included with Xcode or the Xcode Command Line Tools, so installing either Xcode or the Xcode Command Line Tools will also install the necessary Git support.

2. Download the latest AutoPkg installer from https://autopkg.github.io/autopkg

Screen Shot 2022 04 20 at 3 02 36 PM

 

3. Install AutoPkg.

Screen Shot 2022 04 20 at 3 28 03 PM

Screen Shot 2022 04 20 at 3 28 18 PM

4. Open Terminal and run the following command:

autopkg repo-add rtrouton-recipes

Screen Shot 2022 04 20 at 3 38 58 PM

 

5. Once the repo has been added, run the following command to create an AutoPkg override of the AutoPkg recipe which creates the installer package:

autopkg make-override com.github.rtrouton.pkg.privileges

Screen Shot 2022 04 20 at 3 39 41 PM

 

6. An AutoPkg override file should be created with the following recipe identifier:

local.pkg.Privileges

You can verify this by opening the override file in a text editor and looking for the Identifier key.

Screen Shot 2022 04 20 at 3 40 14 PM

 

7. Once the override file has been created, run the following command to create a Privileges installer package:

autopkg run local.pkg.Privileges

Screen Shot 2022 04 20 at 3 40 55 PM

 

You should then see output 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


username@computername ~ % autopkg run local.pkg.Privileges
Processing local.pkg.Privileges…
The following new items were downloaded:
Download Path
————-
/Users/username/Library/AutoPkg/Cache/local.pkg.Privileges/downloads/Privileges-1.5.2.zip
The following packages were built:
Identifier Version Pkg Path
———- ——- ——–
com.sap.privileges 1.5.2 /Users/username/Library/AutoPkg/Cache/local.pkg.Privileges/Privileges-1.5.2.pkg
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

The newly-created Privileges installer package should be stored be in ~/Library/AutoPkg/Cache/local.pkg.Privileges.

Screen Shot 2022 04 20 at 3 42 00 PM

 

8. Repeat process as needed for each new version of Privileges.

Apple discontinues macOS Server

$
0
0

After a long run, first beginning with Mac OS X Server 1.0 in 1999, Apple has announced the end of macOS Server as of April 21, 2022. The final version is macOS Server 5.12.2, which runs on macOS Monterey.

Screen Shot 2022 04 21 at 1 46 23 PM

macOS Server 5.12.2 has shed many of the features once supported by macOS Server. As of 5.12.2, the following two services are supported:

Both services are not currently available outside of macOS Server, so Apple discontinuing macOS Server also means the end of the line for Apple’s Open Directory directory service and Apple’s Profile Manager MDM service.

For current customers who have purchased macOS Server, macOS Server 5.12.2 remains available in the App Store.

Screen Shot 2022 04 21 at 1 42 03 PM

Discussing standard versus admin rights, hosted by Kandji

Safari 15.5 embedded content slow to load

$
0
0

As part of the release of Safari 15.5, there seems to be an issue with Safari being able to load embedded content on some websites. One example is the US State Department’s site for reporting a lost or stolen passport:

https://travel.state.gov/content/travel/en/passports/have-passport/lost-stolen.html

This site has embedded content and Safari is very slow to load that site. The behavior seems to be tied to the Hide IP address from trackers setting in Safari’s privacy settings:

Screen Shot 2022 05 18 at 4 09 53 PM

 

With that setting enabled, slow website loading:

With that setting disabled, normal website loading:

Removing unwanted Time Machine backups from APFS-formatted Time Machine backup drives on macOS Monterey

$
0
0

I recently needed to prune some Time Machine backups, where I wanted to manually delete some older backups while not deleting everything on the drive. When I researched this, the guidance provided used the procedure described below:

  1. Connect your external backup drive to your Mac if needed.
  2. Launch the Time Machine app.
  3. Use the timeline on the right of the screen or the arrows to navigate to the backup date you want to delete. Alternatively, use the Finder window to navigate to the file or folder you want to delete.
  4. After selecting the date or file you want to delete, click the Action () button in Finder and choose to either Delete Backup or Delete All Backups of [Your File]

For an HFS+ formatted Time Machine backup drive, this guidance is correct. However, my Time Machine backup drive is APFS formatted. When following this guidance, I ran into the following issue:

  1. Connect your external backup drive to your Mac if needed.
  2. Launch the Time Machine app.
  3. Use the timeline on the right of the screen or the arrows to navigate to the backup date you want to delete. Alternatively, use the Finder window to navigate to the file or folder you want to delete.
  4. After selecting the date or file you want to delete, click the Action () button in Finder.

With APFS-formatted Time Machine backup drives, only the option to restore files is available. The Delete Backup or Delete All Backups options are not available.

Screen Shot 2022 07 01 at 3 17 34 PM

So how can unwanted Time Machine backups be manually deleted? For more details, please see below the jump.

You can remove unwanted backups using either the Finder, or by using the tmutil command line tool.

To remove unwanted backups using the Finder, use the procedure described below:

1. Connect your external backup drive to your Mac if needed.
2. Open a new Finder window and select the backup drive.

You should see your backups listed in the Finder window.

Screen Shot 2022 07 01 at 1 48 37 PM

3. Select the backup you want to delete and click the Action () button in Finder.

Screen Shot 2022 07 01 at 4 00 55 PM

Note: You can also control-click on the desired backup to access the same options.

Screen Shot 2022 07 01 at 1 48 50 PM

4. Select the Delete Immediately… option.

5. When prompted to confirm, click the Delete button.

Screen Shot 2022 07 01 at 1 48 58 PM

Once confirmed, the backup should be deleted and disappear from the Finder window.

Screen Shot 2022 07 01 at 1 49 21 PM

To remove unwanted backups using the tmutil command line tool, use the procedure described below:

1. Connect your external backup drive to your Mac if needed.

2. Open a Terminal window and run the following command:

tmutil listbackups

Note: You may be prompted to grant full disk access to the Terminal in order to run this command.

Screen Shot 2022 07 01 at 3 06 39 PM

Screen Shot 2022 07 01 at 3 07 32 PM

3. Identify the backup you want to delete. For this example, we’re using the following backup:

2022-07-01-154751.backup

Screen Shot 2022 07 01 at 4 26 21 PM

To delete the backup using the tmutil command line tool, you need two items of information:

  1. The path to the drive it is stored on.
  2. The time stamp of the backup.

The path to the drive is going to depend on what the drive is named. In this example, the name of the drive is Backup so the path name should be as shown below:

/Volumes/Backup

The time stamp of the backup is going to be the name of the backup prior to the .backup part of the name. In this example, the backup is named 2022-07-01-154751.backup so the time stamp should be as shown below:

2022-07-01-154751

Screen Shot 2022 07 01 at 4 26 30 PM

4. Once you have the path and time stamp, run the command shown below with root privileges to delete the backup:

tmutil delete -d /path/to/backup/drive -t timestamp_of_backup

You’ll need to provide the path and time stamp information using tmutil‘s -d flag for the path and the -t flag for the time stamp. For our example, where the path is /Volumes/Backup and the time stamp is 2022-07-01-154751, you would run the command shown below with root privileges to delete the backup:

tmutil delete -d /Volumes/Backup -t 2022-07-01-154751

The specified backup should be deleted.

Screen Shot 2022 07 01 at 4 32 51 PM

5. Run the command shown below to verify that the backup has been removed:

tmutil listbackups

Screen Shot 2022 07 01 at 4 34 48 PM

This post is focused on using Time Machine’s own tools to manage Time Machine backups, but you can also access and delete Time Machine APFS snapshots using Disk Utility on macOS Monterey. For more information on this, please see Howard Oakley‘s post linked below:

https://eclecticlight.co/2021/11/09/disk-utility-now-has-full-features-for-managing-snapshots/

Privileges.app and time-limited admin

$
0
0

Privileges is an open source tool from SAP which helps folks manage admin rights for their account. As part of its feature set, it includes an option for time-limited admin using a specific function called Toggle privileges.

Privileges dock toggleon

Privileges dock toggleon20

However, Toggle privileges’s time-limited admin feature for Privileges is its most misunderstood feature. The reason is that while the ability to set a time limit is only available if you’re using the Toggle privileges function, many users assume that this time-limited admin is available universally to all the functions used to get admin rights using the Privileges app.

It is not. Time limited admin is only available using the Toggle privileges function. If you’re not using the Toggle privileges function, there is no time limitation and you cannot set one from within the Privileges app.

This information is available in the Privileges FAQ:

Screen Shot 2022 07 22 at 10 05 50 AM

What does this mean?

  1. The only way time-limited admin is currently working on Privileges is by using the Toggle privileges function.
  2. If you are clicking on the icon in the dock and not selecting the Toggle privileges function, there’s no time limit.
  3. If you’re using the PrivilegesCLI command line tool, there is no time limit.

How long do you have admin if you’re not using the Toggle privileges function? Admin rights are granted until some process (like running Privileges again) takes them away. There’s no time limit.

All of the Privileges management options available for time-limited admin at this time apply only to the Toggle privileges function. If you’re using any of the management settings options listed below, they apply only and exclusively to the Toggle privileges function:

  • DockToggleTimeout
  • DockToggleMaxTimeout

They will not manage time-limited admin for any of Privileges’ functions outside of using the Toggle privileges function.

What if you want time-limited admin outside of using the Toggle privileges function? You will need to use a separate mechanism. In my case, I usually point folks towards using PrivilegesDemoter:

https://github.com/sgmills/PrivilegesDemoter

This tool uses a separate mechanism for figuring out the timing and then uses the PrivilegesCLI command line tool to take away admin when the time limit set for PrivilegesDemoter expires.

Microsoft Defender and tamper protection

$
0
0

One of the features of Microsoft Defender for macOS is tamper protection. This option is designed to prevent Defender or its settings from being removed or changed.

As of posting date, Defender’s tamper protection has three associated topics:

  • Disabled: Tamper protection is completely off.
  • Audit: Tampering operations are logged, but not blocked.
  • Blocked: Tamper protection is on, tampering operations are blocked.

Microsoft has documentation regarding Defender’s tamper protection for macOS, available via the link below:

https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/tamperprotection-macos

For more details, please see below the jump.

You can manage tamper protection via running commands via the command line, or via management profiles. The commands shown below allow tamper protection to be disabled completely, set to audit mode, or set to full tamper protection where Defender or its settings can’t be removed or changed.

To disable tamper protection, run the following command with root privileges:


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


/usr/local/bin/mdatp config tamper-protection enforcement-level –value disabled
view raw

gistfile1.txt

hosted with ❤ by GitHub

To set tamper protection to audit mode, run the following command with root privileges:


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


/usr/local/bin/mdatp config tamper-protection enforcement-level –value audit
view raw

gistfile1.txt

hosted with ❤ by GitHub

To set tamper protection to full tamper protection mode, run the following command with root privileges:


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


/usr/local/bin/mdatp config tamper-protection enforcement-level –value block
view raw

gistfile1.txt

hosted with ❤ by GitHub

If management via profiles is desired, the example profiles below will set Defender to audit mode or to full tamper protection.

Audit mode:


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


<?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">
<dict>
<key>PayloadUUID</key>
<string>05F0ADFE-8BE0-4C43-BACB-BD0DE6272306</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadOrganization</key>
<string>Company Name</string>
<key>PayloadIdentifier</key>
<string>com.microsoft.wdav</string>
<key>PayloadDisplayName</key>
<string>Enabling Tamper Protection for Microsoft Defender</string>
<key>PayloadDescription</key>
<string>Microsoft Defender tamper protection configuration settings</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true />
<key>PayloadRemovalDisallowed</key>
<true />
<key>PayloadScope</key>
<string>System</string>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadUUID</key>
<string>977D6F1E-E6C1-4BD2-96C5-D4FFCEAE92BB</string>
<key>PayloadType</key>
<string>com.microsoft.wdav</string>
<key>PayloadOrganization</key>
<string>Microsoft</string>
<key>PayloadIdentifier</key>
<string>com.microsoft.wdav</string>
<key>PayloadDisplayName</key>
<string>Microsoft Defender tamper protection configuration settings</string>
<key>PayloadDescription</key>
<string />
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true />
<key>tamperProtection</key>
<dict>
<key>enforcementLevel</key>
<string>audit</string>
</dict>
</dict>
</array>
</dict>
</plist>
view raw

gistfile1.txt

hosted with ❤ by GitHub

Full tamper protection:


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


<?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">
<dict>
<key>PayloadUUID</key>
<string>E21D6405-FA0F-46D2-84DE-33775762DD7E</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadOrganization</key>
<string>Company Name</string>
<key>PayloadIdentifier</key>
<string>com.microsoft.wdav</string>
<key>PayloadDisplayName</key>
<string>Enabling Tamper Protection for Microsoft Defender</string>
<key>PayloadDescription</key>
<string>Microsoft Defender tamper protection configuration settings</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true />
<key>PayloadRemovalDisallowed</key>
<true />
<key>PayloadScope</key>
<string>System</string>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadUUID</key>
<string>C3934617-C698-4A88-819D-47377A35D4F3</string>
<key>PayloadType</key>
<string>com.microsoft.wdav</string>
<key>PayloadOrganization</key>
<string>Microsoft</string>
<key>PayloadIdentifier</key>
<string>com.microsoft.wdav</string>
<key>PayloadDisplayName</key>
<string>Microsoft Defender tamper protection configuration settings</string>
<key>PayloadDescription</key>
<string />
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadEnabled</key>
<true />
<key>tamperProtection</key>
<dict>
<key>enforcementLevel</key>
<string>block</string>
</dict>
</dict>
</array>
</dict>
</plist>
view raw

gistfile1.txt

hosted with ❤ by GitHub

To check the current Defender configuration, the following command can be run:


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


/usr/local/bin/mdatp health
view raw

gistfile1.txt

hosted with ❤ by GitHub

That should return output which looks 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


healthy : true
health_issues : []
licensed : true
engine_version : "1.1.18900.4"
app_version : "101.78.13"
org_id : "…"
log_level : "info"
machine_guid : "…"
release_ring : "Production"
product_expiration : Feb 05, 2023 at 06:24:12 AM
cloud_enabled : true
cloud_automatic_sample_submission_consent : "safe"
cloud_diagnostic_enabled : false
passive_mode_enabled : true [managed]
real_time_protection_enabled : false [managed]
real_time_protection_available : true
real_time_protection_subsystem : "endpoint_security_extension"
network_events_subsystem : "network_filter_extension"
device_control_enforcement_level : "audit"
tamper_protection : "audit"
automatic_definition_update_enabled : true
definitions_updated : Sept 08, 2022 at 01:57:03 PM
definitions_updated_minutes_ago : 27712166
definitions_version : "1.355.2589.0"
definitions_status : "update_failed"
edr_early_preview_enabled : "enabled"
edr_device_tags : []
edr_group_ids : ""
edr_configuration_version : "20.199999.main.2022.09.08.01-10dcd7fedfed0c7a1c3bbf153ba3c9b0d0f36239"
edr_machine_id : "…"
conflicting_applications : []
network_protection_status : "stopped"
network_protection_enforcement_level : "disabled"
data_loss_prevention_status : "disabled"
view raw

gistfile1.txt

hosted with ❤ by GitHub

To check specifically for the tamper protection configuration, the following command can be run to check its status:


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


/usr/local/bin/mdatp health –field tamper_protection
view raw

gistfile1.txt

hosted with ❤ by GitHub

You should see the following output depending on the configuration:

Tamper protection disabled:


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


username@computername ~ % /usr/local/bin/mdatp health –field tamper_protection
"disabled"
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

Tamper protection set to audit mode:


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


username@computername ~ % /usr/local/bin/mdatp health –field tamper_protection
"audit"
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

Tamper protection set to full tamper protection:


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


username@computername ~ % /usr/local/bin/mdatp health –field tamper_protection
"block"
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

For folks with uninstall scripts for Microsoft Defender, they won’t be able to successfully uninstall Defender or its settings with tamper protection enabled. One way to address this is to add a section at the beginning of the uninstall script which can detect if full tamper protection is enabled and stop the script if it is. An example of this is 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


#!/bin/bash
ERROR=0
# Check to see if Microsoft Defender's tamper protection is enabled.
#
# If tamper protection is turned on, a message will be displayed followed
# by the script exiting before proceeding to the uninstall functions of
# the script.
# Verify that the following tool is installed and executable:
#
# /usr/local/bin/mdatp
if [[ -x "/usr/local/bin/mdatp" ]]; then
# If the mdatp is installed, Defender's Tamper protection's
# status is checked by running the following command:
#
# /usr/local/bin/mdatp" health –field tamper_protection
#
# The output of this command will then be checked against the value stored
# in the tamper_protection_enabled_keyword variable.
#
# There are three possible keywords that can be returned by this command:
#
# disabled – tamper protection is completely off.
# audit – tampering operations are logged, but not blocked.
# block – tamper protection is on, tampering operations are blocked.
#
# The tamper_protection_enabled_keyword variable will store the keyword
# currently being used by Defender, in case Microsoft chooses to change
# the keywords in future versions of Defender.
tamper_protection_enabled="$("/usr/local/bin/mdatp" health –field tamper_protection | awk '{print $1}' | tr -d '"')"
tamper_protection_enabled_keyword="block"
if [[ "$tamper_protection_enabled" == "$tamper_protection_enabled_keyword" ]]; then
/usr/bin/osascript -e 'display dialog "Tamper protection for Microsoft Defender is enabled." & "\n" & "\nDefender cannot be uninstalled while tamper protection is turned on."& "\n" & "\nFor more information, please contact the helpdesk."buttons {"Understood"} default button 1 with icon Caution'
exit "$ERROR"
fi
fi
view raw

gistfile1.txt

hosted with ❤ by GitHub

If full tamper protection is enabled, this example script will take the following actions:

1. Display the following message using osascript.

Screen Shot 2022 09 09 at 9 27 38 AM

2. Exit after displaying the message.


Jamf Pro 10.41.0 and SSL verification alerts

$
0
0

Following an upgrade to Jamf Pro 10.41.0, you may notice that you have an alert showing in the Jamf Pro admin console.

Screen Shot 2022 09 12 at 10 39 33 AM

When you click on the alert, you will see the following alert notification.

Verification of SSL certificates is disabled.

There will be a link to enable SSL certificate verification.

Screen Shot 2022 09 12 at 10 39 51 AM

If you click that link, it’ll take you to Management Settings: Computer Management – Management Framework: Security.

Screen Shot 2022 09 09 at 10 15 26 AM

So now what? For more details, please see below the jump.

The SSL certificate in question is the SSL certificate used by Tomcat. Jamf is deprecating the use of self-signed certificates for Tomcat, as mentioned in the Jamf Pro 10.41.0 release notes:

Removal of unverified SSL certificates in Jamf Pro — In a future release of Jamf Pro the option to use an unverified SSL certificate for Jamf Pro will be removed. Customers with Cloud-hosted environments and those with a verified third-party certificate will see no changes. Customers with On-Premise environments using Jamf Pro’s built-in certificate authority to issue SSL certificates need to move to a trusted third-party certificate.

Screen Shot 2022 09 12 at 10 44 05 AM

The alert is being triggered if you have the SSL Certificate Verification setting set to one of the following:

  • Disabled
  • Always except during enrollment

The Disabled setting means the Jamf Pro agent installed on a Mac isn’t verifying certificate trust at all for the SSL certificate that Tomcat is using.

The Always except during enrollment setting means that the Jamf Pro agent installed on a Mac isn’t verifying certificate trust for the SSL certificate that Tomcat is using at enrollment, but does verify that the SSL certificate is trusted for all subsequent communication.

Note: The Always except during enrollment setting was meant to ensure that Jamf Pro could install a root certificate for a self-signed certificate and establish certificate trust that way.

Screen Shot 2022 09 09 at 10 16 14 AM

 

If your Jamf Pro service is using a publicly trusted SSL certificate, the fix is to set the SSL Certificate Verification setting to the following:

  • Always

Screen Shot 2022 09 09 at 10 16 24 AM

Selecting that setting and clicking the Save button will result in the following warning being displayed. If you’re certain you have a publicly trusted certificate, click OK. Otherwise, click the Cancel button to back the change out.

Screen Shot 2022 09 12 at 10 40 55 AM

As long as you have a publicly-trusted SSL certificate for Tomcat, changing the SSL Certificate Verification setting to Always should have no impact. 

If you’re hosted in Jamf Cloud, you should already be using a publicly trusted SSL certificate. If you’re hosting Jamf Pro yourself, I recommend verifying that you’re using a publicly trusted certificate before making that change.

If you are hosting Jamf Pro yourself and don’t have a publicly trusted SSL certificate for Tomcat, I strongly recommend getting one as soon as possible. As Jamf’s release notes mention, the option to not use a trusted certificate will be removed from a future version of Jamf Pro.

Running Jamf Pro inventory updates at startup time

$
0
0

With the release of macOS Ventura expected this month, an important topic to many Mac admins is having their systems management tools detect as quickly as possible which of their Macs have upgraded to macOS Ventura. The reasons for this are varied, but one particular reason is to get configuration profiles deployed as soon as possible to manage new features and functionality in macOS Ventura.

One way to ensure quick detection if you’re using Jamf Pro is to have your managed Macs submit an inventory update to the Jamf Pro server when the Mac starts up. For one way to do this, please see below the jump.

For Macs managed by Jamf Pro, it’s possible to trigger the Jamf agent from the command line to do the following tasks:

  1. Verify that the Jamf agent on the Mac can contact the Jamf Pro server.
  2. Collect an inventory update from the Mac and submit it to the Jamf Pro server

The commands to do so are the following:

Verify connection to the Jamf Pro server:


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


/usr/local/jamf/bin/jamf checkJSSConnection
view raw

gistfile1.txt

hosted with ❤ by GitHub

Collect and submit an inventory update to the Jamf Pro server:


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


/usr/local/jamf/bin/jamf recon
view raw

gistfile1.txt

hosted with ❤ by GitHub

The following command should do the following:

  1. Try for 60 seconds to verify the connection to the Jamf Pro server
  2. If connection is successfully verified, collect and submit an inventory update to the Jamf Pro server.


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


/usr/local/jamf/bin/jamf checkJSSConnection -retry 60 && /usr/local/jamf/bin/jamf recon
view raw

gistfile1.txt

hosted with ❤ by GitHub

Note: The && in the command will ensure that the second command (the inventory update) will only run if the previous command runs without errors. If the connection can’t be verified, the jamf checkJSSConnection command will exit with an error status. The error status will mean that the subsequent inventory update command won’t be executed.

The command above can be added to a LaunchDaemon like the one shown below. Installing this LaunchDaemon will ensure that the two commands (connection verification and inventory update) are run every time the Mac starts.


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


<?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">
<dict>
<key>Label</key>
<string>com.github.runjamfproinventoryupdate</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>/usr/local/jamf/bin/jamf checkJSSConnection -retry 60 && /usr/local/jamf/bin/jamf recon</string>
</array>
</dict>
</plist>

You can deploy this LaunchDaemon using a script like the one shown below. The example script shown below will do the following:

  1. Create the LaunchDaemon file on the Mac in question.
  2. Set the correct permissions on the LaunchDaemon file
  3. Install the LaunchDaemon file into /Library/LaunchDaemons
  4. Load the LaunchDaemon
  5. Verify that the LaunchDaemon is in place and loaded.

Note: Once the LaunchDaemon is loaded, the Jamf agent on Mac will immediately perform the following actions:

  1. Try for 60 seconds to verify the connection to the Jamf Pro server
  2. If connection is successfully verified, collect and submit an inventory update to the Jamf Pro server.

The LaunchDaemon will also be loaded by the Mac at startup, so the same actions will also performed any time the Mac starts up.


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


#!/bin/bash
# Script which installs a LaunchDaemon which runs a Jamf inventory update at startup time.
#
# The LaunchDaemon takes the following actions:
#
# * Verifies that the Mac can communicate with the Jamf Pro server.
# * Sends an updated inventory to the Jamf Pro server
#
# Create the jamf_inventory_update_at_boot LaunchDaemon by using cat input redirection
# to write the XML contained below to a new file.
#
# The LaunchDaemon will run when when loaded and also when the Mac boots up.
# Set the identifier for the LaunchDaemon
LaunchDaemonName="com.github.runjamfproinventoryupdate"
# Set exit code
ERROR=0
# Create temp directory to store LaunchDaemon file inside at file creation time.
temp_directory=$(mktemp -d)
# Create the LaunchDaemon file
/bin/cat > "$temp_directory/$LaunchDaemonName.plist" << JAMF_PRO_INVENTORY_UPDATE_LAUNCHDAEMON
<?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">
<dict>
<key>Label</key>
<string>$LaunchDaemonName</string>
<key>ProgramArguments</key>
<array>
<string>sh</string>
<string>-c</string>
<string>/usr/local/jamf/bin/jamf checkJSSConnection -retry 60 && /usr/local/jamf/bin/jamf recon</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
JAMF_PRO_INVENTORY_UPDATE_LAUNCHDAEMON
# Once the LaunchDaemon file has been created, fix the permissions
# so that the file is owned by root:wheel and set to not be executable
# After the permissions have been updated, move the LaunchDaemon into
# place in /Library/LaunchDaemons.
/usr/sbin/chown root:wheel "${temp_directory}/${LaunchDaemonName}.plist"
/bin/chmod 644 "${temp_directory}/${LaunchDaemonName}.plist"
/bin/chmod a-x "${temp_directory}/${LaunchDaemonName}.plist"
/bin/mv "${temp_directory}/${LaunchDaemonName}.plist" "/Library/LaunchDaemons/${LaunchDaemonName}.plist"
# After the LaunchDaemon is place with proper permissions, load the LaunchDaemon.
# Loading the launchdaemon will trigger an Jamf Pro inventory update to be run.
if [[ -f "/Library/LaunchDaemons/${LaunchDaemonName}.plist" ]]; then
/bin/launchctl bootstrap system "/Library/LaunchDaemons/${LaunchDaemonName}.plist"
fi
# Remove temp directory
/bin/rm -rf "$temp_directory"
if [[ -f "/Library/LaunchDaemons/${LaunchDaemonName}.plist" ]]; then
LaunchDaemonLoaded=$(/bin/launchctl list | grep -o "$LaunchDaemonName")
if [[ -n "$LaunchDaemonLoaded" ]]; then
echo "$LaunchDaemonName LaunchDaemon is loaded. Jamf Pro inventory updates will run when the Mac boots."
else
echo "ERROR: $LaunchDaemonName LaunchDaemon is not loaded."
ERROR=1
fi
else
echo "ERROR: $LaunchDaemonName.plist LaunchDaemon file was not created successfully."
ERROR=1
fi
exit "$ERROR"

Running Jamf Pro inventory updates at startup time using a Jamf Pro policy

$
0
0

As a follow-up to my previous post on running Jamf Pro inventory updates at startup, several folks have asked if the approach I showed was better or more efficient than using a Jamf Pro policy to run the inventory update. I thought about it and I can’t say for certain if the LaunchDaemon-driven approach I described is better than using a Jamf Pro policy.

The advantage of the LaunchDaemon-driven approach has is that the Mac admin has control of the options being used. In my example solution’s case, I have jamf checkJSSConnection checking for up to 60 seconds before giving up. Depending on your network setup, it may take that long before your Mac can verify it can talk to the Jamf Pro server.

If you’re running an inventory update via a Jamf policy’s startup trigger, you’re using whatever configuration Jamf has chosen for making sure the policy is triggered when you want it to be. Jamf’s choices may be the right ones, but those choices are being made by Jamf and not the individual Mac admin.

That said, collecting and submitting inventory updates to Jamf Pro is a problem which can be solved multiple ways and what I presented in my previous blog post was a solution, but not the only solution. With that in mind, please see below the jump for details on how to solve the problem of collecting and submitting inventory updates at startup using a Jamf Pro policy.

You can set up a Jamf Pro policy with the following options to collecting and submit inventory updates to Jamf Pro when a Mac starts up:

1. Under the General policy options, set the following trigger and execution frequency:

  • Trigger: Startup
  • Execution Frequency: Ongoing

Screen Shot 2022 10 09 at 4 51 56 PM

2. Under the Maintenance policy options, set the following option:

  • Update Inventory: Check the box to select this option

Screen Shot 2022 10 09 at 4 52 00 PM

 

All other options (scoping, category, user interaction, etc.) can be set according to the individual Mac admins’s preferences.

Opening macOS Ventura’s System Settings to desired locations via the command line

$
0
0

With the release of macOS Ventura, the System Preferences application has been replaced with the System Settings application.

macOS Monterey System Preferences:

Screen Shot 2022 10 25 at 3 08 11 PM

macOS Ventura System Settings:

Screenshot 2022 10 25 at 3 10 04 PM

Along with this change, a number of previously-known commands for opening individual System Preferences preference panes from the command line no longer work with System Settings.

However, it looks like the underlying command line functionality wasn’t changed by Apple. You just need to know what the new options are to enter. For more details, please see below the jump.

I’ve put together a list of the ones I’ve found to work, which is available below. Find any more? Please let me know in the comments:


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


Open Storage, in System Settings: General:
open x-apple.systempreferences:com.apple.settings.Storage
Open Software Update, in System Settings: General:
open x-apple.systempreferences:com.apple.Software-Update-Settings.extension
Open General, in System Settings:
open x-apple.systempreferences:com.apple.systempreferences.GeneralSettings
Open Privacy & Security, in System Settings:
open x-apple.systempreferences:com.apple.preference.security
Open Privacy & Security, in System Settings:
open x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension
Open Startup Disk, in System Settings: General:
open x-apple.systempreferences:com.apple.preference.startupdisk
Open Startup Disk, in System Settings: General:
open x-apple.systempreferences:com.apple.Startup-Disk-Settings.extension
Open Displays, in System Settings:
open x-apple.systempreferences:com.apple.preference.displays
Open Wallpaper, in System Settings:
open x-apple.systempreferences:com.apple.Wallpaper-Settings.extension
Open Network, in System Settings:
open x-apple.systempreferences:com.apple.preference.network
Open Network, in System Settings:
open x-apple.systempreferences:com.apple.Network-Settings.extension
Open Profiles, in System Settings: Privacy & Security:
open x-apple.systempreferences:com.apple.Profiles-Settings.extension
Open Transfer or Reset, in System Settings: General:
open x-apple.systempreferences:com.apple.Transfer-Reset-Settings.extension
Open Date & Time, in System Settings: General:
open x-apple.systempreferences:com.apple.Date-Time-Settings.extension
Open About, in System Settings: General:
open x-apple.systempreferences:com.apple.SystemProfiler.AboutExtension
Open Language & Region, in System Settings: General:
open x-apple.systempreferences:com.apple.Localization-Settings.extension
Open Login Items, in System Settings: General:
open x-apple.systempreferences:com.apple.LoginItems-Settings.extension
Open Sharing, in System Settings: General:
open x-apple.systempreferences:com.apple.Sharing-Settings.extension
Open AirDrop & Handoff, in System Settings: General
open x-apple.systempreferences:com.apple.AirDrop-Handoff-Settings.extension
Open Time Machine, in System Settings: General
open x-apple.systempreferences:com.apple.Time-Machine-Settings.extension
Open Appearance, in System Settings:
open x-apple.systempreferences:com.apple.Appearance-Settings.extension
Open Apple ID, in System Settings:
open x-apple.systempreferences:com.apple.preferences.AppleIDPrefPane

Adding hidden Login Items on macOS Ventura

$
0
0

One of the changes made between macOS Monterey’s System Preferences and macOS Ventura’s System Settings is that the Hide checkbox in System Preferences’ Login Items has disappeared from System Settings’ Login Items.

Login Items in System Preferences

Screen Shot 2022 10 27 at 2 25 28 PM

Login Items in System Settings

Screenshot 2022 10 27 at 2 40 18 PM

Fortunately for those who want to continue being able to launch applications on login and automatically hide them, it’s still possible to do so on macOS Ventura from the command line using osascript.

To do this, run a command similar to the one shown below using the logged-in user’s privileges:

/usr/bin/osascript -e 'tell application "System Events" to make login item at end with properties {path:"/path/to/itemname", hidden:true}'

For example, if you want Safari to launch at login with its windows automatically hidden, run the command below using the logged-in user’s privileges:

/usr/bin/osascript -e 'tell application "System Events" to make login item at end with properties {path:"/Applications/Safari.app", hidden:true}'

Safari will appear in the Login Items list without any sign that it’s launching as hidden, but the application behavior on login will be just like it would be on earlier versions of macOS where the Hide checkbox was checked.

Downloading macOS Monterey from the App Store

$
0
0

Now that macOS Ventura has been released, it’s become more difficult to access the macOS Monterey installer for those who still need it. Fortunately, macOS Monterey has not been removed from the App Store and it is still available for download. Apple has a KBase article that shows how to access the macOS Monterey page in the App Store, available via the link below:

https://support.apple.com/HT211683

Screenshot 2022 11 11 at 5 24 32 PM

To access the macOS Monterey page directly, please click on the link below:

https://apps.apple.com/us/app/macos-monterey/id1576738294?mt=12

That link should open the App Store and take you to the macOS Monterey download page.

Screenshot 2022 11 11 at 5 26 18 PM

 

In the event that you’re blocked from downloading macOS Monterey, you should be able to download it in a virtual machine. I have a post on how to do this, available via the link below:

https://derflounder.wordpress.com/2017/02/21/downloading-older-os-installers-on-incompatible-hardware-using-vms/

Creating a NexThink installer for deployment via Jamf Pro

$
0
0

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:

  1. Involves an application named csi.app, which has a command line tool.
  2. The referenced csi app’s command line tool configures and runs an installer package.
  3. 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


—–BEGIN CUSTOMER KEY—–MIIDhzCCAm+gAwIBAgIEIa+KoTANBgkqhkiG9w0BAQsFADBbMScwJQYDVQQDDB5SZWdlcnkgU2VsZi1TaWduZWQgQ2VydGlmaWNhdGUxIzAhBgNVBAoMGlJlZ2VyeSwgaHR0cHM6Ly9yZWdlcnkuY29tMQswCQYDVQQGEwJVQTAgFw0yMjEyMDIwMDAwMDBaGA8yMTIyMTIwMjIwMDIxMFowSTEVMBMGA1UEAwwMbG9jYWxob3N0LmlvMSMwIQYDVQQKDBpSZWdlcnksIGh0dHBzOi8vcmVnZXJ5LmNvbTELMAkGA1UEBhMCVUEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaKRW9KeX4wg/838FkxmzaBjqf1DeKD5GKEqhUKz0y78Wwnsv2zAXGM4UkdZJP9zHtC9/wFQT+lhclDlogxkU9lfMADV7nMdGL0GkJzwMQNS52dPNXDup7/d9yRkyjkV0Pf4t2fJF3igoNXFQuBvuArkNV6hfja2gOEczOSAaJ7L7qRnSahLjciJRaCuEPjwneh3krhOFT+djwuYJMIvBDEqs+gfp4OPDDBtVg2scUUGRmHsC+JAoK+JwqYwB9TNt+9hZtGfDqgZSHebXEfRTguhQpBj0mPTo76EahAbHbXJhV+efg3jt32pZ6qRl8ffrZAjefWEAnOMyXQ7fbL+bpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRNHRZG3IKNH0kTRaiVfq6N8Ovp5zAfBgNVHSMEGDAWgBRNHRZG3IKNH0kTRaiVfq6N8Ovp5zANBgkqhkiG9w0BAQsFAAOCAQEAhpbntg+nwhIKgRuUidu/wXn197Ah0Pd4CYYxG5dR9rg8nWObx4QO6ApIH91nUUQVuV6mSTFtfy4yNQzxaROgZP9hDNvhd78D/ewXxp6bN/Xkn+c7SWrs/b1vHb2Dr1sDP4F9SAOrCI6TdoYa8UNhPXXSTt8M/hGSB2oWOpT2FAb2IbdmdYhDaibcJwp+/Had1FLbeDZgdgYCFoZLjws/9E/pIXjSxBYAJLbaQZffrfO5jCe2KesE73iQatW2IPynsFifRGGoMHXVLOfsLA9c2KDGqDmnJ+PvsBSe9rIpSJYC4WjR5Mt8W88kQSj05b9NqCsXmmMDEbD8uVLyKvQihA==—–END CUSTOMER KEY—–

All the needed components with the exception of the CustomerKey file, which is different for each customer, ship on a disk image.

Screenshot 2022 12 02 at 3 31 46 PM

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.

Screenshot 2022 12 02 at 3 46 29 PM

 

Screenshot 2022 12 02 at 3 46 39 PM

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.

Screenshot 2022 12 02 at 3 46 53 PM

 

Screenshot 2022 12 02 at 3 47 02 PM

 

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.

Screenshot 2022 12 02 at 3 47 10 PM

In my case, I decided to do the following to deploy it via Jamf Pro:

  1. Wrap the disk image and CustomerKey file inside a separate installer package.
  2. 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.

Pre-requisites:

  • Packages
  • 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.

Screenshot 2022 12 02 at 4 09 34 PM

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.

Screenshot 2022 12 02 at 4 09 23 PM

 

Building the NexThink Collector installer

1. Set up a new Packages project and select Raw Package.

Screenshot 2022 12 02 at 3 59 32 PM

2. In this case, I’m naming the project NexThink Collector Install 22.9.1.14.

Screenshot 2022 12 02 at 4 00 21 PM

 

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.)

Screenshot 2022 12 02 at 4 01 46 PM

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

Screenshot 2022 12 02 at 4 02 39 PM

 

5. Select the Payload tab. Nothing here should be changed from the defaults.

Screenshot 2022 12 02 at 4 03 01 PM

 

6. Select the Scripts tab.

Under the Additional Resources section, add the following file and directory:

The NexThink disk image

Screenshot 2022 12 02 at 7 54 53 PM

Screenshot 2022 12 03 at 11 30 32 AM

The CustomerKeys directory containing the CustomerKey file.

Screenshot 2022 12 02 at 7 55 10 PM

Screenshot 2022 12 03 at 11 30 08 AM

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


#!/bin/bash
# Description: Script to install the NexThink Collector agent using the csi.app's command-line
# options to install and register the NextThink agent using your organization's Customer Key.
ERROR=0
# File Paths
if [[ -f "$(/usr/bin/find $(dirname $0) -maxdepth 1 \( -iname \*\.dmg \))" ]]; then
dmgFile="$(/usr/bin/find $(dirname $0) -maxdepth 1 \( -iname \*\.dmg \))"
fi
dmgMount="$(/usr/bin/mktemp -d /tmp/NexThink_Collector.XXXX)"
csiAppPath="$dmgMount/csi.app/Contents/MacOS/"
# Remove the trailing slash from the csiAppPath variable if needed.
csiAppPath=${csiAppPath%%/}
#installer variables
udpport="999"
tcpport="443"
tcpdata="enable"
assignment="enable"
tag_value="0"
nexthink_address="nexthink.server.goes.here"
customerKey="$(dirname $0)/CustomerKeys/*.txt"
# Mount the DMG
/usr/bin/hdiutil attach "$dmgFile" -mountpoint "$dmgMount" -nobrowse -noverify -noautoopen
# Install the Nextthink Collector software
# Define the parameters for csi.app for installing the Collector from the command line interface
"$csiAppPath"/csi -address "$nexthink_address" -port "$udpport" -tcp_port "$tcpport" -key "$customerKey" -data_over_tcp "$tcpdata" -use_assignment "$assignment" -tag $"tag_value"
#Disable/Enable Coordinator Service
launchctl bootout system /Library/LaunchDaemons/com.nexthink.collector.nxtcoordinator.plist
launchctl bootstrap system /Library/LaunchDaemons/com.nexthink.collector.nxtcoordinator.plist
# Unmount the DMG
hdiutil detach $dmgMount -force
exit $ERROR
view raw

postinstall

hosted with ❤ by GitHub

If not already selected, select the postinstall script and add it to the project.

Screenshot 2022 12 03 at 11 32 56 AM

Screenshot 2022 12 03 at 11 33 04 AM

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:

https://docs.nexthink.com/platform/latest/installing-collector-on-macos

 

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.


Creating a NexThink uninstaller for deployment via Jamf Pro

$
0
0

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.

Screenshot 2022 12 03 at 3 31 46 PM

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.

Screenshot 2022 12 03 at 3 47 10 PM

In my case, I decided to do the following to deploy the uninstaller via Jamf Pro:

  1. Wrap the disk image inside a separate installer package.
  2. 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.

For more details, please see below the jump.

Pre-requisites:

  • Packages
  • 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.

Screenshot 2022 12 04 at 3 53 01 PM

 

2. In this case, I’m naming the project NexThink Collector Uninstaller 22.9.1.14.

Screenshot 2022 12 04 at 3 53 24 PM

 

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.)

Screenshot 2022 12 04 at 3 53 48 PM

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

Screenshot 2022 12 04 at 3 54 48 PM

 

5. Select the Payload tab. Nothing here should be changed from the defaults.

Screenshot 2022 12 04 at 3 54 58 PM

 

6. Select the Scripts tab.

Under the Additional Resources section, add the following file:

  • The NexThink disk image

Screenshot 2022 12 04 at 3 56 04 PM

Screenshot 2022 12 04 at 3 56 08 PM

 

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


#!/bin/bash
# Description: Script to uninstall NexThink Collector.
ERROR=0
# File Paths
if [[ -f "$(/usr/bin/find $(dirname $0) -maxdepth 1 \( -iname \*\.dmg \))" ]]; then
dmgFile="$(/usr/bin/find $(dirname $0) -maxdepth 1 \( -iname \*\.dmg \))"
fi
dmgMount="$(/usr/bin/mktemp -d /tmp/NexThink_Collector_Uninstaller.XXXX)"
# Remove the trailing slash from the dmgMount variable if needed.
dmgMount=${dmgMount%%/}
# Mount the DMG
/usr/bin/hdiutil attach "$dmgFile" -mountpoint "$dmgMount" -nobrowse -noverify -noautoopen
# Uninstall the NexThink Collector software
"$dmgMount"/uninstaller
# Unmount the DMG
hdiutil detach $dmgMount -force
exit $ERROR
view raw

postinstall

hosted with ❤ by GitHub

If not already selected, select the postinstall script and add it to the project.

Screenshot 2022 12 04 at 3 56 20 PM

Screenshot 2022 12 04 at 3 56 24 PM

 

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.

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

$
0
0

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:


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


<?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:


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


<?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.

There is an existing AutoPkg .download recipe for GlobalProtect, available via the link below:

https://github.com/autopkg/peshay-recipes/blob/master/PaloAlto/GlobalProtect.download.recipe

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


<?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">
<dict>
<key>Description</key>
<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>
<key>Identifier</key>
<string>com.company.pkg.GlobalProtect</string>
<key>Input</key>
<dict>
<key>NAME</key>
<string>GlobalProtect</string>
<key>VENDOR</key>
<string>PaloAlto</string>
<key>SOFTWARETITLE</key>
<string>GlobalProtect</string>
</dict>
<key>MinimumVersion</key>
<string>1.0.0</string>
<key>ParentRecipe</key>
<string>com.company.download.GlobalProtect</string>
<key>Process</key>
<array>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/unpack</string>
<key>flat_pkg_path</key>
<string>%pathname%</string>
</dict>
<key>Processor</key>
<string>FlatPkgUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>pattern</key>
<string>%RECIPE_CACHE_DIR%/unpack/*gp.pkg</string>
</dict>
<key>Processor</key>
<string>FileFinder</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app</string>
<key>pkg_payload_path</key>
<string>%found_filename%/Payload</string>
</dict>
<key>Processor</key>
<string>PkgPayloadUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>input_plist_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app/Contents/Info.plist</string>
<key>plist_version_key</key>
<string>CFBundleShortVersionString</string>
</dict>
<key>Processor</key>
<string>Versioner</string>
</dict>
<dict>
<key>Processor</key>
<string>PkgCopier</string>
<key>Arguments</key>
<dict>
<key>source_pkg</key>
<string>%pathname%</string>
<key>pkg_path</key>
<string>%RECIPE_CACHE_DIR%/%VENDOR%_%SOFTWARETITLE%_%version%.pkg</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>PathDeleter</string>
<key>Arguments</key>
<dict>
<key>path_list</key>
<array>
<string>%RECIPE_CACHE_DIR%/unpack</string>
<string>%RECIPE_CACHE_DIR%/payload</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

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:

  1. An installer choices XML file
  2. 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


<?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">
<dict>
<key>Description</key>
<string>Downloads the current release version of the Global Protect VPN client and builds an installer package which uninstalls Global Protect.</string>
<key>Identifier</key>
<string>com.company.pkg.GlobalProtect.uninstall</string>
<key>Input</key>
<dict>
<key>NAME</key>
<string>GlobalProtect</string>
<key>VENDOR</key>
<string>PaloAlto</string>
<key>SOFTWARETITLE1</key>
<string>GlobalProtect</string>
<key>SOFTWARETITLE2</key>
<string>Uninstaller</string>
</dict>
<key>MinimumVersion</key>
<string>1.0.0</string>
<key>ParentRecipe</key>
<string>com.company.download.GlobalProtect</string>
<key>Process</key>
<array>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/unpack</string>
<key>flat_pkg_path</key>
<string>%pathname%</string>
</dict>
<key>Processor</key>
<string>FlatPkgUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>pattern</key>
<string>%RECIPE_CACHE_DIR%/unpack/*gp.pkg</string>
</dict>
<key>Processor</key>
<string>FileFinder</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app</string>
<key>pkg_payload_path</key>
<string>%found_filename%/Payload</string>
</dict>
<key>Processor</key>
<string>PkgPayloadUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>input_plist_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app/Contents/Info.plist</string>
<key>plist_version_key</key>
<string>CFBundleShortVersionString</string>
</dict>
<key>Processor</key>
<string>Versioner</string>
</dict>
<dict>
<key>Processor</key>
<string>PkgRootCreator</string>
<key>Arguments</key>
<dict>
<key>pkgroot</key>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<key>pkgdirs</key>
<dict>
<key>Scripts</key>
<string>0755</string>
</dict>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileMover</string>
<key>Arguments</key>
<dict>
<key>source</key>
<string>%RECIPE_CACHE_DIR%/pkgroot/Scripts</string>
<key>target</key>
<string>%RECIPE_CACHE_DIR%/Scripts</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>PkgCopier</string>
<key>Arguments</key>
<dict>
<key>source_pkg</key>
<string>%pathname%</string>
<key>pkg_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/GlobalProtect.pkg</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileCreator</string>
<key>Arguments</key>
<dict>
<key>file_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/uninstall_global_protect.xml</string>
<key>file_mode</key>
<string>0755</string>
<key>file_content</key>
<string>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;array&gt;
&lt;dict&gt;
&lt;key&gt;attributeSetting&lt;/key&gt;
&lt;integer&gt;1&lt;/integer&gt;
&lt;key&gt;choiceAttribute&lt;/key&gt;
&lt;string&gt;selected&lt;/string&gt;
&lt;key&gt;choiceIdentifier&lt;/key&gt;
&lt;string&gt;second&lt;/string&gt;
&lt;/dict&gt;
&lt;dict&gt;
&lt;key&gt;attributeSetting&lt;/key&gt;
&lt;integer&gt;1&lt;/integer&gt;
&lt;key&gt;choiceAttribute&lt;/key&gt;
&lt;string&gt;selected&lt;/string&gt;
&lt;key&gt;choiceIdentifier&lt;/key&gt;
&lt;string&gt;com.paloaltonetworks.globalprotect.uninstall.pkg&lt;/string&gt;
&lt;/dict&gt;
&lt;/array&gt;
&lt;/plist&gt;</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileCreator</string>
<key>Arguments</key>
<dict>
<key>file_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/postinstall</string>
<key>file_mode</key>
<string>0755</string>
<key>file_content</key>
<string>#!/bin/bash
PKG="${0%/*}/GlobalProtect.pkg"
ChoiceChangesXMLFile="${0%/*}/uninstall_global_protect.xml"
ERROR=0
if [[ -f "$PKG" ]]; then
/usr/sbin/installer -pkg "$PKG" -applyChoiceChangesXML "$ChoiceChangesXMLFile" -target "$3"
if [[ $? -ne 0 ]]; then
/usr/bin/logger -t "${0##*/}" "ERROR! Installation of package $PKG failed"
ERROR=1
fi
else
/usr/bin/logger -t "${0##*/}" "ERROR! Package $PKG not found"
ERROR=1
fi
exit $ERROR</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>PkgCreator</string>
<key>Arguments</key>
<dict>
<key>pkg_request</key>
<dict>
<key>pkgroot</key>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<key>pkgname</key>
<string>%VENDOR%_%SOFTWARETITLE1%_%SOFTWARETITLE2%_%version%</string>
<key>pkgtype</key>
<string>flat</string>
<key>id</key>
<string>com.company.GlobalProtectUninstall.pkg</string>
<key>options</key>
<string>purge_ds_store</string>
<key>scripts</key>
<string>Scripts</string>
<key>version</key>
<string>%version%</string>
</dict>
</dict>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>path_list</key>
<array>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<string>%RECIPE_CACHE_DIR%/payload</string>
<string>%RECIPE_CACHE_DIR%/Scripts</string>
<string>%RECIPE_CACHE_DIR%/unpack</string>
</array>
</dict>
<key>Processor</key>
<string>PathDeleter</string>
</dict>
</array>
</dict>
</plist>

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


<?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">
<dict>
<key>Description</key>
<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>
<key>Identifier</key>
<string>com.company.pkg.GlobalProtect.systemextension</string>
<key>Input</key>
<dict>
<key>NAME</key>
<string>GlobalProtect</string>
<key>VENDOR</key>
<string>PaloAlto</string>
<key>SOFTWARETITLE1</key>
<string>GlobalProtect</string>
<key>SOFTWARETITLE2</key>
<string>System</string>
<key>SOFTWARETITLE3</key>
<string>Extension</string>
<key>SOFTWARETITLE4</key>
<string>Enabler</string>
</dict>
<key>MinimumVersion</key>
<string>1.0.0</string>
<key>ParentRecipe</key>
<string>com.company.download.GlobalProtect</string>
<key>Process</key>
<array>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/unpack</string>
<key>flat_pkg_path</key>
<string>%pathname%</string>
</dict>
<key>Processor</key>
<string>FlatPkgUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>pattern</key>
<string>%RECIPE_CACHE_DIR%/unpack/*gp.pkg</string>
</dict>
<key>Processor</key>
<string>FileFinder</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>destination_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app</string>
<key>pkg_payload_path</key>
<string>%found_filename%/Payload</string>
</dict>
<key>Processor</key>
<string>PkgPayloadUnpacker</string>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>input_plist_path</key>
<string>%RECIPE_CACHE_DIR%/payload/GlobalProtect.app/Contents/Info.plist</string>
<key>plist_version_key</key>
<string>CFBundleShortVersionString</string>
</dict>
<key>Processor</key>
<string>Versioner</string>
</dict>
<dict>
<key>Processor</key>
<string>PkgRootCreator</string>
<key>Arguments</key>
<dict>
<key>pkgroot</key>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<key>pkgdirs</key>
<dict>
<key>Scripts</key>
<string>0755</string>
</dict>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileMover</string>
<key>Arguments</key>
<dict>
<key>source</key>
<string>%RECIPE_CACHE_DIR%/pkgroot/Scripts</string>
<key>target</key>
<string>%RECIPE_CACHE_DIR%/Scripts</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>PkgCopier</string>
<key>Arguments</key>
<dict>
<key>source_pkg</key>
<string>%pathname%</string>
<key>pkg_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/GlobalProtect.pkg</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileCreator</string>
<key>Arguments</key>
<dict>
<key>file_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/install_system_extensions.xml</string>
<key>file_mode</key>
<string>0755</string>
<key>file_content</key>
<string>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;array&gt;
&lt;dict&gt;
&lt;key&gt;attributeSetting&lt;/key&gt;
&lt;integer&gt;1&lt;/integer&gt;
&lt;key&gt;choiceAttribute&lt;/key&gt;
&lt;string&gt;selected&lt;/string&gt;
&lt;key&gt;choiceIdentifier&lt;/key&gt;
&lt;string&gt;third&lt;/string&gt;
&lt;/dict&gt;
&lt;dict&gt;
&lt;key&gt;attributeSetting&lt;/key&gt;
&lt;integer&gt;1&lt;/integer&gt;
&lt;key&gt;choiceAttribute&lt;/key&gt;
&lt;string&gt;selected&lt;/string&gt;
&lt;key&gt;choiceIdentifier&lt;/key&gt;
&lt;string&gt;com.paloaltonetworks.globalprotect.systemext.pkg&lt;/string&gt;
&lt;/dict&gt;
&lt;/array&gt;
&lt;/plist&gt;</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>FileCreator</string>
<key>Arguments</key>
<dict>
<key>file_path</key>
<string>%RECIPE_CACHE_DIR%/Scripts/postinstall</string>
<key>file_mode</key>
<string>0755</string>
<key>file_content</key>
<string>#!/bin/bash
PKG="${0%/*}/GlobalProtect.pkg"
ChoiceChangesXMLFile="${0%/*}/install_system_extensions.xml"
ERROR=0
if [[ -f "$PKG" ]]; then
/usr/sbin/installer -pkg "$PKG" -applyChoiceChangesXML "$ChoiceChangesXMLFile" -target "$3"
if [[ $? -ne 0 ]]; then
/usr/bin/logger -t "${0##*/}" "ERROR! Installation of package $PKG failed"
ERROR=1
fi
else
/usr/bin/logger -t "${0##*/}" "ERROR! Package $PKG not found"
ERROR=1
fi
exit $ERROR</string>
</dict>
</dict>
<dict>
<key>Processor</key>
<string>PkgCreator</string>
<key>Arguments</key>
<dict>
<key>pkg_request</key>
<dict>
<key>pkgroot</key>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<key>pkgname</key>
<string>%VENDOR%_%SOFTWARETITLE1%_%SOFTWARETITLE2%_%SOFTWARETITLE3%_%SOFTWARETITLE4%_%version%</string>
<key>pkgtype</key>
<string>flat</string>
<key>id</key>
<string>com.company.GlobalProtectSystemExtensionEnable.pkg</string>
<key>options</key>
<string>purge_ds_store</string>
<key>scripts</key>
<string>Scripts</string>
<key>version</key>
<string>%version%</string>
</dict>
</dict>
</dict>
<dict>
<key>Arguments</key>
<dict>
<key>path_list</key>
<array>
<string>%RECIPE_CACHE_DIR%/pkgroot</string>
<string>%RECIPE_CACHE_DIR%/payload</string>
<string>%RECIPE_CACHE_DIR%/Scripts</string>
<string>%RECIPE_CACHE_DIR%/unpack</string>
</array>
</dict>
<key>Processor</key>
<string>PathDeleter</string>
</dict>
</array>
</dict>
</plist>

When does the upgrade to macOS Ventura need admin rights?

$
0
0

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.

Screen Shot 2022 12 19 at 12 40 55 PM

3. If the macOS Ventura upgrade is listed there, click on the Upgrade Now button.

Screen Shot 2022 12 19 at 11 19 59 AM

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.

Screen Shot 2022 12 19 at 11 23 04 AM

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.

Screen Shot 2022 12 19 at 11 24 31 AM

macOS 12.21 or earlier

1. You see a macOS Ventura installer which is around 12 GBs or more.

Screen Shot 2022 12 19 at 11 18 59 AM

2. It downloads an Install macOS Ventura app to your Mac and installs it in /Applications.

Screen Shot 2022 12 19 at 12 31 54 PM

3. The Install macOS Ventura app automatically launches once download and installation of the application completes.

Screen Shot 2022 12 19 at 12 31 57 PM

4. Running the Install macOS Ventura app will prompt for a user with administrator privileges to authenticate before the upgrade proceeds.

Screen Shot 2022 12 19 at 12 32 17 PM

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:

  1. The need to run the macOS Ventura full installer
  2. 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:

Identifying Mac laptops and desktops from the command line by checking for a built-in battery

$
0
0

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


#!/bin/bash
# Set separate power management settings for desktops and laptops
# If it's a laptop, the power management settings for "Battery" are set to have the computer sleep in 15 minutes,
# disk will spin down in 10 minutes, the display will sleep in 5 minutes and the display itself will dim to
# half-brightness before sleeping. While plugged into the AC adapter, the power management settings for "Charger"
# are set to have the computer never sleep, the disk doesn't spin down, the display sleeps after 30 minutes and
# the display dims before sleeping.
#
# If it's not a laptop (i.e. a desktop), the power management settings are set to have the computer never sleep,
# the disk doesn't spin down, the display sleeps after 30 minutes and the display dims before sleeping.
#
# Detects if this Mac is a laptop or not by checking the model ID for the word "Book" in the name.
IS_LAPTOP=$(/usr/sbin/system_profiler SPHardwareDataType | grep "Model Identifier" | grep "Book")
if [[ -n "$IS_LAPTOP" ]]; then
/usr/bin/pmset -b sleep 15 disksleep 10 displaysleep 5 halfdim 1
/usr/bin/pmset -c sleep 0 disksleep 0 displaysleep 30 halfdim 1
else
/usr/bin/pmset sleep 0 disksleep 0 displaysleep 30 halfdim 1
fi
view raw

powersetings.sh

hosted with ❤ by GitHub

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”.

Screenshot 2022 12 23 at 5 51 44 PM

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


/usr/sbin/system_profiler SPHardwareDataType | grep "Model Identifier" | grep "Book"
view raw

gistfile1.txt

hosted with ❤ by GitHub

However, the latest Mac laptops’ model identifier does not contain “Book”. This means that this identification method should no longer be considered reliable.

Screenshot 2022 12 23 at 5 40 48 PM

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


/usr/sbin/ioreg -c AppleSmartBattery -r | awk '/built-in/ {print $3}'
view raw

gistfile1.txt

hosted with ❤ by GitHub

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


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/built-in/ {print $3}'
Yes
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

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


username@computername ~ % /usr/sbin/ioreg -c AppleSmartBattery -r | awk '/built-in/ {print $3}'
username@computername ~ %
view raw

gistfile1.txt

hosted with ❤ by GitHub

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


#!/bin/bash
# Set separate power management settings for desktops and laptops
# If it's a laptop, the power management settings for "Battery" are set to have the computer sleep in 15 minutes,
# disk will spin down in 10 minutes, the display will sleep in 5 minutes and the display itself will dim to
# half-brightness before sleeping. While plugged into the AC adapter, the power management settings for "Charger"
# are set to have the computer never sleep, the disk doesn't spin down, the display sleeps after 30 minutes and
# the display dims before sleeping.
#
# If it's not a laptop (i.e. a desktop), the power management settings are set to have the computer never sleep,
# the disk doesn't spin down, the display sleeps after 30 minutes and the display dims before sleeping.
#
# Detects if this Mac is a laptop or not by checking for a built-in battery.
IS_LAPTOP=$(/usr/sbin/ioreg -c AppleSmartBattery -r | awk '/built-in/ {print $3}')
if [[ -n "$IS_LAPTOP" ]]; then
/usr/bin/pmset -b sleep 15 disksleep 10 displaysleep 5 halfdim 1
/usr/bin/pmset -c sleep 0 disksleep 0 displaysleep 30 halfdim 1
else
/usr/bin/pmset sleep 0 disksleep 0 displaysleep 30 halfdim 1
fi

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.

Granting Volume Owner status on Apple Silicon Macs

$
0
0

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:

* There may be multiple installations of macOS on one Apple Silicon Mac; each macOS install would have their own startup security policy.

For more information on volume ownership, please see Apple’s Platform Deployment article linked below:

https://support.apple.com/guide/deployment/use-secure-and-bootstrap-tokens-dep24dbdcf9e/web (see the Volume ownership section.)

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


/usr/sbin/diskutil apfs listCryptoUsers /
view raw

gistfile1.txt

hosted with ❤ by GitHub

The user accounts with Secure Token assigned should appear listed with the following information:

  • Type: Local Open Directory User
  • Volume Owner: Yes

Screenshot-2023-03-10-at-4.42.10-PM.png

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


/usr/bin/dscl . -search /Users GeneratedUID UUID_goes_here | awk '{print $1}' | head -n 1
view raw

gistfile1.txt

hosted with ❤ by GitHub

Screenshot-2023-03-10-at-4.42.11-PM.png

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


/usr/sbin/sysadminctl -secureTokenStatus username_goes_here
view raw

gistfile1.txt

hosted with ❤ by GitHub

If the account does not have Secure Token assigned, the output of the command should tell you this.

Screenshot-2023-03-10-at-4.52.54-PM.png

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


/usr/sbin/sysadminctl -secureTokenOn username_goes_here -password password_goes_here -adminUser user_with_secure_token_goes_here -adminPassword admin_password_goes_here
view raw

gistfile1.txt

hosted with ❤ by GitHub

Screenshot-2023-03-10-at-4.54.53-PM.png

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


/usr/sbin/sysadminctl -secureTokenOn username_goes_here -password – -adminUser user_with_secure_token_goes_here -adminPassword –
view raw

gistfile1.txt

hosted with ❤ by GitHub

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


/usr/sbin/sysadminctl -secureTokenStatus username_goes_here
view raw

gistfile1.txt

hosted with ❤ by GitHub

The output should now tell you that Secure Token has been assigned to the account.

Screenshot-2023-03-10-at-5.09.41-PM.png

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


/usr/sbin/diskutil apfs listCryptoUsers /
view raw

gistfile1.txt

hosted with ❤ by GitHub

You should see a new entry listed with the following information:

  • Type: Local Open Directory User
  • Volume Owner: Yes

Screenshot-2023-03-10-at-5.21.10-PM.png

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


/usr/bin/dscl . -search /Users GeneratedUID UUID_goes_here | awk '{print $1}' | head -n 1
view raw

gistfile1.txt

hosted with ❤ by GitHub

The desired account’s username should appear in the output.

Screenshot-2023-03-10-at-5.21.11-PM.png

Viewing all 490 articles
Browse latest View live