If you are migrating your machines to authenticate via Active Directory, you may need to convert your local user accounts and their home folders to an AD user account and retain the home folder. I had a script posted here but that version was Tiger only because it used NI* commands.
The following script is written in bash and can be run by double clicking (it’s a .command) as a user with sudo rights (all admin users have this right by default). It will prompt for your admin password, then present a list of numbered local users. Enter a number from the list for the user you want to migrate, then it will ask for the network ID. It runs in a loop until you select the option for “Finished” which will exit the script.
This should work with Tiger, Leopard or Snow Leopard and can easily be modified to work with OD user accounts (change the check4AD variable to check for OD instead).
To download the script, click here.
#!/bin/sh Version=1.0 # Modified 1/14/2009 # MigrateLocalUserToDomainAcct.command # Patrick Gallagher # http://macadmincorner.com # # This script should not need any modification in most enviornments. # If the script does not execute when run, you may need to 'chmod +x /path/to/thisScript' to make it executable clear netIDprompt="Please enter the network ID for this user: " listUsers="$(/usr/bin/dscl . list /Users | grep -v eccsadmin | grep -v _ | grep -v root | grep -v uucp | grep -v amavisd | grep -v nobody | grep -v messagebus | grep -v daemon | grep -v www | grep -v Guest | grep -v xgrid | grep -v windowserver | grep -v unknown | grep -v unknown | grep -v tokend | grep -v sshd | grep -v securityagent | grep -v mailman | grep -v mysql | grep -v postfix | grep -v qtss | grep -v jabber | grep -v cyrusimap | grep -v clamav | grep -v appserver | grep -v appowner) FINISHED" FullScriptName=`basename "$0"` ShowVersion="$FullScriptName $Version" check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"` osversionlong=`sw_vers -productVersion` osvers=${osversionlong:3:1} echo "********* Running $FullScriptName Version $Version *********" # If the machine is not bound to AD, then there's no purpose going any further. if [ "${check4AD}" != "Active Directory" ]; then echo "This machine is not bound to Active Directory.\nPlease bind to AD first. "; exit 1 fi RunAsRoot() { ## Pass in the full path to the executable as $1 if [[ "${USER}" != "root" ]] ; then echo echo "*** This application must be run as root. Please authenticate below. ***" echo sudo "${1}" && exit 0 fi } RunAsRoot "${0}" until [ "$user" == "FINISHED" ]; do printf "%b" "\a\n\nSelect a user to convert or select FINISHED:\n" >&2 select user in $listUsers; do if [ "$user" = "FINISHED" ]; then echo "Finshied converting users to AD" break elif [ -n "$user" ]; then if [ `who | grep console | awk '{print $1}'` == "$user" ]; then echo "This user is logged in.\nPlease log this user out and log in as another admin" exit 1 fi # Determine location of the users home folder userHome=`/usr/bin/dscl . read /Users/$user NFSHomeDirectory | cut -c 19-` # Get list of groups echo "Checking group memberships for local user $user" lgroups="$(/usr/bin/id -Gn $user)" if [[ $? -eq 0 ]] && [[ -n "$(/usr/bin/dscl . -search /Groups GroupMembership "$user")" ]]; then # Delete user from each group it is a member of for lg in $lgroups; do /usr/bin/dscl . -delete /Groups/${lg} GroupMembership $user >&/dev/null done fi # Delete the primary group if [[ -n "$(/usr/bin/dscl . -search /Groups name "$user")" ]]; then /usr/sbin/dseditgroup -o delete "$user" fi # Get the users guid and set it as a var guid="$(/usr/bin/dscl . -read "/Users/$user" GeneratedUID | /usr/bin/awk '{print $NF;}')" if [[ -f "/private/var/db/shadow/hash/$guid" ]]; then /bin/rm -f /private/var/db/shadow/hash/$guid fi # Delete the user /usr/bin/dscl . -delete "/Users/$user" # Verify NetID printf "\e[1m$netIDprompt" read netname /usr/bin/killall DirectoryService sleep 10 /usr/bin/id $netname # Check if there's a home folder there already, if there is, exit before we wipe it if [ -f /Users/$netname ]; then echo "Oops, theres a home folder there already for $netname.\nIf you don't want that one, delete it in the Finder first,\nthen run this script again." exit 1 else /bin/mv $userHome /Users/$netname /usr/sbin/chown -R ${netname} /Users/$netname echo "Home for $netname now located at /Users/$netname" fi break else echo "Invalid selection!" fi done done
No related posts.
Find more like this: AD Integration, Directory Services, Mac, Scripting , Active Directory, Admin, Directory Service, Mac, Open Directory, Scripting






This is a fantastic script that really helps me wrap my head around the problem. I will definitely be using this resource in the future. Thank you for sharing!
Will your script migrate user accounts from one domain to another? Just replaced an existing Exchange 2003 server with an Exchange 2010 solution, but the domain and DNS servers are different…
This was the solution we found for migrating each account in Windows:
http://my.galagzee.com/2007/08/05/transparent-windows-workstation-domain-migration/
It would be nice if Snow Leopard had an easy solution for this as well…
Very cool concept, just some thoughts from having run the script on a few system; you might want to add a failsafe on line 74, to confirm that the group getting deleted does not match the “admin” group name (or any other local group name), ie. if the local account’s short name is “admin”, thus causing the “admin” group to be deleted (which removes local admin access for all local and domain accounts). Also, once a local account is selected, shouldn’t the script wait to delete the local account until a domain user is entered (in case you want to close the script and not continue with the migration)? Thanks,
How do I change this for Open Directory? I see the Check4AD variable but Im not sure what I have to change it to?
also do I run this script on the server or local machines?
Thanks
Dave
@David
You can either change the Check4AD variable to look for OD (grep for “LDAPv3″ instead of “Active Directory”) and change the section towards the top of the script (after the variables) to verify the machine is bound to OD, or you can remove that section all together and just tell your techs to make sure the machine is bound before hand.
Otherwise, I *think* the script should run as-is on an OD system. Been a while since I wrote it but glancing over it I don’t see anything that is AD specific other than that 1 section I mentioned.
I stumbled on your script today. Just what I need to help move 50+ computers with local accounts to Open Directory. One little problem so far. Our account names are in the format first_last. grep -v _ skips those accounts. Changing to grep -v ^_ will skip accounts where the first character is an underscore but include accounts with an underscore that’s not the first character.
I also noticed that grep -v unknown is listed twice. Typo?
@Mike
Without the “grep -v _” you will need a different way to to exclude those accounts. Either list each service account to be excluded or limit the scope of users based on the UID. For instance, a small script I just started using in LANrev to list local users:
for i in `dscl . list /users | grep -v _ | grep -v nobody | grep -v daemon | grep -v Guest | grep -v root`;
do uniqueID=`dscl . read /users/$i UniqueID | awk ‘{print $2}’`
if [ $uniqueID -lt 600 ] && [ $uniqueID -ge 499 ]; then
echo $i
fi
done
You could incorporate this into the above script. I don’t have time to sort test it out now.
And yes, having unknown twice is a typo.
Good job, Patrick – this should come in handy at my day gig. Much appreciated for posting.
When the script asks for network ID what do I have to put?
I tried the network account name, and the UID which was 1032, none of these worked???
Thanks
Dave
@David
You use the shortname of the network account. You are bound to AD, correct? The script verifies this by running “id username”. Try that command to verify that machine can lookup that account in AD.
Patrick thank for you fast reply, yes I am bound to OD
I have changed variable as you described above and it prompts me for the admin password.
It then presents the list of users followed by Network ID.
I tried the network shortname, does the network account need to have a home directory already?
Also does this copy all the home folder contents to the server so the user is able to log in from any machine?
@Dave
I think this script is not exactly what you are looking for. This is not to convert a local home to a network home. It also has nothing to do with OD. This is to convert a local account to an AD account with mobile home directory.
This script works great until I’m on a 10.4 computer using a firstname.lastname login convention. 10.4 command line doesn’t handle the . well. I find that I’ve had to manually do the mv and chown but escape the . with a \. Is there a way to get your script to escape the . when used in a username? In the end I use sudo mv oldname firstname\.lastname then sudo chown -R firstname\.lastname:staff firstname\.lastname.
@Richard
Have you tried using quotes instead? It would be easier to quote the shortname.
Hi Patrick, awesome job on this by the way. Just one problem, I keep ending up with the original user folder now IN my network user folder, alongside the network profile folders.
Any idea what is up?
Thanks!
@Beatlemike
This wasn’t intended for use with network homes. If you are running this on your home directory server, you will have to modify it with the correct path to your home folders. This script assumes /Users
No, sorry …. no I worded it wrong it is a mobile home…. the osx kind, not the kind in a trailer park.
@Beatlemike
Do you have user folders in a non-standard location? Are you using Centrify or Likewise?
No it is a standard setup, but it just recreates the entire local home inside the mobile home. instead of replacing the contents
Do I maybe add the AD user AFTER i migrate the user folder? I thought I tried that and it stopped me from creating a user, but I might be wrong.
This is exactly what I am looking for, thanks for the post. One question, and pardon my ignorance, but the network ID, is that just the username? or domain\username? or username@domain? does it need to include the root? .com or .org??? Thanks in advance for the help! I have tried several ways but it never works, have to login as root and rename and create the account back otherwise its just in limbo.
@Jacob
Network ID is just the user name. Machine has to be bound to AD for this to work.
figured that was the case, but just so happens our local account has the same names… firstinitiallastname. If nothing has changed the local account gets moved, but when you login with the network it sets up a new account.
I have also tried changing the account as well as logging in with root and changing the user folder, then tried to migrate to no avail, any advice is greatly appreciated.
Pingback: Another day in the life of a lonely Mac | Charles L'Abri Anderson
I have two issues I need help on, please:
The domain I’m migrating Mac’s into uses usernames of firstname.lastname. I created an account on the mac for the new domain login, using “domainname\username” as the account name, and “firstnamelastname” (with no period since it’s not allowed) for the short name, using the same pw as the domain account.
For example using myself, my domain login kevin.wilson got an account created on the mac of kevinwilson (shortname). The existing local account on the mac was just “kevin”.
I ran the script, telling it to move “kevin” to “kevinwilson”. It ended up putting the “kevin” profile as a subfolder in the “kevinwilson” account.
Do I have to change the domain logins to not use a period? Or is there another way to do it?
Also, is there a way to reverse the changes so I can do it correctly without fighting with permissions on every file in every profile?
Your help is much appreciated.
Kevin
Very cool script.
Thank You for posting it.
I am looking to do something similar, and I have been picking through your script.
Basically, my users are moving to another domain, and once they are moved, I need to delete the reference to the AD User to allow them to login in the new domain,
This command works for this:
dscl . -delete /Users/$user
But some Macs have multiple users, so I am looking for a way to delete all the AD Users, and not the Local Admin, and root, and the other invisible users.
I’m going to keep at it, any suggestions, would be great.
Thanks,
Pete
Okay, here it is, just needed some small mods…..thanks again:
#!/bin/sh
Version=1.0
# Modified 04/20/2010
# DeleteLocalUserAcct.command
# Patrick Gallagher
# http://macadmincorner.com
#
# This script should not need any modification in most enviornments.
# If the script does not execute when run, you may need to ‘chmod +x /path/to/thisScript’ to make it executable
clear
listUsers=”$(/usr/bin/dscl . list /Users | grep -v eccsadmin | grep -v _ | grep -v root | grep -v uucp | grep -v amavisd | grep -v nobody | grep -v messagebus | grep -v daemon | grep -v www | grep -v Guest | grep -v xgrid | grep -v windowserver | grep -v unknown | grep -v unknown | grep -v tokend | grep -v sshd | grep -v securityagent | grep -v mailman | grep -v mysql | grep -v postfix | grep -v qtss | grep -v jabber | grep -v cyrusimap | grep -v clamav | grep -v appserver | grep -v appowner) FINISHED”
FullScriptName=`basename “$0″`
ShowVersion=”$FullScriptName $Version”
check4AD=`/usr/bin/dscl localhost -list . | grep “Active Directory”`
osversionlong=`sw_vers -productVersion`
osvers=${osversionlong:3:1}
echo “********* Running $FullScriptName Version $Version *********”
# If the machine is not bound to AD, then there’s no purpose going any further.
if [ "${check4AD}" != "Active Directory" ]; then
echo “This machine is not bound to Active Directory.\nPlease bind to AD first. “; exit 1
fi
RunAsRoot()
{
## Pass in the full path to the executable as $1
if [[ "${USER}" != "root" ]] ; then
echo
echo “*** This application must be run as root. Please authenticate below. ***”
echo
sudo “${1}” && exit 0
fi
}
RunAsRoot “${0}”
until [ "$user" == "FINISHED" ]; do
printf “%b” “\a\n\nSelect a user to delete FINISHED:\n” >&2
select user in $listUsers; do
if [ "$user" = "FINISHED" ]; then
echo “Finshied!”
break
elif [ -n "$user" ]; then
if [ `who | grep console | awk '{print $1}'` == "$user" ]; then
echo “This user is logged in.\nPlease log this user out and log in as another admin”
exit 1
fi
# Determine location of the users home folder
#u serHome=`/usr/bin/dscl . read /Users/$user NFSHomeDirectory | cut -c 19-`
# Delete the user
/usr/bin/dscl . -delete “/Users/$user”
fi
done
done
I am pretty new to Mac and Apple world. I would like to use Windows AD to authenticate the Mac users who all have windows ad account. Is this requred system admin’s involvement? In other word, can I use this script to do it by myself? Thanks
I have updated the deleteUser script, which worked great for my migration.
Many thanks again to Patrick for the original script. The following Script will prompt to delete the local User folder, not the User Account. The User will be able to login, retaining all data.
#!/bin/sh
Version=1.0
# Modified 04/20/2010
# DeleteLocalUserAcct.command
# Peter Trondsen (Modified Patrick Gallagher’s script)
clear
listUsers=”$(/usr/bin/dscl . list /Users | grep -v eccsadmin | grep -v _ | grep -v root | grep -v uucp | grep -v amavisd | grep -v nobody | grep -v messagebus | grep -v daemon | grep -v www | grep -v Guest | grep -v xgrid | grep -v windowserver | grep -v unknown | grep -v unknown | grep -v tokend | grep -v sshd | grep -v securityagent | grep -v mailman | grep -v mysql | grep -v postfix | grep -v qtss | grep -v jabber | grep -v cyrusimap | grep -v clamav | grep -v appserver | grep -v appowner | grep -v ladmin) FINISHED”
FullScriptName=`basename “$0″`
ShowVersion=”$FullScriptName $Version”
check4AD=`/usr/bin/dscl localhost -list . | grep “Active Directory”`
osversionlong=`sw_vers -productVersion`
osvers=${osversionlong:3:1}
echo “********* Running $FullScriptName Version $Version *********”
# If the machine is not bound to AD, then there’s no purpose going any further.
if [ "${check4AD}" != "Active Directory" ]; then
echo “This machine is not bound to Active Directory.\nPlease bind to AD first. “; exit 1
fi
RunAsRoot()
{
## Pass in the full path to the executable as $1
if [[ "${USER}" != "root" ]] ; then
echo
echo “*** This application must be run as root. Please authenticate below. ***”
echo
sudo “${1}” && exit 0
fi
}
RunAsRoot “${0}”
printf “%b” “\a\n\nSelect a user to delete:\n” >&2
select user in $listUsers; do
if [ "$user" = "FINISHED" ]; then
echo “Finished Deleting Users…”
exit 1
fi
# Delete the user
/usr/bin/dscl . -delete “/Users/$user”
done
done
One quick question, I’m the only user on the machine, can I convert my account to a domain account while I’m logged in, or should a create a second user to do this?
Thanks
Andrew.
@Andrew
I would run this from another account.
Patrick, thanks for writing the script. It works great! but has anyone ever ask you, instead of just moving the local user home directory to the domain user home directory\LocalUserName to just replace the existing folders for the domain user home directory?
for example: after the migration is completed; The results are as followed;
DomainUser\LocalUserAccount\Desktop
DomainUser\LocalUserAccount\Documents
DomainUser\LocalUserAccount\Library
DomainUser\LocalUserAccount\Music
Instead, can we output it to replace the existing folders and files for the Domain Account? For example
DomainUser\Desktop
DomainUser\Documents
DomainUser\Library
DomainUser\Music
? Thanks!!
@Dan
I’m not sure how you got that result. The intended result is domainuser\folders.
Hi Patrick,
Thanks for getting back to me so quickly. I tried the script a few times now; and every time its finishes, the end result would just move the local account into a folder inside the domain user mobile account. i.e DomainAccount\UsersLocal\* instead of \DomainAccount\*
Do you have to create the Domain Mobile Account first, before running the script?
Thanks man!
No, I don’t create the mobile account first. The script will fail if there’s a home folder there already. I’ll look at this a bit more when I have some time.
Thanks Man! I greatly appreciate. If you don’t create the mobile account first, it will create the correct \DomainAccount\* but when you try to login with the domain account afterwards, it fails to login with the domain home directory.
And if you create the mobile account before running the script, it moves everything from your local account to \DomainAccount\LocalAccount\* where it would be awesome if it would just replace all the existing in the \DomainAccount\Folders.
Thanks again and take your time.
Would this process work with Lion as well without any modifications?
@Sampath
I don’t know, I haven’t had time to try it yet.
@Sampath and @Patrick
I can confirm this script does work on Lion 10.7.1
Since the URL to download the script was broken, I opened up terminal, typed nano, and pasted in the code, saved it as scriptname.command.
The first time I ran it, it did not work because my mac wasn’t able to login to network accounts for some reason, so when I moved it, I couldn’t login. I was able to resolve this by setting the Sharing name, hostname, and computerID in the AD directory utility to the same name, and rebound to the domain.
I did not login to the network account before running this script as well.
I tested this with Parallels 7 using a Lion virtual machine, clean install, and I restored all my data from my macbook pro to the virtual machine to simulate this properly. Upon logging into my network account, I was greeted with my same background, dock icons, and of course my files. The script ran very fast, as I think it only moves the data, does not copy it. My host OS uses an Apple SSD as well.
File links fixed, sorry about that.
@Steven. Yes, this only mv’s the data so it should be very quick.
All, I have not tested this on Lion yet as I can not get AD auth work at all in Lion. We’ve had to use local accounts on any MBA’s we buy for now.
@Patrick
Is there any way to make this script do the reverse effect? Move a network account to a local account?
Also, here is my terminal output for running this on Lion.
********* Running LocalUsertoDomainUserMigration.command Version 1.0 *********
Select a user to convert or select FINISHED:
1) intrust
2) steve
3) FINISHED
#? 2
Checking group memberships for local user steve
Please enter the network ID for this user: hanlonsm
No matching processes were found
uid=1972190779(hanlonsm) gid=2004300143(INTERNAL\Domain Users) groups=2004300143(INTERNAL\Domain Users),404(com.apple.sharepoint.group.3),745431359(INTERNAL\NAS_Users),402(com.apple.sharepoint.group.1),1272231317(INTERNAL\TS Users),403(com.apple.sharepoint.group.2),12(everyone),62(netaccounts),1345651367(INTERNAL\Service Staff),1642528183(INTERNAL\Public Folder Users),1691986051(INTERNAL\CERTSVC_DCOM_ACCESS),406(com.apple.sharepoint.group.5)
Home for hanlonsm now located at /Users/hanlonsm
Select a user to convert or select FINISHED:
1) intrust
2) steve
3) FINISHED
#?
@Steven
Yes, the script could be modified to convert network user to local. You would need to add the commands needed to create a local user.
That output looks normal, except for the “no matching processes were found” but that would be because Apple no longer has the “DirectoryService” process. I only kill that to force it to re-read it’s config.
This script works perfectly! Thank You.
Ok with Lion you just need to replace the killing of DirectoryService with the following and it should work fine.
if [ "$osvers" -gt "6" ]; then
/usr/bin/killall opendirectoryd
else
/usr/bin/killall DirectoryService
fi
I’ve also found I need to add a 20 second sleep after the killing of opendirectoryd to allow launchd to restart it properly.
Hi,
We migrated 21 computers using this script. All but four worked perfectly. One had the user folder on a different partition, didn´t check that first
That messed things up a bit, spent an hour getting it right after that. It was also a and old silver macbook (2gb ram running lion) so every step took ages to finish.
We now have issues on three computers. The rainbow wheel often appears and everything is sluggish. I have, of course run Disk permissions repair several times but the problems are still there. I have also noticed that the new AD-user doesn’t always have the correct permissions to some applications.
Are these problems unique to these computers or has anyone else gotten these issues? The main issues here are the sluggishness and rainbow wheel. If You know the cause, please respond.
P.S Nothing interesting appears in logs.
Cheers
This looks like a great script, however I had a power failure when I was at the portio0n of the script that called for which user to select. Now the network account is still the same as it was (by default) but the local user account and all of its data has disappeared. What should I do?
@Dustin.
The home folder is never deleted. Only renamed. Look in your /Users folder, you should still see a folder named after the local user. You should be able to fix it manually by running:
sudo mv /Users/localhomefolder /Users/networkuser
sudo chown -R networkuser /Users/networkuser
@Patrick
The only folder that I see is the new network account and the guest folder. I have tried to use Disk Drill to recover these files before you replied to my question. The results that came up from that utility were all temp files, I still can’t find the user’s documents, email files, etc.
Any help is greatly appreciated!
Thanks Again Patrick