Skip to content

Commit a6f9bb6

Browse files
authored
Merge pull request #205 from janparttimaa/master
Policy Enforcers: iManage Work Desktop & GlobalProtect + Fixing ABM DEP check bug
2 parents 97bf32d + 7a0aece commit a6f9bb6

File tree

6 files changed

+529
-2
lines changed

6 files changed

+529
-2
lines changed

macOS/Apps/Illumio VEN/illumioVENRegistrationInstaller.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ echo ""
9999
if [ "$abmcheck" = true ]; then
100100
echo "$(date) | Checking MDM Profile Type"
101101
profiles status -type enrollment | grep "Enrolled via DEP: Yes"
102-
if [ ! $? == 0 ]; then
102+
if [[ ! $? == 0 ]]; then
103103
echo "$(date) | This device is not ABM managed"
104104
exit 0;
105105
else

macOS/Apps/Illumio VEN/installIllumioVEN.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ echo ""
955955
if [ "$abmcheck" = true ]; then
956956
echo "$(date) | Checking MDM Profile Type"
957957
profiles status -type enrollment | grep "Enrolled via DEP: Yes"
958-
if [ ! $? == 0 ]; then
958+
if [[ ! $? == 0 ]]; then
959959
echo "$(date) | This device is not ABM managed"
960960
exit 0;
961961
else
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/bin/zsh
2+
#set -x
3+
############################################################################################
4+
##
5+
## Script to set and enforce policies to Palo Alto GlobalProtect on macOS (Machine Level)
6+
##
7+
############################################################################################
8+
9+
## Copyright (c) 2025 Microsoft Corp. All rights reserved.
10+
## Scripts are not supported under any Microsoft standard support program or service. The scripts are provided AS IS without warranty of any kind.
11+
## Microsoft disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a
12+
## particular purpose. The entire risk arising out of the use or performance of the scripts and documentation remains with you. In no event shall
13+
## Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever
14+
## (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary
15+
## loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility
16+
## of such damages.
17+
## Feedback: [email protected]
18+
19+
# Define variables
20+
appname="PaloAltoGlobalProtectPolicyEnforcerMachineLevel" # The name of our script
21+
plist="/Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist" # Location of plist for GlobalProtect
22+
plistbuddy="/usr/libexec/PlistBuddy" # Location of plistbuddy, that we will use
23+
logandmetadir="/Library/Logs/Microsoft/IntuneScripts/$appname" # The location of our logs and last updated data
24+
log="$logandmetadir/$appname.log" # The location of the script log file
25+
26+
# Create log directory if it doesn't exist
27+
if [ ! -d "$logandmetadir" ]; then
28+
echo "$(/bin/date) | Creating log directory - $logandmetadir"
29+
mkdir -p "$logandmetadir"
30+
else
31+
echo "$(/bin/date) | Log directory already exists - $logandmetadir"
32+
fi
33+
34+
# Ensure PlistBuddy exists
35+
if [ ! -x "$plistbuddy" ]; then
36+
echo "$(/bin/date) | ERROR: PlistBuddy not found at $plistbuddy"
37+
exit 1
38+
fi
39+
40+
# Ensure parent directory exists
41+
ensure_directory_exists() {
42+
local dir_path
43+
dir_path="$(dirname "$plist")"
44+
if [ ! -d "$dir_path" ]; then
45+
echo "$(/bin/date) | Creating directory: $dir_path"
46+
mkdir -p "$dir_path"
47+
else
48+
echo "$(/bin/date) | Directory already exists: $dir_path"
49+
fi
50+
}
51+
52+
# Ensure plist exist
53+
create_plist() {
54+
ensure_directory_exists
55+
if [[ ! -f "$plist" ]]; then
56+
echo "$(/bin/date) | [CREATE] Creating empty plist at $plist"
57+
$plistbuddy -c "Clear" "$plist" > /dev/null 2>&1
58+
fi
59+
}
60+
61+
# Ensure parent dictionaries exist
62+
ensure_parents_exist() {
63+
local path="$1"
64+
local plist="$2"
65+
66+
local -a parts
67+
parts=("${(@s/:/)path}")
68+
local quoted_parts=()
69+
70+
for part in "${parts[@]}"; do
71+
quoted_parts+=("'$part'")
72+
done
73+
74+
for ((i = 1; i < ${#quoted_parts[@]}; i++)); do
75+
local current_path="${(j/:/)quoted_parts[1,i]}"
76+
if ! $plistbuddy -c "Print $current_path" "$plist" &>/dev/null; then
77+
echo "$(/bin/date) | [ADD] Creating missing dictionary: ${(j/:/)parts[1,i]}"
78+
$plistbuddy -c "Add $current_path dict" "$plist"
79+
fi
80+
done
81+
}
82+
83+
# Enforce key value
84+
enforce_value() {
85+
local key_path="$1"
86+
local type="$2"
87+
local expected="$3"
88+
89+
ensure_parents_exist "$key_path" "$plist"
90+
91+
if $plistbuddy -c "Print '$key_path'" "$plist" &>/dev/null; then
92+
local current="$($plistbuddy -c "Print '$key_path'" "$plist")"
93+
if [[ "$current" != "$expected" ]]; then
94+
echo "$(/bin/date) | [UPDATE] $key_path: $current -> $expected"
95+
$plistbuddy -c "Set '$key_path' $expected" "$plist"
96+
else
97+
echo "$(/bin/date) | [OK] $key_path is already set to $expected"
98+
fi
99+
else
100+
echo "$(/bin/date) | [ADD] $key_path = $expected"
101+
$plistbuddy -c "Add '$key_path' $type $expected" "$plist"
102+
fi
103+
}
104+
105+
# Delete key if it exists
106+
delete_key() {
107+
local key_path="$1"
108+
if $plistbuddy -c "Print '$key_path'" "$plist" &>/dev/null; then
109+
echo "$(/bin/date) | [DELETE] Removing key: $key_path"
110+
$plistbuddy -c "Delete '$key_path'" "$plist"
111+
else
112+
echo "$(/bin/date) | [INFO] Key not found, nothing to delete: $key_path"
113+
fi
114+
}
115+
116+
# Start logging
117+
exec &> >(tee -a "$log")
118+
119+
# Begin Script Body
120+
echo ""
121+
echo "##############################################################"
122+
echo "# $(/bin/date) | Starting running of script $appname"
123+
echo "##############################################################"
124+
echo ""
125+
126+
# Run functions
127+
128+
# Apply Palo Alto GlobalProtect policies
129+
echo "$(/bin/date) | Applying Palo Alto GlobalProtect policies..."
130+
131+
# [CREATE] Create plist if not existed
132+
create_plist
133+
134+
# [ADD/UPDATE] GlobalProtect - PanSetup
135+
enforce_value "Palo Alto Networks:GlobalProtect:PanSetup:Portal" string "vpn.example.com" "$plist"
136+
enforce_value "Palo Alto Networks:GlobalProtect:PanSetup:Prelogon" string "1" "$plist"
137+
138+
# [ADD/UPDATE] GlobalProtect - Settings
139+
enforce_value "Palo Alto Networks:GlobalProtect:Settings:connect-method" string "pre-logon" "$plist"
140+
enforce_value "Palo Alto Networks:GlobalProtect:Settings:default-browser" string "no" "$plist"
141+
142+
# [DELETE] GlobalProtect - PanSetup (Example commented)
143+
# delete_key "Palo Alto Networks:GlobalProtect:PanSetup:Portal"
144+
145+
# End of script
146+
echo ""
147+
echo "$(/bin/date) | Script $appname completed."
148+
echo "##############################################################"
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Palo Alto GlobalProtect Policy Enforcer
2+
3+
In generally, Mobile Device Management systems like Microsoft Intune [support the distribution of standardized plist files to managed users](https://learn.microsoft.com/en-us/intune/intune-service/configuration/preference-file-settings-macos). This makes it easy to distribute updated plist files to users when specific settings need to be changed, removed, or added. These plist files are typically deployed to the `/Library/Managed Preferences` location.
4+
5+
Unfortunately, some applications, such as GlobalProtect for macOS, do not support reading plist files from this location. Instead, they read directly from `/Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist`. These policy enforcer scripts are specifically developed for such applications that do not support reading deployed plist files from `/Library/Managed Preferences`. The goal is to provide an easy way to distribute configuration values to these applications — whether it's for deploying new settings, modifying existing ones, or removing deprecated entries.
6+
7+
In this example, we provide a policy enforcer script for GlobalProtect on macOS.
8+
9+
## Palo Alto GlobalProtect Policy Enforcer (Machine Level)
10+
11+
> [!NOTE]
12+
> This script can be deployed as a separate script deployment or with a post-install script during GlobalProtect installation via Intune. We recommend using both options to ensure proper configuration.
13+
14+
This custom script is designed to **automate the configuration of GlobalProtect VPN policies** on macOS devices. It is especially useful in **MDM deployment scenarios** such as Microsoft Intune, where consistent and secure configuration across devices is critical.
15+
16+
### Purpose
17+
18+
This script ensures that key GlobalProtect settings are **created, updated, or removed** at the machine level using `PlistBuddy`. It helps enforce security, compliance, and user experience standards by:
19+
20+
- Disabling unnecessary or insecure features.
21+
- Enabling enterprise-grade protections.
22+
- Pre-configuring baseline settings of GlobalProtect to corporate environment.
23+
- Preventing users from changing critical settings. If user change those settings, they will be enforced back to defined values.
24+
25+
### Benefits
26+
27+
- ✅ Ensures **consistent policy enforcement** across all managed Macs
28+
- ✅ Reduces **manual configuration errors**
29+
- ✅ Supports **CIS/NIST-aligned hardening**
30+
- ✅ Fully **automated and silent** when deployed via Intune
31+
- ✅ Logs all actions for **auditability and troubleshooting**
32+
33+
---
34+
### What the Script Does
35+
36+
The script uses `PlistBuddy` to:
37+
38+
- **Create** missing `.plist` files and directories
39+
- **Add or update** specific keys and values
40+
- **Delete** obsolete or undesired keys (optional)
41+
42+
#### Policies (`com.paloaltonetworks.GlobalProtect.settings.plist`)
43+
44+
> [!NOTE]
45+
> - These are example settings and values. Modify as needed before deploying this script to managed devices.
46+
> - Please refer to [GlobalProtect Documentation](https://docs.paloaltonetworks.com/globalprotect/10-1/globalprotect-admin/globalprotect-apps/deploy-app-settings-transparently/customizable-app-settings#idd39ecf6d-6771-4ee3-a4d1-2ba5bbbad1bc) from Palo Alto Networks to validate which key/value pairs are supported and required.
47+
> - The script includes a commented-out example of how to delete values.
48+
> - This script enforces **machine-level** policies and does not target individual users.
49+
50+
| Key Path | Type | Value | Notes |
51+
|----------|------|-------|-------|
52+
| `Palo Alto Networks:GlobalProtect:PanSetup:Portal` | string | `vpn.example.com` | Set your GlobalProtect portal address. [More information](https://docs.paloaltonetworks.com/globalprotect/10-1/globalprotect-admin/globalprotect-apps/deploy-app-settings-transparently/customizable-app-settings/app-behavior-options). |
53+
| `Palo Alto Networks:GlobalProtect:PanSetup:Prelogon` | string | `1` | Enables pre-logon feature. [More information](https://docs.paloaltonetworks.com/globalprotect/10-1/globalprotect-admin/globalprotect-apps/deploy-app-settings-transparently/customizable-app-settings/app-behavior-options). |
54+
| `Palo Alto Networks:GlobalProtect:Settings:connect-method` | string | `pre-logon` | Connection method setting. [More information](https://docs.paloaltonetworks.com/globalprotect/10-1/globalprotect-admin/globalprotect-apps/deploy-app-settings-transparently/customizable-app-settings/app-behavior-options). |
55+
| `Palo Alto Networks:GlobalProtect:Settings:default-browser` | string | `no` | Prevents launching default browser. [More information](https://docs.paloaltonetworks.com/globalprotect/10-1/globalprotect-admin/globalprotect-apps/deploy-app-settings-transparently/customizable-app-settings/app-behavior-options). |
56+
57+
---
58+
59+
### Customization
60+
61+
To **modify or extend** the script:
62+
63+
- To **add a new key or update existing key**, use the `enforce_value` function.
64+
- To **delete a key**, use the `delete_key` or function.
65+
66+
---
67+
68+
### Script Settings
69+
70+
| Setting | Value |
71+
|--------|-------|
72+
| Run script as signed-in user | ❌ No |
73+
| Hide script notifications on devices | ✅ Yes |
74+
| Script frequency | Every 1 day |
75+
| Number of times to retry if script fails | 3 |
76+
77+
---
78+
79+
### Log File
80+
81+
The log file will output to ***/Library/Logs/Microsoft/IntuneScripts/PaloAltoGlobalProtectPolicyEnforcerMachineLevel/PaloAltoGlobalProtectPolicyEnforcerMachineLevel.log*** by default. Exit status is either 0 or 1. To gather this log with Intune remotely take a look at [Troubleshoot macOS shell script policies using log collection](https://docs.microsoft.com/en-us/mem/intune/apps/macos-shell-scripts#troubleshoot-macos-shell-script-policies-using-log-collection)
82+
83+
```
84+
##############################################################
85+
# Fri Jul 4 17:12:51 EEST 2025 | Starting running of script PaloAltoGlobalProtectPolicyEnforcerMachineLevel
86+
##############################################################
87+
88+
Fri Jul 4 17:12:51 EEST 2025 | Applying Palo Alto GlobalProtect policies...
89+
Fri Jul 4 17:12:51 EEST 2025 | Directory already exists: /Library/Preferences
90+
Fri Jul 4 17:12:51 EEST 2025 | [CREATE] Creating empty plist at /Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist
91+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Creating missing dictionary: Palo Alto Networks
92+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Creating missing dictionary: Palo Alto Networks:GlobalProtect
93+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Creating missing dictionary: Palo Alto Networks:GlobalProtect:PanSetup
94+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Palo Alto Networks:GlobalProtect:PanSetup:Portal = vpn.example.com
95+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Palo Alto Networks:GlobalProtect:PanSetup:Prelogon = 1
96+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Creating missing dictionary: Palo Alto Networks:GlobalProtect:Settings
97+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Palo Alto Networks:GlobalProtect:Settings:connect-method = pre-logon
98+
Fri Jul 4 17:12:51 EEST 2025 | [ADD] Palo Alto Networks:GlobalProtect:Settings:default-browser = no
99+
100+
Fri Jul 4 17:12:51 EEST 2025 | Script PaloAltoGlobalProtectPolicyEnforcerMachineLevel completed.
101+
102+
##############################################################
103+
# Fri Jul 4 18:12:40 EEST 2025 | Starting running of script PaloAltoGlobalProtectPolicyEnforcerMachineLevel
104+
##############################################################
105+
106+
Fri Jul 4 18:12:40 EEST 2025 | Applying Palo Alto GlobalProtect policies...
107+
Fri Jul 4 18:12:40 EEST 2025 | Directory already exists: /Library/Preferences
108+
Fri Jul 4 18:12:40 EEST 2025 | [OK] Palo Alto Networks:GlobalProtect:PanSetup:Portal is already set to vpn.example.com
109+
Fri Jul 4 18:12:40 EEST 2025 | [UPDATE] Palo Alto Networks:GlobalProtect:PanSetup:Prelogon: 1 -> 0
110+
Fri Jul 4 18:12:40 EEST 2025 | [OK] Palo Alto Networks:GlobalProtect:Settings:connect-method is already set to pre-logon
111+
Fri Jul 4 18:12:40 EEST 2025 | [OK] Palo Alto Networks:GlobalProtect:Settings:default-browser is already set to no
112+
113+
Fri Jul 4 18:12:40 EEST 2025 | Script PaloAltoGlobalProtectPolicyEnforcerMachineLevel completed.
114+
##############################################################
115+
```

0 commit comments

Comments
 (0)