Deploying BusyCal via MDM or Scripted Installation
BusyCal and BusyContacts do not currently support direct MDM-based licensing for App Store subscriptions, due to limitations imposed by Apple. The Mac App Store is designed around individual iCloud-based subscriptions, which unfortunately do not support business-wide deployments under a single MDM license.
For organizations and IT admins who wish to manage multiple installations of BusyCal / BusyContacts across devices, we recommend using our direct license version—available from our website—which allows volume purchases (e.g., a 5-seat license) and supports custom deployment workflows.
Benefits of our Direct Version vs. App Store
For more details, please visit the licensing page as we have given a detailed comparison there.
Essentially, our direct version allows you to:
- Purchase multi-seat licenses with 18 months of updates included.
- Deploy BusyCal manually or via scripts.
- Register and activate using a license key
- Optional Upgrades
Managed Installation on a Single Machine
You can manually install and activate BusyCal on any Mac using the following steps:
1. Download the latest DMG
2. Mount the DMG
Open Terminal and run:
hdiutil attach /path/to/BusyCal.dmg
This command will mount the DMG file as a volume on your system. Take note of the mount point displayed in the command output (e.g., /Volumes/BusyCal
).
3. Copy BusyCal to Applications
cp -R /Volumes/BusyCal/BusyCal.app /Applications/
4. Register BusyCal with a License Key
You can register BusyCal by opening a special URL with your license key:
open "busycal://register/BCL3-1111-1111-1111-1111"
Replace BCL3-1111-1111-1111-1111
with your actual license key. This will silently register the installed copy in the background.
Sample Deployment Script for Automation
For automating this across multiple machines, here’s a sample Bash script:
This script can be adapted for deployment tools like Jamf, Munki, or custom shell workflows across managed Macs.
#!/bin/bash
# --- Configuration ---
BASE_URL="https://www.busymac.com/download" # Base URL for downloads
DMG_NAME="BusyCal.dmg" # Base name for the downloaded file and in URL
DMG_URL="$BASE_URL/$DMG_NAME" # Construct the full download URL
DMG_PATH="/tmp/$DMG_NAME" # Full path for the downloaded file
APP_NAME="BusyCal.app" # Name of the application bundle inside the DMG
LICENSE_KEY="BCL3-1111-1111-1111-1111" # Replace with actual license key
# --- End Configuration ---
# Variable to store the determined mount point
MOUNT_POINT=""
# Function for cleanup actions
cleanup() {
echo "--- Cleaning up ---"
# Attempt to detach using the determined mount point, if available and mounted
if [ -n "$MOUNT_POINT" ] && hdiutil info | grep -q -F "$MOUNT_POINT"; then
echo "Unmounting volume at $MOUNT_POINT..."
hdiutil detach "$MOUNT_POINT" -force > /dev/null 2>&1
fi
# Remove the downloaded DMG file
if [ -f "$DMG_PATH" ]; then
echo "Removing downloaded DMG at $DMG_PATH..."
rm "$DMG_PATH"
fi
echo "Cleanup finished."
}
trap cleanup EXIT
# --- Main Script ---
echo "Starting BusyCal installation script..."
# Check for xmllint availability
if ! command -v xmllint &> /dev/null; then
echo "Error: xmllint command not found. Install via: brew install libxml2" >&2
exit 1
fi
# Download BusyCal DMG
echo "Downloading $DMG_URL to $DMG_PATH..."
if ! curl --fail -L -o "$DMG_PATH" "$DMG_URL"; then
echo "Error: Failed to download DMG from $DMG_URL." >&2
exit 1
fi
echo "Download complete."
# Mount the DMG and capture the output plist
echo "Mounting DMG: $DMG_PATH..."
MOUNT_INFO_PLIST=$(hdiutil attach "$DMG_PATH" -nobrowse -noverify -plist)
ATTACH_STATUS=$? # Capture exit status of hdiutil attach
if [ $ATTACH_STATUS -ne 0 ]; then
echo "Error: Failed to mount DMG. hdiutil exited with status $ATTACH_STATUS." >&2
exit 1
fi
# Parse the plist output using plutil and xmllint to find the mount point
echo "Parsing mount point information..."
# Convert plist to XML, pipe to xmllint, use XPath to extract the string value
# following the 'mount-point' key. Suppress stderr from plutil.
MOUNT_POINT=$(echo "$MOUNT_INFO_PLIST" | plutil -convert xml1 -o - - 2>/dev/null | \
xmllint --xpath 'string(//key[.="mount-point"]/following-sibling::string[1])' - 2>/dev/null)
PARSE_STATUS=$? # Capture exit status of the command pipeline
if [ $PARSE_STATUS -ne 0 ]; then
echo "Error: Failed to parse mount point using xmllint (exit status $PARSE_STATUS)." >&2
# Attempt to detach using the DMG path as a fallback
hdiutil detach "$DMG_PATH" -force > /dev/null 2>&1
exit 1
fi
# Validate that we found a mount point
if [ -z "$MOUNT_POINT" ]; then
echo "Error: Could not determine mount point from hdiutil output (xmllint parsing failed to find it)." >&2
# Attempt to detach using the DMG path as a fallback
hdiutil detach "$DMG_PATH" -force > /dev/null 2>&1
exit 1
fi
echo "DMG mounted successfully at: $MOUNT_POINT"
# Define the source path for the application
SOURCE_APP_PATH="$MOUNT_POINT/$APP_NAME"
# Check if the application exists at the expected path within the mounted volume
if [ ! -d "$SOURCE_APP_PATH" ]; then
echo "Error: Application '$APP_NAME' not found at '$SOURCE_APP_PATH'." >&2
exit 1
fi
echo "Located application at: $SOURCE_APP_PATH"
# Copy the app to /Applications
echo "Copying $APP_NAME to /Applications/ ..."
if ! cp -R "$SOURCE_APP_PATH" /Applications/; then
echo "Error: Failed to copy '$APP_NAME' to /Applications/." >&2
exit 1
fi
echo "Application copied successfully."
# Register the app using the URL scheme
echo "Attempting to register the application..."
# Add a small delay before trying to register, sometimes needed for the system
# to recognize the newly copied app and its URL scheme handler.
sleep 2
if ! open -g "busycal://register/$LICENSE_KEY"; then
echo "Registration failed."
exit 1
fi
echo "Registration command sent."
# Unmounting and cleanup will be handled by the EXIT trap
echo "BusyCal installation script completed successfully."
# Explicitly exit successfully, triggering the cleanup trap
exit 0
mdm deployment, busycal deployment, deploy busycal, install busycal via script, busycal installer script, deploy via bash, mass install busycal, bulk install busycal, busycal dmgs, deploy busycal without app store, offline busycal install, register busycal app, busycal license registration, automate busycal install, script busycal install, terminal install busycal, busycal mdm workaround, busycal business license, busycal enterprise deployment, deploy busycal with license key, busycal shell script, busycal install mac terminal, install busycal on multiple machines, unattended busycal setup, busycal registration script, jamf busycal install, munki busycal, busycal curl download, busycal mount dmg, busycal bash automation, busycal it admin tools