18

How can i get the domain name of the machine (if the machine is in fact joined to a domain)?

And, of course, if the machine is not joined to a domain the function should return

  • null, or
  • an empty string, or
  • the name of the machine, or
  • "."

Notes:

  • the NetGetJoinInformation Win32 function returns the legacy NetBIOS name of the domain (e.g. AVATOPIA), not the name of the domain (e.g. avatopia.local)

  • the USERDOMAIN environment variable returns the domain of the logged on user, which can be different from the machine; and also returns the legacy NetBIOS name of the domain (e.g. AVATOPIA)

  • the USERDNSDOMAIN environment variable returns the domain name of the logged on user, which can be different from the machine

Microsoft has a knowledge base article How to retrieve current user and domain names on Windows NT, Windows 2000, or Windows XP, which relies on getting the user's security token and calling LookupAccountSid.

  • the LookupAccountSid Win32 function returns the legacy NetBIOS name of the domain (e.g. AVATOPIA); and also returns the domain of the logged on user, which can be different from the machine

Update One

i've also tried using ADs object to bind to the IADs interface of the domain:

IADs domain;
ADsGetObject("LDAP://rootDES", IDs, out domain);

problem with this approach is that:

  • you cannot get the domain name (only the distinguished name)
  • it doesn't work if the user does not have permissions to query AD
  • it doesn't work if the user is not a valid user in active directory
  • it only works for Active Directory domains

Update Two:

Just to be clear what i want is:

enter image description here

Bonus Reading

Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • which language are you using to get it? – Taha Paksu Mar 20 '12 at 18:04
  • @tpaksu Native code, so you can assume C, C++, Delphi, C# with P/Invoke, assembly, etc. (which is a roundabout way of saying i'm not calling it from inside a Common Language Runtime, or a Java runtime, and don't have access to the .NET Framework class library, or the Java class library) – Ian Boyd Mar 20 '12 at 18:07
  • 2
    It's not clear to me why the references you cited are insufficient? – Mark Ransom Mar 20 '12 at 18:20
  • I realize you're wanting to do this from native code, but does `System.DirectoryServices.ActiveDirectory.Domain` in .NET return the desired information? – Cody Gray - on strike Mar 20 '12 at 19:06
  • @MarkRansom Which reference are you referring to, the one that queries the domain of the user, the one from .NET, or the one that returns the NetBIOS name? – Ian Boyd Mar 20 '12 at 19:09
  • @CodyGray Not really. That attempts to bind to LDAP to find the domain name. Problem with that it throws an exception ("Logon failure: Unknown user name or bad password") when the interactive user is not a domain account. It also throws an exception if the domain controller could not be contacted. It also throws an exception if the machine is not domain joined (which could be caught, if it were not the same exception as not able to contact the domain). i presume it also fails on an non-Active Directory domains. – Ian Boyd Mar 20 '12 at 19:32
  • Are you tried the [LsaOpenPolicy](http://msdn.microsoft.com/en-us/library/windows/desktop/aa378299%28v=vs.85%29.aspx) and [LsaQueryInformationPolicy](http://msdn.microsoft.com/en-us/library/windows/desktop/aa378313%28v=vs.85%29.aspx) functions ? for an example check this [How To Determine If a Windows NT/Windows 2000 Computer Is a Domain Member](http://support.microsoft.com/kb/179891) – RRUZ Mar 21 '12 at 01:35

3 Answers3

18

Here you go:

#include <Windows.h>
#include <DSRole.h>

#pragma comment(lib, "netapi32.lib")

#include <stdio.h>

int main(int argc, char ** argv)
{
    DSROLE_PRIMARY_DOMAIN_INFO_BASIC * info;
    DWORD dw;

    dw = DsRoleGetPrimaryDomainInformation(NULL,
                                           DsRolePrimaryDomainInfoBasic,
                                           (PBYTE *)&info);
    if (dw != ERROR_SUCCESS)
    {
        wprintf(L"DsRoleGetPrimaryDomainInformation: %u\n", dw);
        return dw;
    }

    if (info->DomainNameDns == NULL)
    {
        wprintf(L"DomainNameDns is NULL\n");
    }
    else
    {
        wprintf(L"DomainNameDns: %s\n", info->DomainNameDns);
    }

    return 0;
}

Anybody using DsRoleGetPrimaryDomainInformation in production use should consider calling DsRoleFreeMemory to free the memory block when the information is no longer needed (as per discussion in the comments).

The function returns three different domain names, e.g.:

  • Domain Forest Name: e.g. stackoverflow.com
  • Domain DNS Name: e.g. stackoverflow.com
  • Domain NetBIOS Name: e.g. STACKOVERFLOW

If the machine is not joined to a domain, then both Forest and dns are blank, with only NetBios name filled with the name of the workgroup, e.g.:

  • Domain Forest Name: null
  • Domain DNS Name: e.g. null
  • Domain NetBIOS Name: e.g. WORKGROUP

The function also returns a flag indicating if the machine is joined to a domain:

  • DsRole_RoleMemberWorkstation: workstation that is a member of a domain
  • DsRole_RoleMemberServer: server that is a member of a domain
  • DsRole_RolePrimaryDomainController: primary domain controller
  • DsRole_RoleBackupDomainController: backup domain controller

or not:

  • DsRole_RoleStandaloneWorkstation: workstation that is not a member of a domain
  • DsRole_RoleStandaloneServer: server that is not a member of a domain
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • 1
    For the record, I haven't tested this on a non-domain machine. But if it doesn't behave nicely, just use NetGetJoinInformation first to check whether you're in a domain or not. – Harry Johnston Mar 21 '12 at 03:15
  • It works on non-domain joined machines, AD domain joined machines, Windows 2000, and machines not connected to the network. i think we have a winner. i just need to figure out the difference between "dns domain name" and "forest domain name" - and which one is my domain name (http://superuser.com/questions/403447/difference-between-domain-forest-name-and-dns-name) – Ian Boyd Mar 22 '12 at 01:08
  • @wishmesh: after some consideration I decided to roll your edit back. The call to DsRoleFreeMemory is redundant in this case because the very next thing we do is exit the program, and in production code you would typically want to keep this information indefinitely, so you wouldn't call DsRoleFreeMemory then either. It's a small amount of data, after all. The only reason it's in dynamically assigned memory at all is that it's of variable length. – Harry Johnston Jul 11 '12 at 21:06
  • 1
    @harry-johnston: Thanks for your comment. It seems that DsRoleGetPrimaryDomainInformation will NOT return different information on consecutive calls. Deleted my previous comment. – Maris B. Jul 19 '12 at 16:45
  • I tried this on an AWS EC2 Windows 2012 R2 host as GetComputerNameExA( ComputerNameDnsFullyQualified, ...) was not giving me the public or private DNS. I got a NULL DomainNameDns . – osullivj Jan 14 '17 at 15:13
  • @osullivj, that's normal behaviour if the machine isn't in a domain and you haven't explicitly set a primary DNS suffix. You can check (and if necessary correct) these settings using the System control panel, aka "See the name of this computer". – Harry Johnston Jan 15 '17 at 20:55
  • @Harry Johnston; thanks, didn't know that. I'm looking for a completely automated way to discover the fully qualified DNS on an Amazon host, and I've settled on using the EC instance metadata eg http://169.254.169.254/latest/meta-data/public-hostname – osullivj Jan 17 '17 at 09:12
  • 1
    @osullivj: in the general case, you'd want to find your IP address and do a reverse DNS query. There are APIs for that, but not this one. :-) In your particular case using the Amazon-specific data is probably more sensible. – Harry Johnston Jan 17 '17 at 20:37
6

Using GetComputerNameEx you can get your computer name and domain name.

Example:

TCHAR local[100];
DWORD hstSize = sizeof(local);
GetComputerNameEx(ComputerNameDnsDomain, local, &hstSize);

Note: ComputerNameDnsDomain gives domain name and ComputerNameNetBIOS gives local workgroup(computer) name.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
Arjun babu
  • 607
  • 2
  • 13
  • 42
  • This returns the primary DNS suffix instead of the domain that the computer has joined, which can cause problems if you have a [disjoint namespace](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/disjoint-namespace). `DsRoleGetPrimaryDomainInformation` doesn't have this problem. – Shane Spoor Sep 18 '19 at 01:14
0

You can fetch the domain name via WMI in using the Win32_NTDomain class. The link contains additional links to samples on how to interact with WMI.

Bukes
  • 3,668
  • 1
  • 18
  • 20
  • The query `select * from Win32_NTDomain` seems to take about 15 seconds to return; also it doesn't work on Windows 2000. – Ian Boyd Mar 20 '12 at 19:36
  • WMI is slow and unreliable. Better use native API GetComputerNameEx() as @Sanju-Monu suggested. Also GetComputerNameEx exists in Windows 2000. – iPath ツ Mar 16 '13 at 12:22