Skip to main content
This page applies to bare metal Mac host deployments only. It does not apply to MacStadium VDI or virtual machines, which cannot be registered with Apple Business Manager.
This guide describes a tested, repeatable procedure for deprovisioning bare metal Mac hosts via Jamf Pro and automatically restoring them to a remotely accessible state. After an administrator issues the wipe command, the machine re-enrolls, creates a temporary user account, enables SSH, and enables Screen Sharing. A user can connect via VNC with temporary credentials immediately, with no further action from the administrator. This workflow depends on Automated Device Enrollment (ADE) via Apple Business Manager (ABM), which requires physical hardware registered to your ABM account. One-time setup takes approximately 30 minutes. Subsequent wipe-to-accessible cycles take 5 to 10 minutes depending on network conditions.

How it works

When a wipe is issued, the following sequence runs automatically:
  1. The Mac reboots, connects to the network over wired Ethernet, and contacts Apple’s activation servers.
  2. ADE applies the PreStage profile, skipping all Setup Assistant screens and creating a managed admin account.
  3. The Mac enrolls in Jamf Pro. An enrollment-triggered policy fires immediately.
  4. The policy script creates a standard local temporary user account and forces a password change on first login.
  5. The script enables SSH directly on the machine.
  6. The script calls the Jamf API to send the EnableRemoteDesktop MDM command to the device.
  7. Jamf pushes the MDM command. Screen Sharing is enabled. A user can connect via VNC with the temporary credentials.

Prerequisites

  • The Mac is physically connected via wired Ethernet with DHCP enabled on the switch port.
  • The Mac is assigned to your MDM server in Apple Business Manager (ABM).
  • The Mac supports Erase All Content and Settings: Apple Silicon or Intel with T2 chip, running macOS 12.0.1 or later.
  • You have Jamf Pro admin access to create PreStage profiles, API clients, smart groups, scripts, and policies.

One-time setup

Complete these steps once. After setup, the recovery loop runs automatically for every subsequent wipe.
1

Configure the PreStage Enrollment profile

In Jamf Pro, go to Computers > PreStage Enrollments and open or create the PreStage for your Mac fleet.General tab: Ensure the PreStage is assigned to your target devices in ABM.Setup Assistant tab: Select all items to skip. The machine must advance through Setup Assistant completely unattended.Account Settings tab:
  • Enable Create a managed local administrator account during macOS Setup Assistant.
  • Set a username (for example, administrator) and password.
  • Enable Make the managed local administrator account MDM-enabled.
  • Under Local User Account Type, select Skip. This prevents macOS from presenting the account creation screen during Setup Assistant.
2

Create an API client

Go to Settings > API Roles and Clients.Create an API Role with the following settings:
  • Name: Remote Access Provisioning
  • Privileges: Read Computers and Send Computer Remote Desktop Command
Then create an API Client:
  • Display Name: Remote Access Provisioning
  • Role: assign the role you just created
  • Token lifetime: 60 seconds
  • Status: enabled
Copy the Client ID and Client Secret after saving.
3

Create the monitoring Smart Group

This group gives you visibility into machines that still need remote access enabled. It is not used as a policy scope.
  • Name: Remote Management - Disabled
  • Criteria: Remote Desktop Enabled is No
After a successful recovery, the machine drops out of this group automatically.
4

Create the policy scope Smart Group

Using enrollment method as the criterion avoids race conditions with inventory collection timing.
  • Name: ADE Enrolled Machines
  • Criteria: Enrollment Method is PreStage Enrollment
  • Optional: add PreStage Enrollment is [your PreStage name] to target a specific PreStage.
5

Add the script

Go to Settings > Computer Management > Scripts > New.Set the Display Name to Enable Remote Access Post-Enrollment.On the Options tab, set the following parameter labels:
  • Parameter 4: API Client ID
  • Parameter 5: API Client Secret
  • Parameter 6: Jamf Pro URL
  • Parameter 7: Temp Username
  • Parameter 8: Temp Password
On the Script tab, paste the following:
#!/bin/bash

###############################################################################
# enable_remote_access.sh
#
# Triggered by Jamf Pro enrollment complete policy.
# - Creates a standard local temporary user account
# - Forces password change on first login
# - Enables SSH (Remote Login) directly via systemsetup
# - Calls the Jamf Pro API to send the Enable Remote Desktop MDM command
#   to this device using its own serial number for lookup
#
# Parameters:
#   $4 - Jamf Pro API Client ID
#   $5 - Jamf Pro API Client Secret
#   $6 - Jamf Pro URL (e.g. https://yourinstance.jamfcloud.com)
#   $7 - Temporary local username (e.g. tempuser)
#   $8 - Temporary local password
###############################################################################

CLIENT_ID="$4"
CLIENT_SECRET="$5"
JAMF_URL="$6"
TEMP_USER="$7"
TEMP_PASS="$8"

if [[ -z "$CLIENT_ID" || -z "$CLIENT_SECRET" || -z "$JAMF_URL" ]]; then
    echo "ERROR: Missing required parameters. Check Parameter 4 (Client ID), 5 (Client Secret), 6 (Jamf URL)."
    exit 1
fi

if [[ -z "$TEMP_USER" || -z "$TEMP_PASS" ]]; then
    echo "ERROR: Missing temp user parameters. Check Parameter 7 (username) and 8 (password)."
    exit 1
fi

JAMF_URL="${JAMF_URL%/}"

# Create temporary standard local user
echo "Creating temporary local user: $TEMP_USER..."
/usr/sbin/sysadminctl -addUser "$TEMP_USER" -fullName "Temporary User" -password "$TEMP_PASS"
if [[ $? -eq 0 ]]; then
    echo "User $TEMP_USER created."
else
    echo "WARNING: sysadminctl returned an error. User may not have been created."
fi

# Force password change on first login
/usr/bin/pwpolicy -u "$TEMP_USER" -setpolicy "newPasswordRequired=1"
if [[ $? -eq 0 ]]; then
    echo "Password change required on first login."
else
    echo "WARNING: Could not set newPasswordRequired policy for $TEMP_USER."
fi

# Enable SSH (Remote Login) locally -- no MDM command required
echo "Enabling SSH (Remote Login)..."
/usr/sbin/systemsetup -setremotelogin on
if [[ $? -eq 0 ]]; then
    echo "SSH enabled."
else
    echo "WARNING: systemsetup -setremotelogin returned an error. SSH may not be enabled."
fi

# Get bearer token
echo "Requesting API token..."
TOKEN_RESPONSE=$(curl -s -X POST "$JAMF_URL/api/oauth/token" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&grant_type=client_credentials")

TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4)

if [[ -z "$TOKEN" ]]; then
    echo "ERROR: Failed to obtain API token. Check Client ID and Secret."
    echo "Response: $TOKEN_RESPONSE"
    exit 1
fi

echo "Token obtained."

# Get this device's serial number
SERIAL=$(system_profiler SPHardwareDataType | awk '/Serial Number/{print $4}')

if [[ -z "$SERIAL" ]]; then
    echo "ERROR: Could not determine serial number."
    exit 1
fi

echo "Serial number: $SERIAL"

# Brief pause for Jamf DB write lag after enrollment
sleep 20

# Look up Jamf device ID by serial number
echo "Looking up Jamf ID for serial $SERIAL..."
COMPUTER_XML=$(curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/xml" "$JAMF_URL/JSSResource/computers/serialnumber/$SERIAL")

COMPUTER_ID=$(echo "$COMPUTER_XML" | xpath -q -e "//computer/general/id/text()" 2>/dev/null)

if [[ -z "$COMPUTER_ID" ]]; then
    echo "ERROR: Could not find Jamf ID for serial $SERIAL."
    echo "Response: $COMPUTER_XML"
    exit 1
fi

echo "Jamf ID: $COMPUTER_ID"

# Send Enable Remote Desktop MDM command via Jamf API
echo "Sending Enable Remote Desktop command..."
COMMAND_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: Bearer $TOKEN" "$JAMF_URL/JSSResource/computercommands/command/EnableRemoteDesktop/id/$COMPUTER_ID")

if [[ "$COMMAND_RESPONSE" == "201" ]]; then
    echo "SUCCESS: Enable Remote Desktop command queued for device ID $COMPUTER_ID."
    exit 0
else
    echo "ERROR: API returned HTTP $COMMAND_RESPONSE when sending remote desktop command."
    exit 1
fi
On a freshly wiped macOS install, /usr/bin/python3 is a stub that triggers an Xcode Command Line Tools install prompt. In a headless session this fails silently. The script uses grep and cut instead, which are always available.
6

Create the policy

Go to Computers > Policies > New.General payload:
  • Display Name: Enable Remote Access - Post Enrollment
  • Trigger: Enrollment Complete
  • Execution Frequency: Ongoing
Scripts payload: Add Enable Remote Access Post-Enrollment and fill in all five parameters:
  • Parameter 4: your API Client ID
  • Parameter 5: your API Client Secret
  • Parameter 6: https://yourinstance.jamfcloud.com
  • Parameter 7: temp username (for example, tempuser)
  • Parameter 8: temp password
Scope tab: Scope to the ADE Enrolled Machines Smart Group. Save the policy.

Recovery procedure

Once setup is complete, recovering a machine requires a single action.
  1. In Jamf Pro, open the target machine’s inventory record.
  2. Click Management > Wipe Computer.
    • Only check Clear Activation Lock if Activation Lock is confirmed active on the device.
    • If prompted for a wipe passcode, enter any 6-digit value (for example, 123456). The secure enclave wipe bypasses it on modern macOS.
  3. Click Wipe. No further action is required.
The machine reboots, re-enrolls, and the policy runs automatically. The temporary user account is created, SSH is enabled, and Screen Sharing is enabled. Hand the temporary credentials to the user. They can connect via VNC immediately and will be prompted to set a new password on first login. Monitoring progress: Refresh Computers until the machine reappears (typically 5 to 10 minutes). Open the computer record and check History > Policy Logs to confirm the script exited with code 0. Then check History > Management Commands to see EnableRemoteDesktop move from Pending to Completed. Policy Logs is the leading indicator: if the script succeeded, SSH is already up and the temporary user account exists before the MDM command finishes.

Verify the recovery

  • Policy Logs: Enable Remote Access - Post Enrollment ran and exited with code 0.
  • Management Commands: EnableRemoteDesktop shows status Completed.
  • SSH: ssh administrator@[machine-ip]
  • Screen Sharing: connect to vnc://[machine-ip] and log in with the temporary credentials.
  • The machine no longer appears in the Remote Management - Disabled Smart Group.

Troubleshooting

SymptomLikely causeFix
Machine stuck on account creation screen after wipeLocal User Account Type in PreStage not set to SkipEdit PreStage Account Settings and select Skip under Local User Account Type
Machine does not appear in Jamf after wipeABM assignment not synced to JamfGo to Settings > Global > Device Enrollment Program > your ABM token > Sync Now
Script fails with token errorClient ID or Secret incorrect in policy parametersEdit the policy Scripts payload and verify Parameters 4 and 5
Temp user not createdUsername or password missing from policy parametersEdit the policy Scripts payload and verify Parameters 7 and 8
Policy never fires after enrollmentTrigger not set to Enrollment Complete, or machine not in ADE Enrolled Machines groupVerify the policy trigger and Smart Group criteria
EnableRemoteDesktop queued but never completesMachine lost network before Jamf could push the MDM commandConfirm wired Ethernet and DHCP; re-run the policy manually