Newsroom Update

Beginning in May, a special Today at Apple series titled “Made for Business” will offer small business owners and entrepreneurs free opportunities to learn how Apple products and services can support their growth and success. Learn more >

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Directory Binding Script (Active and Open Directory)

Hi everyone


I wrote quite a lengthy script to perform a proper binding to Active- and Open Directory Services in the local network. Since I've done the work, I'd like to share it with others in need of such a thing.

I'm well aware that it is far from perfection, there's no error handling but it's doing a good job. The script is based on two sources I like to mention and thank here:

- The Script written by Ross Hamilton and postet on HowToMac: http://www.howtomac.co.uk/?p=247

- And of course, Mike Bombich's AD Binding Script for Leopard found in http://www.afp548.com/netboot/mactips/scripts.html


It is mainly copy-pasted from the sources above and slightly modified to perform a good and stable job in what it is intended for..



#!/bin/sh

## Script to automate OD and AD Binding to the Servers
## Script written by Marc Horat, URZ Basel, 11.6.2010

# With the use of the following sources as inspiration:

# http://www.howtomac.co.uk/?p=247
#####################################
#Created by Ross Hamilton
#Clock restart / Remove existing settings
#Join to Open Directory and Active Directory
#
#####################################

# Bombich's AD-Bind Script:
# This script binds to AD and configures advanced options of the AD plugin
# As this scripts contains a password, be sure to take appropriate security
# precautions
# 
# A good way to run this script is to set it as a login hook on your master machine
# Because it only needs to be run once, the last thing this script does is to delete
# itself. If you have another login script that you typically run, include the 
# script on your master machine, and indicate its path in the "newLoginScript"
# variable.
#
# If running this as a one-time login hook to bind to AD after imaging,
# be sure to enable auto-login (for any local user) before creating your master image



############ Begin

# Host-specific parameters
# computerid should be set dynamically, this value must be machine-specific
# This value may be restricted to 19 characters! The only error you'll receive upon entering
# an invalid computer id is to the effect of not having appropriate privileges to perform the requested operation
#computerid=`/sbin/ifconfig en0 | awk '/ether/ { gsub(":", ""); print $2 }'` # MAC Address
#computerid=`hostname | sed 's/.unibas.ch//'`
#computerid=`/usr/sbin/scutil --get LocalHostName | cut -c 1-19` # Assure that this will produce unique names!
#computerid=`/usr/sbin/scutil --get LocalHostName`
computerid=`scutil --get ComputerName`
adcomputerid=`echo $computerid | tr [:lower:] [:upper:]`


#####################OD CONFIG#############################
# These variables need to be configured for your env
odAdmin="ENTERODADMIN" #enter your OD admin name between the quotes
odPassword="ENTERODADMINPW"  # Enter your OD admin password between the quotes
oddomain="ENTERODDOMAIN" # FQDN of your OD domain
computerGroup="ENTERODCOMPGROUP"  # Add appropriate computer group you want machines to be added to, case sensitive
oldComputerGroup="ENTEROLDODCOMPGROUP" # If the Computer is in a Group already

#####################END OD CONFIG#############################

# These variables probably don't need to be changed
nicAddress=`ifconfig en0 | grep ether | awk '{print $2}'`
check4OD=`dscl localhost -list /LDAPv3 | grep -n 1 | sed 's/1://' | sed 's/2://'`
check4ODacct=`dscl /LDAPv3/$check4OD -read Computers/"${computerid}" RealName | cut -c 11-`
check4AD=`dscl /Search -read / CSPSearchPath | grep /Active`
osversionlong=`sw_vers -productVersion`
osvers=${osversionlong:3:1}


#####################AD CONFIG#############################
# Standard parameters
domain="ENTERADDOMAIN"            # fully qualified DNS name of Active Directory Domain
udn="ENTERADADMINNAME"            # username of a privileged network user
password="ENTERADADMINPW"                    # password of a privileged network user
ou="OU=ENTER,OU=TARGET,OU=OU,OU=OF,DC=THE,DC=MAC,DC=IN,DC=AD"        # Distinguished name of container for the computer

# Advanced options AD Plugin
alldomains="disable"            # 'enable' or 'disable' automatic multi-domain authentication
localhome="disable"            # 'enable' or 'disable' force home directory to local drive
protocol="smb"                # 'afp' or 'smb' change how home is mounted from server
mobile="disable"            # 'enable' or 'disable' mobile account support for offline logon
mobileconfirm="disable"        # 'enable' or 'disable' warn the user that a mobile acct will be created
useuncpath="enable"            # 'enable' or 'disable' use AD SMBHome attribute to determine the home dir
user_shell="/bin/bash"        # e.g., /bin/bash or "none"
preferred="-nopreferred"    # Use the specified server for all Directory lookups and authentication
                            # (e.g. "-nopreferred" or "-preferred ad.server.edu")
admingroups="ENTERADGROUPSANDUSERSFORADMINISTRATION"                # These comma-separated AD groups may administer the machine (e.g. "" or "APPLE\mac admins")
packetsign="allow"            # allow | disable | require
packetencrypt="allow"        # allow | disable | require
passinterval="14"            # number of days
namespace="domain"            # forest | domain

# Login hook setting -- specify the path to a login hook that you want to run instead of this script
newLoginHook="PATHTOLOGINHOOK"        # e.g., "/Library/Management/login.sh"


#####################END AD CONFIG#############################

#Time Sync

#Restart ntpdate
StartService ()
{
if [ "${TIMESYNC:=-YES-}" = "-YES-" ] && ! GetPID ntpd > /dev/null; then

CheckForNetwork

if [ -f /var/run/NetworkTime.StartupItem -o "${NETWORKUP}" = "-NO-" ]; then exit; fi
touch /var/run/NetworkTime.StartupItem

echo "Starting network time synchronization"

# Synchronize our clock to the network’s time,
# then fire off ntpd to keep the clock in sync.
ntpdate -bvs
ntpd -f /var/run/ntp.drift -p /var/run/ntpd.pid
fi
}

#List existing Directories
echo "This computer is bound to the following Open Directory Services:"
dscl /Search -read / CSPSearchPath | grep /LDAP

sleep 5

echo "This computer is bound to the following Active Directory Services:"
dscl /Search -read / CSPSearchPath | grep /Active

sleep 5
# Removing any existing directory bindings

# Removing any existing directory bindings

if [ "${check4ODacct}" == "${computerid}" ]; then
    echo "This machine already has a computer account on "${oddomain}"."
    if [ "$oldComputerGroup" != "" ]; then
        echo "Removing entry from group $oldComputerGroup"
        dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"$check4OD" -delete /ComputerGroups/"$oldComputerGroup" GroupMembership "${computerid}"
    fi
    echo "Removing Computer entry $computerid in OD"
    dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"$check4OD" -delete /Computers/"${computerid}"
fi
#A second time..
if [ "${check4ODacct}" == "${computerid}" ]; then
    echo "This machine already has a computer account on "${oddomain}"."
    if [ "$oldComputerGroup" != "" ]; then
        echo "Removing entry from group $oldComputerGroup"
        dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"$check4OD" -delete /ComputerGroups/"$oldComputerGroup" GroupMembership "${computerid}"
    fi
    echo "Removing Computer entry $computerid in OD"
    dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"$check4OD" -delete /Computers/"${computerid}"
fi


sleep 10

echo "Removing any existing AD-Binding to "$check4AD""
dsconfigad -v -r -u $udn -p "$password"
dscl /Search -delete / CSPSearchPath "$check4AD"
dscl /Search/Contacts -delete / CSPSearchPath "$check4AD"
dscl /Search -delete / CSPSearchPath "$check4AD"
sleep 10

echo "Removing OD-Binding to "$check4OD""
# Check a second time in order to delete any remaining LDAP-Bindings
echo "Removing OD-Binding to "$check4OD""
dsconfigldap -v -r "$check4OD"
dsconfigldap -v -r "$check4OD"
dscl /Search -delete / CSPSearchPath /LDAPv3/"$check4OD"
dscl /Search/Contacts -delete / CSPSearchPath /LDAPv3/"$check4OD"
dscl /Search -delete / CSPSearchPath /LDAPv3/"$check4OD"



#Remove Existing Directory Services Config
echo "Removing existing DS Config"

if [ ! -d "/Library/Preferences/DirectoryService/ActiveDirectory" ]; then
rm -R /Library/Preferences/DirectoryService/ActiveDirectory*
fi

if [ ! -d "/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig" ]; then
rm -R /Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig*
fi

if [ ! -d "/Library/Preferences/DirectoryService/SearchNode" ]; then
rm -R /Library/Preferences/DirectoryService/SearchNode*
fi

if [ ! -d "/Library/Preferences/DirectoryService/ContactsNode" ]; then
rm -R /Library/Preferences/DirectoryService/ContactsNode*
fi

if [ ! -d "/Library/Preferences/edu.mit.Kerberos" ]; then
rm -R /Library/Preferences/edu.mit.Kerberos
fi

if [ ! -d "/etc/krb5.keytab" ]; then
rm -R /etc/krb5.keytab
fi

# Clean up the DirectoryService configuration files
rm -vfR "/Library/Preferences/DirectoryService/*"
rm -vfR "/Library/Preferences/DirectoryService/.*" 

#############################################################
#OD
#############################################################

echo "Binding to OD-Damin $oddomain"
dsconfigldap -v -a $oddomain -n $oddomain -c $computerid
sleep 5


echo "Killing DirectoryService"
killall DirectoryService

sleep 10

echo "Adding computer account to /LDAPv3/${oddomain}"
dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"${oddomain}" -create /Computers/"${computerid}" ENetAddress "$nicAddress"
dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"${oddomain}" -merge /Computers/"${computerid}" RealName "${computerid}"
# Add computer to ComputerList
dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"${oddomain}" -merge /ComputerLists/${computerGroup} apple-computers "${computerid}"

# Set the GUID
GUID="$(dscl /LDAPv3/${oddomain} -read /Computers/"${computerid}" GeneratedUID | awk '{ print $2 }')"
# Add to computergroup
dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"${oddomain}" -merge /ComputerGroups/"${computerGroup}" apple-group-memberguid "${GUID}"
dscl -u "${odAdmin}" -P "${odPassword}" /LDAPv3/"${oddomain}" -merge /ComputerGroups/"${computerGroup}" memberUid "${computerid}"


sleep 15 # Give DS a chance to catch up

echo "Finished OD Binding."
#############################################################
#AD
#############################################################

# Activate the AD plugin
defaults write /Library/Preferences/DirectoryService/DirectoryService "Active Directory" "Active"
plutil -convert xml1 /Library/Preferences/DirectoryService/DirectoryService.plist

computeridtmp="default"
LEN=$(echo ${#adcomputerid})

if [ $LEN -lt 15 ]; then
        echo "ComputerID "$adcomputerid " has 15 characters or less and is therefore suitable for AD-Binding. It is $adcomputerid"
        computeridtmp=$adcomputerid
else
        echo "ComputerID "$adcomputerid " has 16 or more characters and needs to be modified for AD-Binding."
    echo "Removing any -"
        computeridtmp=${adcomputerid//-/}
        LEN=$(echo ${#computeridtmp})
        if [ $LEN -lt 15 ]; then
            echo "ComputerID "$computeridtmp" has now 15 characters or less and is therefore suitable for AD-Binding."
        else
            echo "Only using the last 15 characters of the Computer name to be able to bind to AD."
            computeridtmp=${computeridtmp:(-15)}
        fi
        echo "Cropped Computername to "$computeridtmp 


fi

# Bind to AD
dsconfigad -f -a $computeridtmp -domain $domain -u $udn -p "$password" -ou "$ou"

# Configure advanced AD plugin options
if [ "$admingroups" = "" ]; then
    dsconfigad -nogroups
else
    dsconfigad -groups "$admingroups"
fi

dsconfigad -alldomains $alldomains -localhome $localhome -protocol $protocol \
    -mobile $mobile -mobileconfirm $mobileconfirm -useuncpath $useuncpath \
    -shell $user_shell $preferred -packetsign $packetsign -packetencrypt $packetencrypt \
    -passinterval $passinterval -namespace $namespace

sleep 20


# Add the OD & AD node to the search path
if [ "$alldomains" = "enable" ]; then
    csp="/Active Directory/All Domains"
else
    csp="/Active Directory/$domain"
fi

echo "Finished AD Binding."

echo "Adding Domain /LDAPv3/"$oddomain" and "$csp" to Search Path"

dscl /Search -create / SearchPolicy CSPSearchPath
#dscl /Search -append / CSPSearchPath /LDAPv3/OD_SERVER
dscl /Search -append / CSPSearchPath /LDAPv3/"$oddomain"
#dscl /Search -append / CSPSearchPath /Active Directory/AD_Domain
dscl /Search -append / CSPSearchPath "$csp"

dscl /Search/Contacts -create / SearchPolicy CSPSearchPath
#dscl /Search/Contacts -append / CSPSearchPath /LDAPv3/OD_SERVER
dscl /Search/Contacts -append / CSPSearchPath /LDAPv3/"$oddomain"
#dscl /Search/Contacts -append / CSPSearchPath /Active Directory/All Domains
dscl /Search/Contacts -append / CSPSearchPath "$csp"

echo "Finished Updating Search Paths."

# Restart DirectoryService (necessary to reload AD plugin activation settings)
killall DirectoryService


# Destroy the login hook (or change it)
if [ "${newLoginHook}" == "" ]; then
    defaults delete /var/root/Library/Preferences/com.apple.loginwindow LoginHook
else
    defaults write /var/root/Library/Preferences/com.apple.loginwindow LoginHook $newLoginHook
fi

sleep 5

# Customizing the login-Window
#defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo DSStatus
#defaults write /Library/Preferences/com.apple.loginwindow showInputMenu -bool TRUE
#defaults write /Library/Preferences/com.apple.loginwindow SHOWFULLNAME -bool TRUE


# Disable autologin
defaults delete /Library/Preferences/com.apple.loginwindow autoLoginUser
srm /etc/kcpassword

# Kill loginwindow to return to the login screen
#killall loginwindow


exit 0        ## Success
exit 1        ## Failure


If anyone has inputs, critics, optimization suggestions or experience reports feel free to post them here ;-)


Cheers

Posted on May 31, 2011 5:09 AM

34 replies

Mar 27, 2012 8:21 PM in response to sthrom

Not sure, if you saw my last reply, but it's been extremely difficult, I am able to login once, but after reboot, I cannot. So, it made me think that maybe this is a Kerberos issue. I imaged the Mac with DeployStudio and apparently DeployStudio writes a duplicate LocalKDC. So, the following is what I did to allow me to consistently login.

1) In the Utilities folder, open Keychain Access. In the System keychain, find and delete the three com.apple.kerberos.kdc entries - a certificate and a public/private key pair generated from that certificate.

This worked, but now Kerberos was no longer working and I was getting Single Sign-ons.

So, the next step is to:

2) In Terminal, run 'sudo rm -fr /var/db/krb5kdc' - this will destroy the local KDC database.
3) In Terminal, run 'sudo /usr/libexec/configureLocalKDC' - this will regenerate the local KDC database, including a new certificate and SHA1 hash.


I have not tested 2, and 3, I will report back.

Apr 3, 2012 6:32 PM in response to ptrondsen

Hi All, I figured out my issue.

The issue was with the Lion Open Directory Server trying provide a Kerberos login at the same time as the AD Server. Once I deleted the Open Directory Server from Directory Utility, I was able to login with my AD Credentials. So, unlike Snow Leopard Server, in Lion Server, you have to completely remove Kerberos with the following command:


sudo sso_util remove -k -a username -p password -r NAME.OF.KERBEROSREALM


(use the OD diradmin and PW)


reboot


This done after setting up the Lion Server as an Open Directory Master, and running the -enablesso, and kerberizing it in a standard way.

Jan 9, 2014 12:37 PM in response to dmare

I have a new simple version of a join to AD script.


It's pretty simple. It prompts for a computer name, then applies that computer name and saves it as a string. Then it runs dsconfigad with the settings provided. This version prompts for the domain admin password but it can be put into the script for more automation. (Seehttps://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/ man8/dsconfigad.8.html for additional dsconfigad configuration settings)


Join to AD Script


#begin script


echo “Enter Computer Name:”

read computername

echo The Computer Name is $computername

scutil --set ComputerName $computername

scutil --set LocalHostName $computername

dsconfigad -add your.domain.com -username domainadmin [-computerid $computername] [-ou CN=Computers,DC=your,DC=domain,DC=com] [-mobile enable] [-mobileconfirm disable] [-useuncpath disable] [-shell /bin/bash]


#end script


I would run this (on 10.8 and 10.9) and it would give me an error saying "Invalid credentials supplied for binding to the server" (It worked fine on 10.7). After some research I found that I needed to run the script as root user. To automate this a little more I wrote a script to run the original script as root user.


Run as Root Script


#begin script


sudo /Path/To/Your/Script/JoinAD.sh


#end script


I then made the root script executable by opening terminal and running:

chmod 755 /Path/To/Your/Script/RunAsRoot.sh


Then I changed the extension to .command. (RunAsRoot.command)


Where I use this, we have a network drive that both of these are stored on. I can just mount the drive and double click the RunAsRoot.command and fill in the require info. After that my machine will be joined to AD!

Directory Binding Script (Active and Open Directory)

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.