We are seeing issues with machines that have broken AD binds, is there a way to automatically remove the profile and reinstall it, or can I just add those machines from a SmartGroup into the scope?
We don’t currently do this in our environment, but if I were going to tackle it, I’d approach it in three steps: detect, group, and remediate.
1) Detect broken AD binds with an Extension Attribute
Create an Extension Attribute (EA) that confirms the Mac is bound and that its AD trust is intact by reading its own computer object. It returns SUCCESS
if both checks pass, otherwise FAIL
:
#!/bin/bash
# EA Name: AD Health
# Data Type: String
# Returns "SUCCESS" if bound & trust OK, else "FAIL"
ADDomain="$(/usr/sbin/dsconfigad -show 2>/dev/null | awk '/Active Directory Domain/{print $NF}')"
if /> -z "$ADDomain" ]]; then
echo "<result>FAIL</result>"
exit 0
fi
ShortDomain="$(/usr/bin/dscl /Active\ Directory/ -read . 2>/dev/null | awk -F': ' '/SubNodes/{print $2}')"
CompAcct="$(/usr/sbin/dsconfigad -show 2>/dev/null | awk '/Computer Account/{print $4}')"
if /usr/bin/dscl "/Active Directory/$ShortDomain/All Domains" -read "/Computers/$CompAcct" RecordName &>/dev/null; then
echo "<result>SUCCESS</result>"
else
echo "<result>FAIL</result>"
fi
Then build a Smart Computer Group where AD Health = FAIL. That group dynamically captures Macs that are unbound or have lost trust (bound‑but‑broken), a common pattern in Jamf deployments. t1]=2]
2) Why not just re‑scope the profile?
Simply re‑scoping a Directory payload/profile is not advisable for broken trust scenarios. The Mac retains the old local AD binding; a re‑applied profile generally can’t overwrite that stale state. You typically need to force‑remove the existing bind first, then re‑apply the binding/profile. This avoids lingering, invalid machine account state that prevents a clean rebind. w1]
3) Remediation Policy
With the Smart Group in place, scope a policy to that group that:
- Force‑removes the existing AD bind.
- Flushes directory caches.
- Rebinds to AD (via
dsconfigad
or by re‑applying your Directory payload/profile). - Runs
jamf recon
to refresh inventory and update the EA/Smart Group.
(If you deploy the AD bind via a Configuration Profile, still do the force‑remove first; then let MDM re‑apply the profile—un‑scope/re‑scope if needed.) f1]p2]
4) dsconfigad and what it does
dsconfigad
is Apple’s CLI for managing macOS–Active Directory integration:
-show
— Displays current AD bind details.-remove
— Unbinds the Mac from AD (removes local directory config).-force
— Forces removal without contacting AD (useful when off‑network or trust is broken).-add
— Binds the Mac to AD using the specified domain, credentials, and options (OU, mobile accounts, etc.).
The commonly used force‑remove line:
/usr/sbin/dsconfigad -force -remove -u "placeholder" -p "placeholder"
-force
ensures the local binding is removed even if AD/DCs are unreachable.- Some macOS versions expect
-u
/-p
with-remove
; when used with-force
, they aren’t validated against AD, so harmless placeholders are acceptable. - Clearing the old binding first is what makes the subsequent rebind (or profile re‑apply) actually stick. -1]
5) Full remediation script (unbind → rebind → verify → recon)
How to use: Add as a Policy script and pass values via Script Parameters (don’t hard‑code secrets).\ Parameters
- $4: AD Domain (e.g.,
ad.example.com
)- $5: Bind account username
- $6: Bind account password
- $7: Target OU (optional; e.g.,
OU=Macs,OU=Computers,DC=ad,DC=example,DC=com
)- $8: Computer ID override (optional; defaults to LocalHostName)
- $9: NTP server (optional; default
time.apple.com
)
#!/bin/bash
# Purpose: Repair a broken AD bind by force-unbinding, time sync, rebind, verify, and recon
# Exit codes: 0=success; non-zero=failure
set -u
# --- Parameters from Jamf ---
DOMAIN="${4:-}"
BIND_USER="${5:-}"
BIND_PASS="${6:-}"
OU="${7:-}"
COMPUTER_ID="${8:-}"
NTP_SERVER="${9:-time.apple.com}"
log() { echo "}$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
current_name() {
local n
n="$(scutil --get LocalHostName 2>/dev/null || true)"
=" -n "$n" ]] || n="$(hostname -s 2>/dev/null || hostname)"
echo "$n"
}
# --- Validate ---
if me -z "$DOMAIN" || -z "$BIND_USER" || -z "$BIND_PASS" ]]; then
echo "ERROR: Missing required parameters: DOMAIN, BIND_USER, BIND_PASS."
exit 2
fi
am -n "$COMPUTER_ID" ]] || COMPUTER_ID="$(current_name)"
# --- 1) Time sync (helps with Kerberos skew) ---
log "Syncing time with $NTP_SERVER..."
/usr/sbin/systemsetup -setusingnetworktime on >/dev/null 2>&1 || true
/usr/sbin/systemsetup -setnetworktimeserver "$NTP_SERVER" >/dev/null 2>&1 || true
if command -v sntp >/dev/null 2>&1; then
sntp -sS "$NTP_SERVER" >/dev/null 2>&1 || true
elif command -v ntpdate >/dev/null 2>&1; then
ntpdate -u "$NTP_SERVER" >/dev/null 2>&1 || true
fi
# --- 2) Force-remove existing bind if present ---
if /usr/sbin/dsconfigad -show >/dev/null 2>&1; then
log "Removing existing AD bind..."
/usr/sbin/dsconfigad -force -remove -u "placeholder" -p "placeholder" || true
else
log "No active AD bind detected."
fi
# --- 3) Flush Directory caches ---
log "Flushing DirectoryService caches..."
/usr/bin/killall opendirectoryd >/dev/null 2>&1 || true
sleep 5
# --- 4) Rebind ---
log "Rebinding to $DOMAIN as '$COMPUTER_ID'..."
REBIND_CMD=(/usr/sbin/dsconfigad -add "$DOMAIN" -username "$BIND_USER" -password "$BIND_PASS"
-computer "$COMPUTER_ID"
-localhome enable -useuncpath disable -alldomains disable
-mobile enable -mobileconfirm disable)
sa -n "$OU" ]] && REBIND_CMD+=(-ou "$OU")
if ! "${REBIND_CMDa@]}" >/dev/null 2>&1; then
echo "ERROR: AD rebind failed."
exit 3
fi
# --- 5) Verify trust by reading the computer object ---
ShortDomain="$(/usr/bin/dscl /Active\ Directory/ -read . 2>/dev/null | awk -F': ' '/SubNodes/{print $2}')"
CompAcct="$(/usr/sbin/dsconfigad -show 2>/dev/null | awk '/Computer Account/{print $4}')"
if ;g -z "$ShortDomain" || -z "$CompAcct" ]]; then
echo "ERROR: Unable to determine ShortDomain or Computer Account after bind."
exit 4
fi
if /usr/bin/dscl "/Active Directory/${ShortDomain}/All Domains" -read "/Computers/${CompAcct}" RecordName >/dev/null 2>&1; then
log "AD trust verified (computer object readable)."
else
echo "ERROR: AD trust verification failed."
exit 5
fi
# --- 6) Recon to refresh EAs/Smart Group membership ---
log "Running jamf recon..."
/usr/local/bin/jamf recon >/dev/null 2>&1 || true
log "Remediation complete."
exit 0
Notes & tips
- Security: Pass bind credentials as Policy Script Parameters (or your organization’s secrets process); don’t hard‑code.
- Performance: AD lookups can be slow off‑network; tune how often inventory runs and consider EA optimizations if needed.
- Jamf docs: EA and Smart Group setup details are in Jamf Pro documentation.
Disclaimer: I haven’t implemented this exact workflow in production, so there may be better approaches—but the logic above matches common practices discussed on Jamf Nation. I also had AI help with formatting and a few insights while drafting this. The scripts are not my own but they look good to me. References below to where I got some of it.
References
I’ve got the EA in place with a SmartGroup to keep track of them, I feel like the old config profile would need to be removed or can I just reinstall the same one by adding the SmartGroup to the targets?
Personally I would get rid of using a config profile to bind to AD. Use a policy to do it instead, that way you can just scope it on deploy and then have a policy in Self Serve (even if scoped to just IT Staff) to rebind.
We also had a policy in AD to rebind. That way the lab tech could take care of it without intervention from the Tech dept.
We used to bind through a script. I’ll look into these, thanks.
Just make sure you don’t make the same mistake I made initially and make sure to force the unbind otherwise you may have issues.
At my old job, we just forced the unbind (dsconfigad -force -remove -u johndoe -p nopasswordhere) and rebound using the AD bind payload nightly after a reboot.
**also had it on a custom trigger for technicians to run
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.