Sep 14 2022 01:56 AM
Sep 16 2022 07:12 AM
@Simon42 You are not alone, this is a long standing issue with PA Global Protect due to the way it handles the installation in the package. This was happening with wrapped packages as well.
There is a way to get it to install with a .sh script. At the bottom of my post is a sample script that will require some editing and testing.
What the script does:
It creates a plist file and then populates vpn portal info from the information provided in the script, and then downloads or gets the package from a location (hopefully you have access to define a URL where you can store the base package), and installs it.
You will need to whitelist system extensions in a device profile by whitelisting the teamID , but aside from that it should work with some tweaking of the script, provided you can get the package to retrieve from a specific location you have chosen for it to reside:
#!/bin/sh
plistBuddy='/usr/libexec/PlistBuddy'
GPplistFile='/Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist'
if [ -f ${GPplistFile} ]
then
echo "Plist already exists..."
else
echo "Creating Plist"
${plistBuddy} -c "print : 'Palo Alto Networks':'GlobalProtect':'PanSetup':'Portal'" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup':'Portal' string 'vpn.company.com'" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup':'Prelogon' integer 0" ${GPplistFile}
fi
if [ -d "/Applications/GlobalProtect.app" ]
then
echo "Already installed..."
exit 0
else
echo "Preparing..."
curl "http://files.company.com/GlobalProtect.pkg" > "/tmp/GlobalProtect.pkg"
echo "Installing..."
sudo installer -pkg "/tmp/GlobalProtect.pkg" -target /
echo "Cleaning..."
rm "/tmp/GlobalProtect.pkg"
exit 0
fi
Sep 19 2022 12:12 AM
Hello @Michelle_ash
thanks for the reply.
Then I will try to open a ticket for this at palo alto.
I know the script and it works with it. But it would be nicer if the user could load the app via the company portal when needed.
If I hear anything from Palo Alto, I will report here.
Oct 05 2022 12:53 PM
@Simon42 I haven't see anyone post but here is the shell script I used and it worked light out. We used azure blob with public www
also used plist option to set the url
#!/bin/bash
#set -x
############################################################################################
##
## Script to install the latest GlobalProtect Blob Servers
##
############################################################################################
# Define variables
weburl="https://xxxx.z13.web.core.windows.net/GlobalProtect.pkg" # What is the Azure Blob Storage URL?
appname="GlobalProtect" # The name of our App deployment script
app="GlobalProtect.app" # The actual name of our App once installed
logandmetadir="/Library/Logs/Microsoft/IntuneScripts/GlobalProtect" # The location of our logs and last updated data
processpath="/Applications/GlobalProtect.app/Contents/MacOS/GlobalProtect" # The process name of the App we are installing
terminateprocess="false" # Do we want to terminate the running process? If false we'll wait until its not running
autoUpdate="false"
# Generated variables
tempdir=$(mktemp -d)
log="$logandmetadir/$appname.log" # The location of the script log file
metafile="$logandmetadir/$appname.meta" # The location of our meta file (for updates)
plistBuddy='/usr/libexec/PlistBuddy'
GPplistFile='/Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist'
if [ -f ${GPplistFile} ]
then
echo "Plist already exists..."
else
echo "Creating Plist"
${plistBuddy} -c "print : 'Palo Alto Networks':'GlobalProtect':'PanSetup':'Portal'" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup' dict" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup':'Portal' string 'vpn.something.com'" ${GPplistFile}
${plistBuddy} -c "add :'Palo Alto Networks':'GlobalProtect':'PanSetup':'Prelogon' integer 0" ${GPplistFile}
fi
# function to delay script if the specified process is running
waitForProcess () {
#################################################################################################################
#################################################################################################################
##
## Function to pause while a specified process is running
##
## Functions used
##
## None
##
## Variables used
##
## $1 = name of process to check for
## $2 = length of delay (if missing, function to generate random delay between 10 and 60s)
## $3 = true/false if = "true" terminate process, if "false" wait for it to close
##
###############################################################
###############################################################
processName=$1
fixedDelay=$2
terminate=$3
echo "$(date) | Waiting for other [$processName] processes to end"
while ps aux | grep "$processName" | grep -v grep &>/dev/null; do
if [[ $terminate == "true" ]]; then
echo "$(date) | + [$appname] running, terminating [$processpath]..."
pkill -f "$processName"
return
fi
# If we've been passed a delay we should use it, otherwise we'll create a random delay each run
if [[ ! $fixedDelay ]]; then
delay=$(( $RANDOM % 50 + 10 ))
else
delay=$fixedDelay
fi
echo "$(date) | + Another instance of $processName is running, waiting [$delay] seconds"
sleep $delay
done
echo "$(date) | No instances of [$processName] found, safe to proceed"
}
# function to check if we need Rosetta 2
checkForRosetta2 () {
#################################################################################################################
#################################################################################################################
##
## Simple function to install Rosetta 2 if needed.
##
## Functions
##
## waitForProcess (used to pause script if another instance of softwareupdate is running)
##
## Variables
##
## None
##
###############################################################
###############################################################
echo "$(date) | Checking if we need Rosetta 2 or not"
# if Software update is already running, we need to wait...
waitForProcess "/usr/sbin/softwareupdate"
## Note, Rosetta detection code from https://derflounder.wordpress.com/2020/11/17/installing-rosetta-2-on-apple-silicon-macs/
OLDIFS=$IFS
IFS='.' read osvers_major osvers_minor osvers_dot_version <<< "$(/usr/bin/sw_vers -productVersion)"
IFS=$OLDIFS
if [[ ${osvers_major} -ge 11 ]]; then
# Check to see if the Mac needs Rosetta installed by testing the processor
processor=$(/usr/sbin/sysctl -n machdep.cpu.brand_string | grep -o "Intel")
if [[ -n "$processor" ]]; then
echo "$(date) | $processor processor installed. No need to install Rosetta."
else
# Check for Rosetta "oahd" process. If not found,
# perform a non-interactive install of Rosetta.
if /usr/bin/pgrep oahd >/dev/null 2>&1; then
echo "$(date) | Rosetta is already installed and running. Nothing to do."
else
/usr/sbin/softwareupdate --install-rosetta --agree-to-license
if [[ $? -eq 0 ]]; then
echo "$(date) | Rosetta has been successfully installed."
else
echo "$(date) | Rosetta installation failed!"
exitcode=1
fi
fi
fi
else
echo "$(date) | Mac is running macOS $osvers_major.$osvers_minor.$osvers_dot_version."
echo "$(date) | No need to install Rosetta on this version of macOS."
fi
}
# Function to update the last modified date for this app
fetchLastModifiedDate() {
#################################################################################################################
#################################################################################################################
##
## This function takes the following global variables and downloads the URL provided to a temporary location
##
## Functions
##
## none
##
## Variables
##
## $logandmetadir = Directory to read nand write meta data to
## $metafile = Location of meta file (used to store last update time)
## $weburl = URL of download location
## $tempfile = location of temporary DMG file downloaded
## $lastmodified = Generated by the function as the last-modified http header from the curl request
##
## Notes
##
## If called with "fetchLastModifiedDate update" the function will overwrite the current lastmodified date into metafile
##
###############################################################
###############################################################
## Check if the log directory has been created
if [[ ! -d "$logandmetadir" ]]; then
## Creating Metadirectory
echo "$(date) | Creating [$logandmetadir] to store metadata"
mkdir -p "$logandmetadir"
fi
# generate the last modified date of the file we need to download
lastmodified=$(curl -sIL "$weburl" | grep -i "last-modified" | awk '{$1=""; print $0}' | awk '{ sub(/^[ \t]+/, ""); print }' | tr -d '\r')
if [[ $1 == "update" ]]; then
echo "$(date) | Writing last modifieddate [$lastmodified] to [$metafile]"
echo "$lastmodified" > "$metafile"
fi
}
function downloadApp () {
#################################################################################################################
#################################################################################################################
##
## This function takes the following global variables and downloads the URL provided to a temporary location
##
## Functions
##
## waitForCurl (Pauses download until all other instances of Curl have finished)
## downloadSize (Generates human readable size of the download for the logs)
##
## Variables
##
## $appname = Description of the App we are installing
## $weburl = URL of download location
## $tempfile = location of temporary DMG file downloaded
##
###############################################################
###############################################################
echo "$(date) | Starting downlading of [$appname]"
# wait for other downloads to complete
waitForProcess "curl -f"
#download the file
updateOctory installing
echo "$(date) | Downloading $appname"
cd "$tempdir"
curl -f -s --connect-timeout 30 --retry 5 --retry-delay 60 -L -J -O "$weburl"
if [ $? == 0 ]; then
# We have downloaded a file, we need to know what the file is called and what type of file it is
tempSearchPath="$tempdir/*"
for f in $tempSearchPath; do
tempfile=$f
done
case $tempfile in
*.pkg|*.PKG)
packageType="PKG"
;;
*.zip|*.ZIP)
packageType="ZIP"
;;
*.dmg|*.DMG)
packageType="DMG"
;;
*)
# We can't tell what this is by the file name, lets look at the metadata
echo "$(date) | Unknown file type [$f], analysing metadata"
metadata=$(file "$tempfile")
if [[ "$metadata" == *"Zip archive data"* ]]; then
packageType="ZIP"
mv "$tempfile" "$tempdir/install.zip"
tempfile="$tempdir/install.zip"
fi
if [[ "$metadata" == *"xar archive"* ]]; then
packageType="PKG"
mv "$tempfile" "$tempdir/install.pkg"
tempfile="$tempdir/install.pkg"
fi
if [[ "$metadata" == *"bzip2 compressed data"* ]] || [[ "$metadata" == *"zlib compressed data"* ]] ; then
packageType="DMG"
mv "$tempfile" "$tempdir/install.dmg"
tempfile="$tempdir/install.dmg"
fi
;;
esac
if [[ ! $packageType ]]; then
echo "Failed to determine temp file type [$metadata]"
rm -rf "$tempdir"
else
echo "$(date) | Downloaded [$app] to [$tempfile]"
echo "$(date) | Detected install type as [$packageType]"
fi
else
echo "$(date) | Failure to download [$weburl] to [$tempfile]"
updateOctory failed
exit 1
fi
}
# Function to check if we need to update or not
function updateCheck() {
#################################################################################################################
#################################################################################################################
##
## This function takes the following dependencies and variables and exits if no update is required
##
## Functions
##
## fetchLastModifiedDate
##
## Variables
##
## $appname = Description of the App we are installing
## $tempfile = location of temporary DMG file downloaded
## $volume = name of volume mount point
## $app = name of Application directory under /Applications
##
###############################################################
###############################################################
echo "$(date) | Checking if we need to install or update [$appname]"
## Is the app already installed?
if [ -d "/Applications/$app" ]; then
# App is installed, if it's updates are handled by MAU we should quietly exit
if [[ $autoUpdate == "true" ]]; then
echo "$(date) | [$appname] is already installed and handles updates itself, exiting"
exit 0;
fi
# App is already installed, we need to determine if it requires updating or not
echo "$(date) | [$appname] already installed, let's see if we need to update"
fetchLastModifiedDate
## Did we store the last modified date last time we installed/updated?
if [[ -d "$logandmetadir" ]]; then
if [ -f "$metafile" ]; then
previouslastmodifieddate=$(cat "$metafile")
if [[ "$previouslastmodifieddate" != "$lastmodified" ]]; then
echo "$(date) | Update found, previous [$previouslastmodifieddate] and current [$lastmodified]"
update="update"
else
echo "$(date) | No update between previous [$previouslastmodifieddate] and current [$lastmodified]"
echo "$(date) | Exiting, nothing to do"
exit 0
fi
else
echo "$(date) | Meta file [$metafile] not found"
echo "$(date) | Unable to determine if update required, updating [$appname] anyway"
fi
fi
else
echo "$(date) | [$appname] not installed, need to download and install"
fi
}
## Install PKG Function
function installPKG () {
#################################################################################################################
#################################################################################################################
##
## This function takes the following global variables and installs the PKG file
##
## Functions
##
## isAppRunning (Pauses installation if the process defined in global variable $processpath is running )
## fetchLastModifiedDate (Called with update flag which causes the function to write the new lastmodified date to the metadata file)
##
## Variables
##
## $appname = Description of the App we are installing
## $tempfile = location of temporary DMG file downloaded
## $volume = name of volume mount point
## $app = name of Application directory under /Applications
##
###############################################################
###############################################################
# Check if app is running, if it is we need to wait.
waitForProcess "$processpath" "300" "$terminateprocess"
echo "$(date) | Installing $appname"
# Update Octory monitor
updateOctory installing
# Remove existing files if present
if [[ -d "/Applications/$app" ]]; then
rm -rf "/Applications/$app"
fi
installer -pkg "$tempfile" -target /Applications
# Checking if the app was installed successfully
if [ "$?" = "0" ]; then
echo "$(date) | $appname Installed"
echo "$(date) | Cleaning Up"
rm -rf "$tempdir"
echo "$(date) | Application [$appname] succesfully installed"
fetchLastModifiedDate update
updateOctory installed
exit 0
else
echo "$(date) | Failed to install $appname"
rm -rf "$tempdir"
updateOctory failed
exit 1
fi
}
## Install DMG Function
function installDMG () {
#################################################################################################################
#################################################################################################################
##
## This function takes the following global variables and installs the DMG file into /Applications
##
## Functions
##
## isAppRunning (Pauses installation if the process defined in global variable $processpath is running )
## fetchLastModifiedDate (Called with update flag which causes the function to write the new lastmodified date to the metadata file)
##
## Variables
##
## $appname = Description of the App we are installing
## $tempfile = location of temporary DMG file downloaded
## $volume = name of volume mount point
## $app = name of Application directory under /Applications
##
###############################################################
###############################################################
# Check if app is running, if it is we need to wait.
waitForProcess "$processpath" "300" "$terminateprocess"
echo "$(date) | Installing [$appname]"
updateOctory installing
# Mount the dmg file...
volume="$tempdir/$appname"
echo "$(date) | Mounting Image"
hdiutil attach -quiet -nobrowse -mountpoint "$volume" "$tempfile"
# Remove existing files if present
if [[ -d "/Applications/$app" ]]; then
echo "$(date) | Removing existing files"
rm -rf "/Applications/$app"
fi
# Sync the application and unmount once complete
echo "$(date) | Copying app files to /Applications/$app"
rsync -a "$volume"/*.app/ "/Applications/$app"
# Unmount the dmg
echo "$(date) | Un-mounting [$volume]"
hdiutil detach -quiet "$volume"
# Checking if the app was installed successfully
if [[ -a "/Applications/$app" ]]; then
echo "$(date) | [$appname] Installed"
echo "$(date) | Cleaning Up"
rm -rf "$tempfile"
echo "$(date) | Fixing up permissions"
sudo chown -R root:wheel "/Applications/$app"
echo "$(date) | Application [$appname] succesfully installed"
fetchLastModifiedDate update
updateOctory installed
exit 0
else
echo "$(date) | Failed to install [$appname]"
rm -rf "$tempdir"
updateOctory failed
exit 1
fi
}
## Install ZIP Function
function installZIP () {
#################################################################################################################
#################################################################################################################
##
## This function takes the following global variables and installs the DMG file into /Applications
##
## Functions
##
## isAppRunning (Pauses installation if the process defined in global variable $processpath is running )
## fetchLastModifiedDate (Called with update flag which causes the function to write the new lastmodified date to the metadata file)
##
## Variables
##
## $appname = Description of the App we are installing
## $tempfile = location of temporary DMG file downloaded
## $volume = name of volume mount point
## $app = name of Application directory under /Applications
##
###############################################################
###############################################################
# Check if app is running, if it is we need to wait.
waitForProcess "$processpath" "300" "$terminateprocess"
echo "$(date) | Installing $appname"
updateOctory installing
# Change into temp dir
cd "$tempdir"
if [ "$?" = "0" ]; then
echo "$(date) | Changed current directory to $tempdir"
else
echo "$(date) | failed to change to $tempfile"
if [ -d "$tempdir" ]; then rm -rf $tempdir; fi
updateOctory failed
exit 1
fi
# Unzip files in temp dir
unzip -qq -o "$tempfile"
if [ "$?" = "0" ]; then
echo "$(date) | $tempfile unzipped"
else
echo "$(date) | failed to unzip $tempfile"
if [ -d "$tempdir" ]; then rm -rf $tempdir; fi
updateOctory failed
exit 1
fi
# If app is already installed, remove all old files
if [[ -a "/Applications/$app" ]]; then
echo "$(date) | Removing old installation at /Applications/$app"
rm -rf "/Applications/$app"
fi
# Copy over new files
rsync -a "$app/" "/Applications/$app"
if [ "$?" = "0" ]; then
echo "$(date) | $appname moved into /Applications"
else
echo "$(date) | failed to move $appname to /Applications"
if [ -d "$tempdir" ]; then rm -rf $tempdir; fi
updateOctory failed
exit 1
fi
# Make sure permissions are correct
echo "$(date) | Fix up permissions"
sudo chown -R root:wheel "/Applications/$app"
if [ "$?" = "0" ]; then
echo "$(date) | correctly applied permissions to $appname"
else
echo "$(date) | failed to apply permissions to $appname"
if [ -d "$tempdir" ]; then rm -rf $tempdir; fi
updateOctory failed
exit 1
fi
# Checking if the app was installed successfully
if [ "$?" = "0" ]; then
if [[ -a "/Applications/$app" ]]; then
echo "$(date) | $appname Installed"
updateOctory installed
echo "$(date) | Cleaning Up"
rm -rf "$tempfile"
# Update metadata
fetchLastModifiedDate update
echo "$(date) | Fixing up permissions"
sudo chown -R root:wheel "/Applications/$app"
echo "$(date) | Application [$appname] succesfully installed"
exit 0
else
echo "$(date) | Failed to install $appname"
exit 1
fi
else
# Something went wrong here, either the download failed or the install Failed
# intune will pick up the exit status and the IT Pro can use that to determine what went wrong.
# Intune can also return the log file if requested by the admin
echo "$(date) | Failed to install $appname"
if [ -d "$tempdir" ]; then rm -rf $tempdir; fi
exit 1
fi
}
function updateOctory () {
#################################################################################################################
#################################################################################################################
##
## This function is designed to update Octory status (if required)
##
##
## Parameters (updateOctory parameter)
##
## notInstalled
## installing
## installed
##
###############################################################
###############################################################
# Is Octory present
if [[ -a "/Library/Application Support/Octory" ]]; then
# Octory is installed, but is it running?
if [[ $(ps aux | grep -i "Octory" | grep -v grep) ]]; then
echo "$(date) | Updating Octory monitor for [$appname] to [$1]"
/usr/local/bin/octo-notifier monitor "$appname" --state $1 >/dev/null
fi
fi
}
function startLog() {
###################################################
###################################################
##
## start logging - Output to log file and STDOUT
##
####################
####################
if [[ ! -d "$logandmetadir" ]]; then
## Creating Metadirectory
echo "$(date) | Creating [$logandmetadir] to store logs"
mkdir -p "$logandmetadir"
fi
exec &> >(tee -a "$log")
}
# function to delay until the user has finished setup assistant.
waitForDesktop () {
until ps aux | grep /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock | grep -v grep &>/dev/null; do
delay=$(( $RANDOM % 50 + 10 ))
echo "$(date) | + Dock not running, waiting [$delay] seconds"
sleep $delay
done
echo "$(date) | Dock is here, lets carry on"
}
###################################################################################
###################################################################################
##
## Begin Script Body
##
#####################################
#####################################
# Initiate logging
startLog
echo ""
echo "##############################################################"
echo "# $(date) | Logging install of [$appname] to [$log]"
echo "############################################################"
echo ""
# Install Rosetta if we need it
checkForRosetta2
# Test if we need to install or update
updateCheck
# Wait for Desktop
waitForDesktop
# Download app
downloadApp
# Install PKG file
if [[ $packageType == "PKG" ]]; then
installPKG
fi
# Install PKG file
if [[ $packageType == "ZIP" ]]; then
installZIP
fi
# Install PKG file
if [[ $packageType == "DMG" ]]; then
installDMG
fi