Apple Event: May 7th at 7 am PT

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

Feb 8, 2012 5:37 AM in response to Kevin Trumbull

Hi Kevin


That looks promising and thank you very much for mentioning PasteBin!

A suggestion I have: One could add better command line usability, e.g. call the script with parameters, so that one does not have to edit the script itself if in need of changing parameters, servers etc.


That would look like this:


./DirectorybindingScript.sh your.ad.serv.er your.od.serv.er ADMINNAME ADMINPW...

Feb 21, 2012 7:50 PM in response to Community User

Sorry about the delay in replying...


Regarding command line usage, I completely agree. What's currently there is pretty weak. That's one of the things that I'd like to fix once it's working.


I have a couple of questions regarding your setup, mostly due to how some of the script is written...


Near the top of the script there's the following line:

check4ODtmp=`dscl localhost -list /LDAPv3 | grep -n 1 | sed 's/1://' | sed 's/2://'`


Are you using an IP address to bind to the Open Directory server?


I get the run the following command under 10.5, 10.6, and 10.7 I get the result listed below it:

$ dscl localhost -list /LDAPv3

server.domain.internal


And yes, sadly we use a 'fake' TLD...


The point is that there's no result that contains a "1". Also it's kinda odd to have grep number the results (grep -n), only to remove them with sed (sed 's/1://')...


Perhaps it's an uncaught error, that doesn't cause binding issues...


I'll try to get around to uploading a newer version of the script soon.


Anyway, thanks for your time...

Feb 21, 2012 10:29 PM in response to Kevin Trumbull


Kevin Trumbull wrote:


Near the top of the script there's the following line:

check4ODtmp=`dscl localhost -list /LDAPv3 | grep -n 1 | sed 's/1://' | sed 's/2://'`




In my environment I have a few machines bound to two LDAP-Servers: OD and our Master LDAP for authentication instead of AD (which is essentially in Sync with the LDAP anyway). So I'll get two lines as a result of the command dscl localhost -list /LDAPv3.


That's quite bad if I want to use this result afterwards as name for the server, as it will not work :-) So I just grep one of the two lines (by grep -n 1) and strip it off the line number. When the first server is unbound, check4ODtmp will return the second LDAP server, that's why I have two unbinding sections for LDAP Servers in the script.


I admit this is ugly, a much better way to do this would be to fill an array with the ldap servers


ldapArray=( $(dscl localhost -list /LDAPv3) )


and then loop over the array for the unbinding process.


for i in "${ldapArray[@]}"

do

:

done


Feb 22, 2012 9:05 AM in response to Community User

seegorkesolot wrote:



Kevin Trumbull wrote:


Near the top of the script there's the following line:

check4ODtmp=`dscl localhost -list /LDAPv3 | grep -n 1 | sed 's/1://' | sed 's/2://'`


In my environment I have a few machines bound to two LDAP-Servers: OD and our Master LDAP for authentication instead of AD (which is essentially in Sync with the LDAP anyway). So I'll get two lines as a result of the command dscl localhost -list /LDAPv3.


That's quite bad if I want to use this result afterwards as name for the server, as it will not work :-) So I just grep one of the two lines (by grep -n 1) and strip it off the line number. When the first server is unbound, check4ODtmp will return the second LDAP server, that's why I have two unbinding sections for LDAP Servers in the script.


I admit this is ugly, a much better way to do this would be to fill an array with the ldap servers


ldapArray=( $(dscl localhost -list /LDAPv3) )


and then loop over the array for the unbinding process.


for i in "${ldapArray[@]}"

do

:

done

Feb 22, 2012 12:37 PM in response to Community User

Apparently there is a timeout in the submission form. It ate my reply. For best results, use a text editor to type posts, since the submission form should not be trusted.


Also, you cannot delete a post made in error. Lame…

------------------------------


I had originally wondered if you were trying to do the equivalent of "head -n 1" with "grep -n 1".


I got no results from "dscl localhost -list /LDAPv3 | grep -n 1" on a bound machine that showed the domain using "dscl localhost -list /LDAPv3". So I checked the man pages. "grep -n" numbers the lines, but the "1" is used as a matching pattern.


"grep -n 1" will only show machines whose names contain a "1".


Since the server in my environment has a "2" in the name, "dscl localhost -list /LDAPv3 | grep -n 2" will list it but "dscl localhost -list /LDAPv3 | grep -n 1" doesn't list anything.


I'm guessing that there is a "1" somewhere in the names of your servers if they're showing up, since I've not had this work on 10.5, 10.6, or 10.7.



I'd not thought of including support for multiple servers until I'd read this script. It makes perfect sense to do so, and I'd considered using an array to do it. On the other hand, I've also been considering whether it might make sense to put the check in a function and use a while loop to do something like that. Using a function should make it easier to support multiple OS revisions, but might require more time than I have to put into it right now.


Another intriguing thought… Apparently in XCode 4, it's pretty easy to create automator actions that are simply wrappers for a shell script. I'm not committing to turning this into an Automator action just yet, but it's definitely something I might look into when the script is done.



Once again, thank you for your time. While I've done a fair bit of shell-based automation work on MacOS X, I'm new to dealing with directory services in this environment... I'm still trying to make sure that I'm not missing anything. 🙂

Feb 22, 2012 1:00 PM in response to Kevin Trumbull

Kevin Trumbull wrote:


"grep -n 1" will only show machines whose names contain a "1".

Ah of course, my bad! You're right and I'm wrong :-) The handling of multiple ldap-servers is not crucially necessary as the script is deleting the whole existing DS-config anyway (that's why it worked to unbind my ldap-server although it hasn't a "1" in its name).

But if this is implemented right (better than I did apparently :-)), it is capable as intended to properly delete machine records in the DS-Nodes and so on. Otherwise it will leave behind some zombie accounts on the server.

Kevin Trumbull wrote:


Another intriguing thought… Apparently in XCode 4, it's pretty easy to create automator actions that are simply wrappers for a shell script. I'm not committing to turning this into an Automator action just yet, but it's definitely something I might look into when the script is done.

Yeah, why not? I thought of writing a Cocoa Wrapper as well to pass all the parameters to the script. That shouldn't be too hard to do. But as you said, it's not that high in priority. ;-)

Feb 26, 2012 7:44 PM in response to Community User

Regarding the handling of existing records...


I very much like the idea of the script cleaning up after itself and not leaving zombie records, or duplicates laying around. I've seen far too many problems crop up when things get cluttered.


However, 95% of the time I'm re-imaging a machine that's already been bound to Open Directory and Active Directory at some point. What I need is for the machine to be able to set itself back up to match it's previous configuration. This means binding to directory services using the same name and computergroup it was previously set to use, while making it possible to alter those things if it needs to be redeployed.


So the question was how best to keep persistant records of the machine specific information required to rebind the machine that will survive reformatting of the hard drive. Years ago, a colleague and I did this using an FTP server to store a directory for each machine named using it's MAC address. Our scripts created a config file containing all of the configuration data for each machine in it's MAC-named directory. However, I don't want to do that this time for a number of reasons.


It occurred to me that I should look into the directory services themselves for this information. Since my knowledge of LDAP specifics was somewhat limited it took me a bit to figure the following two things out...



The first thing is that Open Directory stores the MAC address of the wired ethernet card (en0) in computer records.


The following command should use the MAC address to retrieve the computer name of any previously bound machine from Open Directory:

/usr/bin/ldapsearch -x -h OpenDirectoryServerFQDN -b "cn=computers, dc=YourServer, dc=YourDomain, dc=TLD" "macAddress=`ifconfig en0 | awk '/ether/{print $2}'`"

-- Note: That's a single command line...

-- For some reason, this command did not require authentication or being on the domain to work.


This also removed the dependancy on the imaging solution or me to rename the machine properly. The command will pull the name from Open Directory regardless of how you re-image or re-install the OS.



The second obstacle I needed remove in making a single script able to work for every machine in my environment was the issue of computer groups.


The following command should hopefully use the computer name to retrieve the computer group any previously bound machine from Open Directory:

dscl -u OpenDirectoryAdmin OpenDirectoryServerFQDN -list /LDAPv3/127.0.0.1/ComputerGroups Member | awk '/ComputerName/{print $1}'

-- Note: That's a single command line...

-- This requires authentication, and will probably have to be scripted using "expect" since I couldn't get the "-p" or "-P" options to work.


This removes the dependancy in the script for specifying which group a machine was previously in. There's 82 computer groups in my environment, which is more than I care to worry about keeping track of. 😉 This should allow for more precise handling of computers that are in multiple computer groups.



There is another reason why I believe that querying the directory service server is the optimal way to deal with this. If I'm not mistaken, since the script is querying the "main" Open Directory server, it should always be in sync with that server. This should make it possible to simply configure these things on the server, and the script will take care of the rest. If possible, I'd prefer not to have to configure anything on a client machine beyond building the inital install.


Since I don't have a great deal of experience with digging into directory services at this low a level, I'm not sure if the paths have changed between versions of OSX server, or how much this varies from one deployment to another.


I'd appreciate whatever feedback I can get regarding those commands and environments other than my own. I'd also appreciate whatever insight and/or improvements anyone can offer.

Feb 27, 2012 6:12 AM in response to Kevin Trumbull

Kevin Trumbull wrote:

dscl -u OpenDirectoryAdmin OpenDirectoryServerFQDN -list /LDAPv3/127.0.0.1/ComputerGroups Member | awk '/ComputerName/{print $1}'

-- Note: That's a single command line...

-- This requires authentication, and will probably have to be scripted using "expect" since I couldn't get the "-p" or "-P" options to work.

I'd prefer to use "ldapsearch" to retrieve the computer group since it might work without requiring the use of "expect". Where possible I try to avoid using "expect".


I tried a number of different variations using "ldapsearch" as well as "dscl" to get the information. Using the above "dscl" command finally provided the information.

Feb 27, 2012 8:29 AM in response to Kevin Trumbull

While it's likely that seegorkesolot understands the above two commands, I'll explain them for whomever else may come across this thread. I also noticed an error, which is corrected below.


The "dscl" command (quoted in the previous post) does the following:

  1. It uses "dscl -u OpenDirectoryAdmin OpenDirectoryServerFQDN" to search the specified server as the user "OpenDirectoryAdmin".
    1. This command will ask for a password before it provides the requested information.
    2. There are options that are supposed to allow you to specify the password as well, however it's been widely reported that they don't work. I couldn't get them to work either.
  2. It uses "-list /LDAPv3/127.0.0.1/ComputerGroups Member" to list the "Member" information for every computer group on the server.
    1. It's possible that the path could be something other than "/LDAPv3/127.0.0.1" on other servers. I think this is the default in 10.5 server.
    2. It lists the groups, one per line, with the name of the group followed by a list of the machines in it.
    3. There are a number of different attributes which contain a list of group members. They are "dsAttrTypeNative:memberUid" and "GroupMembership". I'm not sure which one of the three is best to use. I arbitrarily picked "Members".
  3. It uses "awk '/ComputerName/{print $1}'" to get the computer group name.
    1. The text used for "ComputerName" will be what was retrieved using the "ldapsearch" command (quoted below).
    2. The above "awk" command matches every single line that contains the name of the computer.
    3. This means that if the computer is in multple groups, this command should return the names of all of them, one per line.



I just noticed an error. The "ldapsearch" command in the previous post should be:

/usr/bin/ldapsearch -x -h OpenDirectoryServerFQDN -b "cn=computers, dc=YourServer, dc=YourDomain, dc=TLD" "macAddress=$(ifconfig en0 | awk '/ether/{print $2}')" | awk '/realname/{print $2}'

The "ldapsearch" command (quoted above) does the following:

  1. It uses "$(ifconfig en0 | awk '/ether/{print $2}')" to get the information of the main (wired) ethernet card. It passes that information to "awk" which outputs the second bit of information on the line that contains the text "ether".
    1. The result is the MAC address.
    2. Since the command is wrapped in "$()", it's run before anything and the result is inserted into the command line.
    3. I'll probably use a pre-set variable for this in the script.
    4. I initally used ` `(backticks) to wrap the command but changed it to $(), since that's generally preferred...
  2. It uses "ldapsearch -h YourServer.domain.TLD -b "cn=computers, dc=YourServer, dc=domain, dc=TLD" "macAddress=00:00:00:00:00:00"" to retrieve the computer's record from the specified Open Directory server.
    1. I used "00:00:00:00:00:00", shown above, represents the MAC address of the machine retrieved using ifconfig.
    2. It searches the "computers" container. (It's possible that your machines may not be in this container, however "computers" should be the default.)
    3. It uses the MAC address of the machine it's run on to find it's computer record. The MAC address can generally be trusted to be unique.
  3. It sends the information in the computer record to "awk '/realname/{print $2}'", which retrives the computer name from the record.

    I could have also used "awk '/cn:/{print $2}'" or "awk '/apple-realname:/{print $2}'"



It's also worth noting that I've figured out how to retrieve a few other bits of data as well.

  1. The Open Directory UID and GUID for a machine which has been bound.
  2. The GeneratedUID attribute for Open Directory computer groups.
  3. "dscl -u OpenDirectoryAdmin OpenDirectoryServerFQDN -list /LDAPv3/127.0.0.1/ComputerGroups" should output a list showing all of the computer groups on an Open Directory server.
  4. The computer's name from Active Directory.
  5. "ldapsearch -x -D Domain\\ActiveDirectoryAdmin -W -H ldaps://Domain.TLD:636 -b "DC=Domain,DC=TLD" -LLL -v "(sn="loginname")"" will output the information contained in an Active Directory user's account. No "private" information is disclosed; mostly it's a list various IDs, group memberships, and the sort of stuff that's listed under contacts in Outlook.


I've found quite a bit more information while figuring this stuff out, but it doesn't seem applicable to the script. As always, I could be mistaken about that... If there are other bits of information that would smooth things out, let me know.

Mar 18, 2012 11:52 PM in response to dmare

Hi dmare


My version at the beginning should still work (or for 10.7 the one in the other thread) until the more sophisticated script of Kevin is finished. If you only need AD you should delete all the OD-Stuff in it.


Cheers


See

Mar 26, 2012 4:32 PM in response to Community User

Hello All,

I am having a lot of problems with binding in 10.7.3. I had my own script based on Bombich's script, which I used for Snow Leopard, and even worked in 10.7.2, but since 10.7.3, I am having no success.

I tried seegorkesolot's script and it still does not work, I can bind fine, but I cannot login as an AD User.

When I change the IP6 configuration to none, or local-link only, I can login, but after a restart, I cannot login.

I've tried all the tips to no avail.

My current computer is on 10.7.3, and I can login, but I updated it from 10.7.2, which was already bound.

The problem is occuring with newly imaged Macs, with a 10.7.3 build I created.


Any suggestions would be helpful.

I may go back to 10.7.2.


Thanks,

Pete

Mar 27, 2012 5:39 AM in response to ptrondsen

Hi Pete,


I've been having the same issue, I'm binding to only one forest so I uncheck the any domain in forest option. but also if you do you have to have in your search policys Active Directory/DOMAIN_NAME/All Domains and /Active Directory/DOMAIN_NAME/you.domain.here. Also the way they are ordered is very important, you should have your OD server listed first then you.domain.here and the All Domains. When using a script it will always put the AD domains backwords hence All Domains first then your.domain.here. The work around I found for this is to create your image with your.domain.here in the search policys and it will be ordered correctly. I have spoke nto Apple about this and they havent had much to say except that the search policy has to be the way I mentioned above.


Also I have been having issues joining my OD server, I would get the green light saying its connected but it never adds the computers to the OD computer group or lists. I've noticed the only way it will work is to Bind with authentication but the script keeps failing saying cant bind with credentials. I even added the credentials to one of the lines in the OD section of the script since it was not there and it started to work but now seems to be intermittant. I think my big issue is that im in a .local domain. Also just so your aware I can join the OD fine by using system preferences but sometimes in Directory Utility I have the same issue as scripting. I also called Apple on this and they recommended binding through system preferences because they are having issues with directory utility.

Mar 27, 2012 10:05 AM in response to sthrom

Hey Sthrom,

Thank you for the useful information.

That really seems to work, changing the search policies. it's interesting because in Snow Leopard, it was always important to keep the AD Search paths at the top. I'm going to start all over to make sure it works again, but thanks for the info.

The OD part of the script is working for me, which is nice.


Also, originally, I used to have scutil part of the bind script, now run that as a separate script before the binding script, so it's picked up dynamically.


Thanks,

Pete

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.