16

How can I get the Windows user and domain from an Active Directory DirectoryEntry (SchemaClassName="user") object?

The user name is in the sAMAccountName property but where can I look up the domain name?

(I can't assume a fixed domain name because the users are from various subdomains.)

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
laktak
  • 57,064
  • 17
  • 134
  • 164

10 Answers10

27

This assumes that results is a SearchResultCollection obtained from a DirectorySearcher, but you should be able to get the objectsid from a DirectoryEntry directly.

SearchResult result = results[0];
var propertyValues = result.Properties["objectsid"];
var objectsid = (byte[])propertyValues[0];

var sid = new SecurityIdentifier(objectsid, 0);

var account = sid.Translate(typeof(NTAccount));
account.ToString(); // This give the DOMAIN\User format for the account
Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
  • 3
    Unfortunately this doesn't work for me - I have the objectsid but I get a IdentityNotMappedException on the Translate() call. This may be because the machine that runs the code is not part of the domain, I'm just querying AD. – laktak Jun 05 '09 at 06:53
  • Is there any way to translate in reverse? If I have a string in the format DOMAIN\user, can I search for the directory object? Especially considering I could be dealing with multiple domains that are trusted, is this possible? – Jeremy Mar 16 '12 at 20:37
  • As laktak described above, this works well when you are querying it from a machine that's a member of the domain. The translate call is rejected from an untrusted machine. – Ezra Nugroho Mar 23 '16 at 00:41
7

To get the DirectoryEntry domain name you can use recursion on directoryEntry.Parent. And then if directoryEntry.SchemaClassName == "domainDNS" you can get the domain name like this:

directoryEntry.Properties["Name"].Value
sth
  • 222,467
  • 53
  • 283
  • 367
tchimev
  • 71
  • 1
  • 1
7

You won't find what you're looking for in the DirectoryEntry, unfortunately.

You have the sAMAccountName which typically is something like myuser (without the domain). You have the distinguishedName which is something like LDAP://cn=joe myuser,cn=Users,dc=yourCompany,dc=com. You also have a userPrincipalName but that's usually a name in the format of joeUser@mycompany.com.

But you won't find any attribute that has the domain\MyUser in it, unfortunately. You'll have to put that together from your information about the domain name, and the sAMAccountName of the DirectoryEntry.

For more information and some excellent Excel sheets on all the LDAP and WinNT properties in System.DirectoryServices, check out the Hilltop Lab website by ADSI MVP Richard Mueller.

Marc

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
4
public static string GetDomainNameUserNameFromUPN(string strUPN)
{

    try
    {
        WindowsIdentity wi = new WindowsIdentity(strUPN);
        WindowsPrincipal wp = new WindowsPrincipal(wi);

       return wp.Identity.Name;



    }
    catch (Exception ex)
    {

    }

    return "";
}
AdamantineWolverine
  • 2,131
  • 1
  • 17
  • 14
4

I found a partitions container in CN=Partitions,CN=Configuration that contains all domains.

When you match the user to the partion you can read the real domain name from the nETBIOSName+"\"+sAMAccountName property.

laktak
  • 57,064
  • 17
  • 134
  • 164
2

I'm extending a previous answer by @laktak to provide the details of what he meant.

There is a partitions container in CN=Partitions,CN=Configuration that contains all domains which gives you the cn which is the Netbios domain name and the nCName property that contains the distinguishedName prefix a user will have if they are in this domain.

So start by searching ldap for (objectClass=*) in CN=Partitions,CN=Configuration and store the (cn, nCName) pairs of each result to a map.

Next you query ldap using (sAMAccountName=USERIDHERE) and get the distinguishedName from the user. Now go through the (cn, nCName) pairs and find the nCName that prefixes the distinguishedName from the user, and the corresponding cn is your desired Domain name.

Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152
2

I wrote this pieces of code for my own usage (in VB.net, easy translation) :

 <System.Runtime.CompilerServices.Extension()>
Public Function GetDomainFQDN(ByVal Entry As DirectoryServices.DirectoryEntry) As String

    Try

        While Entry.SchemaClassName <> "domainDNS"
            Entry = Entry.Parent
        End While

        Dim DN As String = Entry.Properties("DistinguishedName").Value
        Return DN.Replace("DC=", "").Replace(",", ".")

    Catch ex As Exception
        Debug.WriteLine(ex.ToString)
        Return String.Empty
    End Try

End Function

<System.Runtime.CompilerServices.Extension()>
Public Function GetDomainNetbiosName(ByVal Entry As DirectoryServices.DirectoryEntry) As String

    Try

        While Entry.SchemaClassName <> "domainDNS"
            Entry = Entry.Parent
        End While

        Return Entry.Properties("Name").Value

    Catch ex As Exception
        Debug.WriteLine(ex.ToString)
        Return String.Empty
    End Try

End Function
Epervier 666
  • 97
  • 1
  • 8
2

If you are using the System.DirectoryServices libraries, you should have a SearchResultsCollection from a DirectorySearcher.

Within each SearchResult's Properties collection, there is a "distinguishedname" property. That will contain all the DC parts that make up the domain your directory entry belongs to.

joshua.ewer
  • 3,944
  • 3
  • 25
  • 35
  • +1: I've done this to get all kinds of information like who they are employed by as well as a listing of all of their security groups. – RSolberg Jun 02 '09 at 20:29
  • 6
    Yes but how does that help me? How do I get the domain name "company-central" from DC=Company,DC=com? – laktak Jun 03 '09 at 09:59
  • This is the right way to go...but remember a domain can often be an alias for the correct path in AD...e.g. in our organisation, the domain SOUTH_AMERICA is actually soa.company.com, EUROPE is eur.company.com which is represented by dc=eur,dc=company,dc=com etc so you might need a look up table and do a search in the distinguishedName string – davidsleeps Jul 01 '09 at 05:11
0

I feel obligated to add my answer which was inspired from Nicholas DiPiazza's answer here. Hope this PowerShell code helps someone!

$hash = @{} //this contains the map of CN and nCNAME
$Filter = '(nETBIOSName=*)'
$RootOU = "CN=Partitions,CN=Configuration,DC=DOMAIN,DC=LOCAL" //Change this to your org's domain
$Searcher = New-Object DirectoryServices.DirectorySearcher
$Searcher.SearchScope = "subtree"
$Searcher.Filter = $Filter
$Searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$($RootOU)")
$Searcher.FindAll()|sort | foreach { $hash[($_.Properties.ncname).Trim()] = ($_.Properties.cn).Trim() }
$hash.GetEnumerator() | sort -Property Value

If the user details are available in $userDetails, then the you can get the correct domain with this:

$hash[[regex]::Match($userDetails.DistinguishedName, 'DC=.*').Value]

and the final username would look like this:

$hash[[regex]::Match($userDetails.DistinguishedName, 'DC=.*').Value] + "\" + $userDetails.SamAccountName
Suraj
  • 468
  • 1
  • 4
  • 14
-2

1) You can get the userPrincipalName from the DirectoryEntry.

2) Then, split the UPN up between the Username and Domain Name.

3) Then call GetNetBIOSName() on it.

      public static DirectoryEntry GetDirectoryObject(string strPath)
        {
            if (strPath == "")
            {
                strPath = ConfigurationManager.AppSettings["LDAPPath"]; //YOUR DEFAULT LDAP PATH ie. LDAP://YourDomainServer
            }

            string username = ConfigurationManager.AppSettings["LDAPAccount"];
            string password = ConfigurationManager.AppSettings["LDAPPassword"];
                //You can encrypt and decrypt your password settings in web.config, but for the sake of simplicity, I've excluded the encryption code from this listing.

}
            catch (Exception ex)
            {
                HttpContext.Current.Response.Write("user: " + username + ", LDAPAccount: "+ ConfigurationManager.AppSettings["LDAPAccount"] + ".<br /> "+ ex.Message +"<br />");

                if (HttpContext.Current.User.Identity != null)
                {

                    HttpContext.Current.Response.Write("HttpContext.Current.User.Identity: " + HttpContext.Current.User.Identity.Name + ", " + HttpContext.Current.User.Identity.IsAuthenticated.ToString() + "<br />");

                    HttpContext.Current.Response.Write("Windows Identity: " + WindowsIdentity.GetCurrent().Name + ", " + HttpContext.Current.User.Identity.IsAuthenticated.ToString());


                }
                else
                {
                    HttpContext.Current.Response.Write("User.Identity is null.");
                }

                HttpContext.Current.Response.End();


            }




            DirectoryEntry oDE = new DirectoryEntry(strPath, username, password, AuthenticationTypes.Secure);
            return oDE;
        }




 public static string GetNetBIOSName(string DomainName)
 {



     string netBIOSName = "";
     DirectoryEntry rootDSE =GetDirectoryObject(
         "LDAP://"+DomainName+"/rootDSE");

     string domain = (string)rootDSE.Properties[
         "defaultNamingContext"][0];

      //   netBIOSName += "Naming Context: " + domain + "<br />";

    if (!String.IsNullOrEmpty(domain))
     {

          //This code assumes you have a directory entry at the /CN=Partitions, CN=Configuration
          //It will not work if you do not have this entry.

         DirectoryEntry parts = GetDirectoryObject(
             "LDAP://"+DomainName+"/CN=Partitions, CN=Configuration," + domain);

            foreach (DirectoryEntry part in parts.Children)
         {


             if ((string)part.Properties[
                 "nCName"][0] == domain)
             {
                 netBIOSName +=  (string)part.Properties[
                     "NetBIOSName"][0];
                 break;
             }
         }


     } 
        return netBIOSName;
 }


    public static string GetDomainUsernameFromUPN(string strUPN)
{
string DomainName;
string UserName;
  if (strUPN.Contains("@"))
        {
            string[] ud = strUPN.Split('@');
            strUPN= ud[0];
            DomainName = ud[1];

            DomainName=LDAPToolKit.GetNetBIOSName(DomainName);

            UserName= DomainName + "\\" + strUPN;
        }
        else
        {
            UserName= strUPN;
        }


    return UserName;
}
AdamantineWolverine
  • 2,131
  • 1
  • 17
  • 14