Skip to main content
Apprentice
September 8, 2025
Question

Deploying MacOS jump clinet via Intune

  • September 8, 2025
  • 12 replies
  • 1880 views

So, I’ve attempted this multiple times and took a short break to clear my head. Cannot seem to get this wrapped up, and it’s a necessity.

 

Hi, I’m Robert and I’m a Security Engineer for my company. Part of my portfolio is Enterprise Software Management via Intune. I manage all software deployments for the company on a tenant level, using assignment groups to make certain apps available to pertinent groups. Over the past 3 years, I’ve learned a lot where Intune deployments and the Windows OS intersect. I’m still on the learning path, but I’m figuring out the nuances, the lowest common denominators and getting better at troubleshooting issues. This is where things get complicated: 100% of my experience in this arena is Windows 10 / Windows 11 based. And we now have a very small fleet (<10 devices) of Mac devices for our Marketing team.

 

Now, I’ve tried everything I can find online, but the documentation on how to pull this off via Intune is scarce and incomplete. Reddit has been the most...verbose? But still not able to get things working. I’ve done many, many things, but this is just the most recent and the most well documented:

  1. I installed Packages on a testbench MacBook Pro I was deployed.
  2. Went to the Jump Clients page in our BeyondTrust tenant and downloaded the Mac installer (dmg).
  3. Imported the DMG into a new Packages project. 
  4. Added the following post install script (per sources on Reddit)
    #!/bin/bash

    PROCESS=bomgar
    number=$(ps aux | grep -v grep | gre -ci $PROCESS)

    if [ $number -eq 0 ]
    then
    sciprtDir=$(dirName $0)
    hdiutil attach -nobrowse -mountpoint /Volumes/bomgar-scc $scriptDir/bomgar-scc-guid.dmg
    sudo /Volumes/bomgar-scc/Open\ To\ Start\ Support\ Session.app/Contents/MacOS/sdcust --silent
    sleep 15
    fi
  5. Save and build package.
  6. Upload to Intune, assign to groups, deploy.
  7. Prior to clicking deploy, setting up the Bomgar.mobileconfig file as outlined here. This is the only place I found that states this must be done, so if this is wrong, please advise how to reverse/remove it.

 

It appears to successfully deploy, according to Intune, but the devices never show up in our Jump Client list, and no icon ever populates on the end devices.

If you require more information, please advise. If you have some guidance or a tutorial or just a good point in the right general direction, I would be greatly appreciative. I’ve looked at the offical documentation, but it appears to only support JAMF, which I do not have. Everything else I’ve found pertaining to Intune is either wrong (I’m assuming, they didn’t work) or wildly out of date (click on this button...the button doesn’t exist, etc.). I’m struggling here, I’ve had mostly good experiences with BeyondTrust but this making me want to pull my non-existent hair out.

12 replies

Apprentice
January 8, 2026

Hello ​@rpollock_tg - we have this KB which outlines our Best Practises and guide on how to deploy the JC on to the MacOS OS: <removed>

Please let us know if this helps you!

How can I get access to this KB? When I try the link I just get a permissions error?

 

Also why is this thing so difficult for mac? It would seem some effort should be put into making a native signed pkg that can just be imported into our MDM of choice like pretty much all other software.

I am receiving the same error accessing the article.

Apprentice
February 6, 2026
#!/bin/zsh

# Beyondtrust JumpClient download and install script

# Logging output to a file for testing
#time=$( date "+%d%m%y-%H%M" )
#set -x
#logfile=/private/tmp/beyondtrust-"$time".log
#exec > $logfile 2>&1

# Require root (needed for /Applications & LaunchDaemons)
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This script must be run as root (use: sudo $0)"
exit 1
fi

# Intune/zsh hardening: minimal PATH and UTF-8 locale; disable globbing for JSON handling
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
export LANG="en_US.UTF-8"
export LC_ALL="en_US.UTF-8"
setopt NO_GLOB

# Set credential variables here
clientid="<CLIENTID>"
clientse='<CLIENTSECRET>'
creds=$( printf "$clientid:$clientse" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - )

####
# Alternatively if you dont want to store your clientid and client secret within the script you can create the base64
# encoded credential and simply store that within the script.

# creds="<base64 encoded credential>"
####

# Set Beyondtrust API creds here
url="https://<Your Site URL>"
token="oauth2/token"
base="api/config/v1"
jumpgroup="jump-group"
jumpclient="jump-client"
installer="jump-client/installer"

# Misc information we need to supply for this to work
jumpgroupname="<Enter Jump Group Name here>"
platform="mac-dmg"
dlfolder="/private/tmp"

# Obtain the user details.
# Here we have two options. If there is a local administrator account on all machines, we can specify that user
# for the installation
#currentuser="<Enter your username>"
#userid=$( /usr/bin/id -u $currentuser )

####
# Alternatively we can use the currently logged in user
currentuser=$( /usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk -F': ' '/[[:space:]]+Name[[:space:]]:/ { if ( $2 != "loginwindow" ) { print $2 }}' )
userid=$( /usr/bin/id -u $currentuser )
####

# Work out major os version
majver=$( /usr/bin/sw_vers -productVersion | /usr/bin/cut -d "." -f1 )

#####
## Download the latest BeyondTrust client via API
#####

# Request bearer access token using the API
request=$( /usr/bin/curl -s -X POST "${url}/${token}" \
-H "accept: application/json" \
-H "Authorization: Basic ${creds}" \
-d "grant_type=client_credentials" )

# Extract the bearer token from the json output above
if [ "$majver" -le 11 ];
then
access_token=$( /usr/bin/osascript -l 'JavaScript' -e "JSON.parse(\`$request\`).access_token" )
else
access_token=$( /usr/bin/plutil -extract access_token raw -o - - <<< "$request" )
fi

# Get a list of the jump groups
groups=$( /usr/bin/curl -s -X GET "${url}/${base}/${jumpgroup}" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${access_token}" )

# Find group ID by exact name via JXA (reliable under zsh/Intune)
groupid=$(/usr/bin/osascript -l JavaScript -e '
(function() {
var groups = JSON.parse(String.raw`'"$groups"'`);
var want = "'"$jumpgroupname"'";
for (var i=0; i<groups.length; i++) {
if (groups[i].name === want) { $.NSFileHandle.fileHandleWithStandardOutput.writeData($(groups[i].id + "\n").dataUsingEncoding(4)); return; }
}
})();')

# Safety: one numeric ID only
groupid=$(echo "$groupid" | tr -d '[:space:]')
if ! echo "$groupid" | grep -Eq '^[0-9]+$'; then
echo "ERROR: Could not resolve jump group id for name: $jumpgroupname"
echo "Groups response was: $groups"
exit 2
fi

# We're ready to request the download. First form the data to pass to the API
# Feed it the groupid from before.
# This is configurable based upon requirements, for more information review the
# BeyondTrust API Documentation.

jumpclientconfig='
{
"name":"",
"jump_group_id":'$groupid',
"jump_group_type":"shared",
"tag":"",
"connection_type":"active",
"valid_duration":30,
"elevate_install":true,
"elevate_prompt":true,
"allow_override_jump_group":false,
"allow_override_jump_policy":false,
"allow_override_name":false,
"allow_override_comments":false
}'

# Use the prepared json above to get the installer unique id
uid=$( /usr/bin/curl -s -X POST "${url}/${base}/${installer}" \
-d "${jumpclientconfig}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${access_token}" )

# Extract the installer ID from the output
if [ "$majver" -le 11 ];
then
installer_id=$( /usr/bin/osascript -l 'JavaScript' -e "JSON.parse(\`$uid\`).installer_id" )
# key_info structure changed in the API. Try the new `key_info.encodedInfo` first,
# then fall back to the previous platform-specific path if present.
key_info=$( /usr/bin/osascript -l 'JavaScript' -e "(function(){var j=JSON.parse(\`$uid\`); if (j.key_info && j.key_info.encodedInfo) return j.key_info.encodedInfo; if (j.key_info && j.key_info['mac-osx-x86'] && j.key_info['mac-osx-x86'].encodedInfo) return j.key_info['mac-osx-x86'].encodedInfo; if (j.key_info) return j.key_info; return ''; })()" )
else
installer_id=$( /usr/bin/plutil -extract installer_id raw -o - - <<< "$uid" )
# key_info structure changed in the API. Try multiple plutil extract paths.
# 1) key_info.encodedInfo
# 2) key_info.mac-osx-x86.encodedInfo
# 3) fallback: extract the whole key_info object as a raw string

key_info=$( /usr/bin/plutil -extract key_info.encodedInfo raw -o - - <<< "$uid" 2>/dev/null )
if [ $? -ne 0 ]; then
key_info=$( /usr/bin/plutil -extract key_info.mac-osx-x86.encodedInfo raw -o - - <<< "$uid" 2>/dev/null )
fi
if [ $? -ne 0 ]; then
key_info=$( /usr/bin/plutil -extract key_info raw -o - - <<< "$uid" 2>/dev/null )
fi
fi

# Download latest installer to private tmp folder. Retry if required.
for loop in {1..10};
do
echo "Download attempt: [$loop / 10]"
test=$( /usr/bin/curl -s \
-X GET "${url}/${base}/${installer}/${installer_id}/${platform}" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${access_token}" \
-w "%{http_code}" \
-o ${dlfolder}/bomgar-scc-${key_info}.dmg )
[ "$test" = "200" ] && break
done

# Did the download actually work. Error if not.
[ "$test" != "200" ] && { echo "Download failed. Exiting."; exit 1; }

#####
## Check and uninstall any previous installations.
#####

# Find the existing BeyondTrust install in /Users then run the uninstall command
/usr/bin/find /Users/Shared /Applications -iname "sdcust" -type f -maxdepth 5 -exec {} -uninstall silent \;
sleep 3

# This is the manual cleanup process. Uninstall should remove everything
# however this will also catch any previous failed installations.

# Are there any LaunchAgents from a previous install?
test=$( /usr/bin/find /Library/LaunchAgents -iname "com.bomgar.bomgar*.plist" | /usr/bin/wc -l | /usr/bin/awk '{ print $1 }' )

# More than zero means we have work to do
if [ "$test" -gt 0 ]; then
# Unload user LaunchAgents only if a user is logged in
if [ -n "$currentuser" ]; then
laarray=$(/usr/bin/su - "$currentuser" -c "/bin/launchctl list" | grep com.bomgar | awk '{ print $3 }')
for la in $laarray; do
/bin/launchctl bootout user/"$la"
done
else
echo "No console user; skipping user LaunchAgent unload."
fi

# Unload system LaunchDaemons
ldarray=$(/bin/launchctl list | grep com.bomgar | awk '{ print $3 }')
for ld in $ldarray; do
/bin/launchctl bootout system/"$ld"
done

# Remove all the launchd agents and daemons
/usr/bin/find /Library/LaunchAgents -iname "*com.bomgar*.plist" -exec rm -rf {} \;
/usr/bin/find /Library/LaunchDaemons -iname "*com.bomgar*.plist" -exec rm -rf {} \;
/usr/bin/find /Library/LaunchDaemons -iname "*com.bomgar*.helper" -exec rm -rf {} \;

# Remove any existing install folders
/bin/rm -rf /Users/Shared/bomgar-scc*
/bin/rm -rf /Users/Shared/.com.bomgar.scc.*
/bin/rm -rf /Applications/.com.bomgar*
fi

# Check the API to see if there's an existing record for the current hostname
# Remove if exists

# Generate the query date we require. As long as our hostnames are correct,
# then we can find the mac we're running on.
# Check for existing record for this hostname and delete it (GET with query string, not body)
host=$(hostname)
devices_json=$(/usr/bin/curl -s -G "${url}/${base}/${jumpclient}" \
--data-urlencode "name=${host}" \
-H "Accept: application/json" \
-H "Authorization: Bearer ${access_token}")

# Extract first matching device id (if any)
if [ "$majver" -le 11 ]; then
deviceid=$(/usr/bin/osascript -l JavaScript -e '
(function() {
var a = JSON.parse(String.raw`'"$devices_json"'`);
if (Array.isArray(a) && a.length > 0 && a[0].id) { $.NSFileHandle.fileHandleWithStandardOutput.writeData($(a[0].id + "\n").dataUsingEncoding(4)); }
})();')
else
# plutil path for array index 0 id (if present)
deviceid=$(echo "$devices_json" | /usr/bin/plutil -extract 0.id raw -o - - 2>/dev/null)
fi

# If we found a device id, delete it
if [ -n "$deviceid" ]; then
/usr/bin/curl -s -X DELETE "${url}/${base}/${jumpclient}/${deviceid}" \
-H "accept: application/json" \
-H "Authorization: Bearer ${access_token}" >/dev/null
sleep 5
fi

#####
## We're ready to install the application.
#####

# Create a temporary folder to mount the dmg to.
tmpmnt=$(/usr/bin/mktemp -d /private/tmp/tempinstall.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create temporary folder. Exiting."
exit 1
fi

# Mount and capture the device node (e.g., /dev/disk4s3)
attach_out=$(/usr/bin/hdiutil attach "${dlfolder}/bomgar-scc-${key_info}.dmg" \
-mountpoint "$tmpmnt" -nobrowse -noverify -noautoopen)
devnode=$(echo "$attach_out" | awk '/Apple_HFS|HFSX/ {print $1; exit}')

# Find and run the installer
sdc=$(/usr/bin/find "$tmpmnt" -iname "sdcust" -type f)
"$sdc" --silent
sleep 20

# Detach the volume reliably, then clean up
if [ -n "$devnode" ]; then
/usr/bin/hdiutil detach "$devnode" -force || /usr/bin/hdiutil detach "$tmpmnt" -force
else
/usr/bin/hdiutil detach "$tmpmnt" -force
fi

/bin/rm -rf "$tmpmnt"
/bin/rm -rf "${dlfolder}/bomgar-scc-${key_info}.dmg"

# All done
exit 0

So I contacted support and they sent me the script that was in the Knowledge article that, as of today, is not released.

Alot of trial and error later, plus some Copilot, I got it working. Do note that I am not a pro scripter or anything like that, so it can probably be improved upon both in terms of efficiency and security. Nevertheless, this works for us currently.

ps: Do remember to configure the Mass Deployment policies on Intune, according to Beyondtrusts Documentation.