tags:

views:

2282

answers:

4

How do I detect whether the machine is joined to an Active Directory domain (versus in Workgroup mode)?

+4  A: 
ManagementObject cs;
        using(cs = new ManagementObject("Win32_ComputerSystem.Name='" + System.Environment.MachineName + "'" ))
        {
            cs.Get();
            Console.WriteLine("{0}",cs["domain"].ToString());
        }

That should allow you to get the domain. I believe it will be null or empty if you are part of a workgroup and not a domain.

Make sure to reference System.Management

Stephan
It returns "WORKGROUP" if not in domain. This will work (unless you're in a domain named "WORKGROUP"!), but I'll wait for a bit to see if there is a non-WMI based approach before choosing it as the right answer.
DSO
Thanks for letting me know. I only have my work machine to test on and I can't exactly remove it from the domain to test.
Stephan
On second thought I don't think this will work. It turns out that the name of the workgroup for my test box is actually WORKGROUP. I think its returning the workgroup name, not a fixed value, which from an API perspective makes more sense, but it means you can't use this to determine whether its domain joined.
DSO
+7  A: 

You can PInvoke to Win32 API's such as NetGetDcName which will return a null/empty string for a non domain-joined machine.

Even better is NetGetJoinInformation which will tell you explicitly if a machine is unjoined, in a workgroup or in a domain.


Edit: Using NetGetJoinInformation I just put together this, which worked for me:

public class Test
{
    public static bool IsInDomain()
    {
        Win32.NetJoinStatus status = Win32.NetJoinStatus.NetSetupUnknownStatus;
        IntPtr pDomain = IntPtr.Zero;
        int result = Win32.NetGetJoinInformation(null, out pDomain, out status);
        if (pDomain != IntPtr.Zero)
        {
            NetApiBufferFree(pDomain);
        }
        if (result == Win32.ErrorSuccess)
        {
            if (status == Win32.NetJoinStatus.NetSetupDomainName)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            throw new Exception("Domain Info Get Failed");
        }
    }
}
internal class Win32
{
    public const int ErrorSuccess = 0;

    [DllImport("Netapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
    public static extern int NetGetJoinInformation(string server, out IntPtr domain, out NetJoinStatus status);

    [DllImport("Netapi32.dll")]
    public static extern int NetApiBufferFree(IntPtr Buffer);

    public enum NetJoinStatus
    {
        NetSetupUnknownStatus = 0,
        NetSetupUnjoined,
        NetSetupWorkgroupName,
        NetSetupDomainName
    }

}
Rob
Cool. But isn't there a memory leak in your function, the pDomain data returned by NetGetJoinInformation?
DSO
(not that a leak matters too much... as I'll be calling this once and caching it)
DSO
Ahh - the code sample I hacked this up from in the PInvoke site was calling NetApiBufferFree - I've added that to the sample =)
Rob
A: 

The Environment variables could work for you.

Environment.UserDomainName

MSDN Link for some more details.

Environment.GetEnvironmentVariable("USERDNSDOMAIN")

I'm not sure this environment variable exists without being in a domain.

Correct me if I'm wrong Windows Admin geeks -- I believe a computer can be in several domains so it may be more important to know what domain, if any, you are in instead of it being in any domain.

Austin Salonen
As far as I'm aware a computer can only be joined to *one* domain - but you may be able to login to a PC using credentials from more than one domain in that forest, or from multiple forests if there are trusts set up. It all gets a bit too complicated there though =)
Rob
Environment.UserDomainName returns the computer name if the machine is not joined to domain. I suppose I can compare that with Environment.MachineName to determine if its domain joined, but I'm not sure if that will be correct in all situations.
DSO
@DSO - I know I'm chiming in late here but just in case someone stumbles upon this thread I just wanted to mention that even on a domain-joined machine if the user account the process is running under is a local account or system account, you can't rely on UserDomainName != MachineName.
Josh Einstein
+8  A: 

Don't fool with pinvoke if you don't have to.

Reference System.DirectoryServices.Activedirectory, then call:

System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain()

Throws an ActiveDirectoryObjectNotFoundException if the machine is not domain-joined. The Domain object that's returned contains the Name property you're looking for.

Joe Clancy
I always love to find that exists a managed version of almost anything.
SoMoS