Best practices or experience with company wide Username policies and resolving duplicates
Windows copes with this by using a GUID to identify every account. The username is just decoration. You'll find that the old jsmith and new jsmith have different GUIDs even though the usernames are the same.
Can you associate a GUID with each account in your app? If I think about it I can probably tell you how to get at the GUID for a user. It will be an attribute of the user in active directory.
JR
Yes we keep every user ever hired. I usually reccommend a first initial,middle initial,lastname to minimize the number of JQPublic1 accounts but it happens, however from an AD perspective users are just numbers. You can see the number for any account with this script:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objAccount = objWMIService.Get ("Win32_UserAccount.Name='myusername',Domain='mydomain'")
Wscript.Echo objAccount.SID
as a free bonus here's how to turn a sid into a username:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objAccount = objWMIService.Get ("Win32_SID.SID='S-1-5-21-1454471165-1004336348-1606980848-5555'")
Wscript.Echo objAccount.AccountName
Wscript.Echo objAccount.ReferencedDomainName
As others have mentioned, using the GUID attribute of the user's Active Directory account is a great idea. If you want human-readability, though, you should have a look at the docs for the iADsNameTranslate interface. You can get a lot of mileage out of it for dealing translating the various possible names of an AD account (GUID, SID, samAccountName, displayName, DN, etc).
Example:
Option Explicit
' Constants for the iADsNameTranslate object. (from http://msdn.microsoft.com/en-us/library/aa772267(VS.85).aspx)
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_GUID = 7
Const ADS_NAME_INITTYPE_GC = 3
Dim objNameTranslate
Dim strUserGUID
' Create a nametranslate object and init to talk to a global catalog server
Set objNameTranslate = CreateObject("NameTranslate")
objNameTranslate.Init ADS_NAME_INITTYPE_GC, ""
' We're looking for an "NT 4" account name type-- aka a samAccountName
objNameTranslate.Set ADS_NAME_TYPE_NT4, "DOMAIN\username"
' Translate into the user's GUID
strUserGUID = objNameTranslate.Get(ADS_NAME_TYPE_GUID)
WScript.Echo strUserGUID
This isn't just for user accounts. Every object in AD has a GUID, so if you need to "remember" a DN for, say, an LDAP search base (or a group, or anything) you can use the GUID such that if it gets moved around in AD (think about some admin going off and re-organizing OU's, or renaming groups) your "pointer" to it won't break (because the GUID never changes).
There are several naming attributes in Active Directory:
- sAMAccountName: This is the up to 20 character name that must be unique within the Domain but not within the forest.
- userPrinicipalName: This is usually in the form of [email protected] and I believe needs to be unique within the forest, but since the first part is unique within the domain, then @domain.name that should just happen.
- displayName: What you see in ADUC MMC when you look at users.
- DN: The actual LDAP DN of the user in the AD tree. This is how you would identify the user from an LDAP perspective, usually.
DN is a bad one to key off of, since it will change if the user is moved or renamed. Sane is possible for userPrincipalName/sAMAccountName (if they get renamed).
As another poster suggested, the really truly unique attribute of users is probably GUID, and is not nice and human readable, alas.
GUID is definitely the way to go. If you really need to present the person's name in a human-friendly format just do an AD lookup in code.