How to know using a script if a mac is actually bound to AD?

osxadmin
Contributor II

here's my problem:
-a user tries to change his/her password and it fails because the mac lost trust with AD, I'm able to send configuration profiles, do a "sudo jamf recon" works fine, except the mac is not bound, even though in Directory Utility it shows its bound.

-after unbinding and rebinding everything works fine.
(fyi: macs are on 10.11.6 and 10.12.x with JSS: 9.96)

I'm trying to avoid having to do that manually.
How can I do that using a script if a mac is actually bound to AD?

thank you for your help.

2 ACCEPTED SOLUTIONS

mlavine
Contributor

Hi @osxadmin, I've run into the exact kind of issue that you are describing and this is what I did.

I created 2 extension attributes to check the AD status of a machine.

The first one checks if the machine is bound to AD but doesn't query AD for verification.

#!/bin/sh

ADDomainCheck=$(dsconfigad -show | awk '/Active Directory Domain/{print $NF}')

if [ "$ADDomainCheck" = "" ]; then
        result="Not Bound to Active Directory"
elif [ "$ADDomainCheck" != "" ]; then
        result=$ADDomainCheck
fi

echo "<result>$result</result>"

The second one checks if the machine is connected to AD by reading its own AD object.

#!/bin/bash

###### Do not edit below this line

dscacheutil -flushcache

sleep 5

# Check if the computer is on the network by reading its own computer object from AD

    # Get Domain from full structure, cut the name and remove space.
    ShortDomainName=$(dscl /Active Directory/ -read . | grep SubNodes | sed 's|SubNodes: ||g')

    computer=$(dsconfigad -show | grep "Computer Account" | awk '{ print $4 }')
    dscl /Active Directory/$ShortDomainName/All Domains -read /Computers/$computer RecordName &>/dev/null

    if [ ! $? == 0 ] ; then 
        echo "<result>No connection to the domain</result>"
        exit 1
    else
        echo "<result>Connected to $ShortDomainName</result>"
    fi


exit 0

If a Mac still believes it is connected but isn't communicating with AD then the first extension attribute will return the domain name and the second will say "No connection to the domain".

Using these two extension attributes I can tell if a Mac is truly connected and communicating with AD.


If a machine has lost that trust then I have a policy that I run on it to Rebind. The policy is in 4 parts.

First, a simple time sync with Apple's server.

#!/bin/bash

ntpdate -u time.apple.com

Second, I force the machine to drop the binding. Just as an FYI, the user account and password don't matter in this script.

#!/bin/bash

dsconfigad -force -remove -u johndoe -p nopasswordhere

exit 0

Third, I run a Directory Binding policy.

Lastly, I update my inventory.

Also, I didn't come up with the code for any of this and I cannot remember where I got it from but all credit to their creators.

View solution in original post

mm2270
Legendary Contributor III

Welcome to the un-wonderful world of AD bind woes!

I think we've almost all run into these issues, and continue to, so you're in good company.

So you understand the core problem, it is that you cannot trust the info coming from dsconfigad -show. You just can't. The reason is, that simply reads from a local plist file that gets created at bind time. Unfortunately that doesn't mean anything. AD join, or AD communication, can get broken in a few ways. For one, if the Mac is out of AD communication for too long, it may lose it's communication. Especially if you leave the default password interval setting in your bind config (14 days) If it's not connected to your network for too long it will simply stop communicating.
The 2nd reason is that the AD System keychain may have been removed. Upon bind, Apple's AD plugin creates a System keychain that usually shows up like /Active Directory/DOMAIN or something like that. This is what actually stores the computer to AD password and that the Mac will use to "talk" with AD. For reasons I haven't been able to nail down, sometimes that keychain goes missing and then the AD join is broken until it's rejoined. It's likely either a bug in Apple's AD plug-in that they have never fixed, or it's something 3rd party causing it, like our McAfee Endpoint Security software. Unfortunately I have never been able to catch it "in the act" so to speak, so I have nothing to prove my suspicion on that.

To that end, we have an Extension Attribute that verifies AD join, by checking all of the above stuff and reports on whether it's good or if the AD System keychain is missing or if lookups are just failing. Or, lastly, if the Mac is sitting outside the network (we have a DMZ accessible JSS)
This has helped us determine why a user suddenly starts having problems changing passwords, or has changed it and it won't sync to their account and FIleVault for example.

View solution in original post

10 REPLIES 10

BenL
New Contributor III

I have a Self Service policy that has a before script to remove the binding then uses the Directory Binding jamf framework as a 2nd part to add it back. If a user has that issue they just go into Self Service and run it.

hkabik
Valued Contributor

run an id command on a known AD user

id username

If you get anything but:
id: username: no such user

Then you're good to go.

osxadmin
Contributor II

@BenL could you share your script?
what you have, is exactly what I'm looking for.

mlavine
Contributor

Hi @osxadmin, I've run into the exact kind of issue that you are describing and this is what I did.

I created 2 extension attributes to check the AD status of a machine.

The first one checks if the machine is bound to AD but doesn't query AD for verification.

#!/bin/sh

ADDomainCheck=$(dsconfigad -show | awk '/Active Directory Domain/{print $NF}')

if [ "$ADDomainCheck" = "" ]; then
        result="Not Bound to Active Directory"
elif [ "$ADDomainCheck" != "" ]; then
        result=$ADDomainCheck
fi

echo "<result>$result</result>"

The second one checks if the machine is connected to AD by reading its own AD object.

#!/bin/bash

###### Do not edit below this line

dscacheutil -flushcache

sleep 5

# Check if the computer is on the network by reading its own computer object from AD

    # Get Domain from full structure, cut the name and remove space.
    ShortDomainName=$(dscl /Active Directory/ -read . | grep SubNodes | sed 's|SubNodes: ||g')

    computer=$(dsconfigad -show | grep "Computer Account" | awk '{ print $4 }')
    dscl /Active Directory/$ShortDomainName/All Domains -read /Computers/$computer RecordName &>/dev/null

    if [ ! $? == 0 ] ; then 
        echo "<result>No connection to the domain</result>"
        exit 1
    else
        echo "<result>Connected to $ShortDomainName</result>"
    fi


exit 0

If a Mac still believes it is connected but isn't communicating with AD then the first extension attribute will return the domain name and the second will say "No connection to the domain".

Using these two extension attributes I can tell if a Mac is truly connected and communicating with AD.


If a machine has lost that trust then I have a policy that I run on it to Rebind. The policy is in 4 parts.

First, a simple time sync with Apple's server.

#!/bin/bash

ntpdate -u time.apple.com

Second, I force the machine to drop the binding. Just as an FYI, the user account and password don't matter in this script.

#!/bin/bash

dsconfigad -force -remove -u johndoe -p nopasswordhere

exit 0

Third, I run a Directory Binding policy.

Lastly, I update my inventory.

Also, I didn't come up with the code for any of this and I cannot remember where I got it from but all credit to their creators.

mm2270
Legendary Contributor III

Welcome to the un-wonderful world of AD bind woes!

I think we've almost all run into these issues, and continue to, so you're in good company.

So you understand the core problem, it is that you cannot trust the info coming from dsconfigad -show. You just can't. The reason is, that simply reads from a local plist file that gets created at bind time. Unfortunately that doesn't mean anything. AD join, or AD communication, can get broken in a few ways. For one, if the Mac is out of AD communication for too long, it may lose it's communication. Especially if you leave the default password interval setting in your bind config (14 days) If it's not connected to your network for too long it will simply stop communicating.
The 2nd reason is that the AD System keychain may have been removed. Upon bind, Apple's AD plugin creates a System keychain that usually shows up like /Active Directory/DOMAIN or something like that. This is what actually stores the computer to AD password and that the Mac will use to "talk" with AD. For reasons I haven't been able to nail down, sometimes that keychain goes missing and then the AD join is broken until it's rejoined. It's likely either a bug in Apple's AD plug-in that they have never fixed, or it's something 3rd party causing it, like our McAfee Endpoint Security software. Unfortunately I have never been able to catch it "in the act" so to speak, so I have nothing to prove my suspicion on that.

To that end, we have an Extension Attribute that verifies AD join, by checking all of the above stuff and reports on whether it's good or if the AD System keychain is missing or if lookups are just failing. Or, lastly, if the Mac is sitting outside the network (we have a DMZ accessible JSS)
This has helped us determine why a user suddenly starts having problems changing passwords, or has changed it and it won't sync to their account and FIleVault for example.

thoule
Valued Contributor II

@hkabik FYI, the 'id' command will return a cached result if a user has cached their account. No Such User is returned only if an ID has never logged in before and domain binding is not valid. Therefor an EA like posted above is more reliable.

osxadmin
Contributor II

thank you everyone for your help...I really appreciated.

hkabik
Valued Contributor

I use a service account as the id target. It would never be logged into any machine.

clegger06
New Contributor III

@mlavine or anyone else who understands my question,

I would like to take your script from above, the one related to "The second one checks if the machine is connected to AD by reading its own AD object."...

If I don't want a "ShortDomainName" how can I edit,

ShortDomainName=$(dscl /Active Directory/ -read . | grep SubNodes | sed 's|SubNodes: ||g')

To show the full domain name?

ryan_ball
Valued Contributor

I use something like this in a LaunchDaemon to check the bind functionality and fix it if necessary:

domain=""           # Full domain name; i.e. contoso.com
shortDomain=""      # Short domain name in all caps; i.e. CONTOSO

if [[ $(/usr/sbin/dsconfigad -show | awk '/Active Directory Domain/{print $NF}') == "$domain" ]]; then
    # Mac has correct dsconfigad info
    if /usr/bin/security find-generic-password -l "/Active Directory/$shortDomain" | grep "Active Directory" &> /dev/null; then
        # AD keychain entry exists
        computerName=$(/usr/sbin/dsconfigad -show | awk '/Computer Account/{print $NF}')
        if /usr/bin/dscl "/Active Directory/$shortDomain/All Domains" read /Computers/"$computerName" | grep -i "$computerName" &> /dev/null; then
            # Found AD entry. Binding is good
            echo "Mac has a functional Active Directory bind; no changes necessary."
        else
            echo "Can't lookup computer object in Acrive Directory."
        fi
    else
        echo "AD Keychain entry missing."
    fi
else
    echo "The Mac is not bound to $domain."
fi