Using DsAddressToSiteNamesEx in C# sample: How to get the site and subnet names from an IP Address of a machine

The DsAddressToSiteNamesEx function obtains the site and subnet names corresponding to the addresses specified.

Sample usage: How to get the site and subnet names from an IP Address of a machine

[DllImport("Netapi32.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "DsAddressToSiteNamesEx", CharSet = CharSet.Unicode)]
        private static extern int DsAddressToSiteNamesEx(
            [In] string computerName,
            [In] Int32 EntryCount,
            [In] SOCKET_ADDRESS[] SocketAddresses,
            [Out] out IntPtr SiteNames,
            [Out] out IntPtr SubnetNames);

private static extern int NetApiBufferFree([In] IntPtr buffer);

private const int ERROR_SUCCESS = 0;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct SockAddr_In
    public Int16 sin_family;
    public Int16 sin_port;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] sin_addr;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] sin_zero;

internal struct SOCKET_ADDRESS
    public IntPtr lpSockaddr;
    public Int32  iSockaddrLength;

static void Main(string[] args)
	string sIP = "";//@ip =
	string sDC = "dc-fr-001";//the name of a domain controller
	IntPtr pSiteNames;
	IntPtr pSubnetNames;
	SOCKET_ADDRESS[] SocketAddresses = new SOCKET_ADDRESS[1];

	String[] ipArray = sIP.Split('.');

	SockAddr_In sockAddr;
	sockAddr.sin_family = 2;
	sockAddr.sin_port = 0;
	sockAddr.sin_addr = new byte[4] { byte.Parse(ipArray[0]), byte.Parse(ipArray[1]), byte.Parse(ipArray[2]), byte.Parse(ipArray[3]) };
	sockAddr.sin_zero = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };

	SocketAddresses[0].iSockaddrLength = Marshal.SizeOf(sockAddr);

	IntPtr pSockAddr = Marshal.AllocHGlobal(16);
	Marshal.StructureToPtr(sockAddr, pSockAddr, true);
	SocketAddresses[0].lpSockaddr = pSockAddr;

	if (DsAddressToSiteNamesEx(
			out pSiteNames,
			out pSubnetNames) == ERROR_SUCCESS)
		string sSite = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(pSiteNames, 0));
		string sSubnet = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(pSubnetNames, 0));

		Console.WriteLine("Found site: " + sSite);
		Console.WriteLine("Found subnet: " + sSubnet);

Using DsGetSiteName in C# sample: how to get the name of the site where a computer resides?

The DsGetSiteName function returns the name of the site where a computer resides. The site in which the computer resides (as reported by a domain controller) is stored in the computer registry in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ Netlogon\Parameters.

The client IP address is used by the domain controller to retrieve the corresponding subnet that it matches in the Subnets container.
Then the name of the site is retrived from the subnet-to-site mapping.

If the client’s IP address does not match a subnet range of any of the subnets stored in Active Directory, the dclocator will randomly pick a site to use.

Sample usage to get the name of the site where a computer resides:

[DllImport("netapi32.dll", CharSet = CharSet.Auto)]
private static extern int DsGetSiteName(string ComputerName, out IntPtr SiteName);

[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int NetApiBufferFree(IntPtr dwBuffer);

private const int ERROR_SUCCESS = 0;

static void Main(string[] args)
	IntPtr pSiteInfo;
	String sSiteName;

	if (DsGetSiteName(
			out pSiteInfo) == ERROR_SUCCESS)
		sSiteName = Marshal.PtrToStringAuto(pSiteInfo);
		Console.WriteLine("Found workstaton's site Name: " + sSiteName);

You can also use a command-line interface for the same purpose:

nltest /server:<HostName> /DsGetSite

Using DsGetDcName in C# sample: How to get a Global Catalog

The directory service functions provide a utility for locating a domain controller (DC) in a Windows domain.
The DsGetDcName function (implemented by the Netlogon service) returns the name of a domain controller in a specified domain

Sample usage:

How to get a Global Catalog

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DomainControllerInfo
	public string DomainControllerName;
	public string DomainControllerAddress;
	public int DomainControllerAddressType;
	public Guid DomainGuid;
	public string DomainName;
	public string DnsForestName;
	public int Flags;
	public string DcSiteName;
	public string ClientSiteName;

private enum DSGETDCNAME_FLAGS : uint
	DS_GC_SERVER_REQUIRED = 0x00000040,
	DS_PDC_REQUIRED = 0x00000080,
	DS_BACKGROUND_ONLY = 0x00000100,
	DS_IP_REQUIRED = 0x00000200,
	DS_KDC_REQUIRED = 0x00000400,
	DS_AVOID_SELF = 0x00004000,
	DS_ONLY_LDAP_NEEDED = 0x00008000,
	DS_IS_FLAT_NAME = 0x00010000,
	DS_IS_DNS_NAME = 0x00020000,
	DS_RETURN_DNS_NAME = 0x40000000,
	DS_RETURN_FLAT_NAME = 0x80000000

[DllImport("Netapi32.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "DsGetDcNameW", CharSet = CharSet.Unicode)]
private static extern int DsGetDcName(
	[In] string computerName,
	[In] string domainName,
	[In] IntPtr domainGuid,
	[In] string siteName,
	[Out] out IntPtr domainControllerInfo);

private static extern int NetApiBufferFree(
	[In] IntPtr buffer);

private const int ERROR_SUCCESS = 0;

static void Main(string[] args)
	IntPtr pDomainInfo;
	if (DsGetDcName(
			out pDomainInfo) == ERROR_SUCCESS)
		DomainControllerInfo dci = new DomainControllerInfo();
		dci = (DomainControllerInfo)Marshal.PtrToStructure(pDomainInfo, typeof(DomainControllerInfo));
		pDomainInfo = IntPtr.Zero;
		Console.WriteLine("Found Global catalog DC: " + dci.DomainControllerName);

How to check if a user is member of a specific group with C#

The following code will find out if a specific user is member of a specific group in the Active Directory.

static void Main(string[] args)
	string group = "LDAP://cn=sales,ou=groups,ou=west,dc=contoso,dc=com";
	string member = "LDAP://cn=Jim Smith,ou=users,ou=west,dc=contoso,dc=com";

	Console.WriteLine("Determining if " + member + " is a member of the " + group + " Group...");

	using (DirectoryEntry deMember = new DirectoryEntry(member),
						  deGroup = new DirectoryEntry(group))
		bool isGroupMember = (bool)deGroup.Invoke("IsMember", new object[] { deMember.Path });
		Console.WriteLine(member + (isGroupMember ? " is" : " is not") + " a member of the " + group + " Group...");

How to determine the fsmo role holder (fsmoRoleOwner attribute)

This article describes how to find the servers that hold the Flexible Single Master Operation (FSMO) roles in a forest.

Active Directory defines five FSMO roles:

Per-forest roles, one per forest:

  • Schema master
  • Domain naming master

Per-domain roles, one per domain:

  • RID master
  • PDC master
  • Infrastructure master


To determine the master for a partition, query the fSMORoleOwner attribute on the corresponding object under the naming context root in question:

Schema Master:

Domain Naming Master:

PDC Role Owner:

Infrastructure Master:
LDAP://cn=Infrastructure, dc=concorp,dc=contoso,dc=com

RID Master:
LDAP://cn=RID Manager$,cn=System, dc=concorp,dc=contoso,dc=com

You can use tools such as ldifde to perform queries to get FSMO role holders:

ldifde -f Infrafsmo.ldf -d "CN=Infrastructure,DC=concorp,DC=contoso,DC=com" -l fSMORoleOwner

This query returns the infrastructure master role owner for the DC=concorp,DC=contoso,DC=com partition to the Infrafsmo.ldf file.

The information in the attribute is stored as a DN, representing the NTDS Settings object of the DC that is the role owner. Example:

CN=NTDS Settings,CN=DC1,CN=Servers,CN=SITE1,CN=Sites,CN=Configuration,DC=contoso,DC=com

The following c# code returns the PDC role owner:

static void Main(string[] args)
  DirectoryEntry DomDn = new DirectoryEntry("LDAP://dc=concorp,dc=contoso,dc=com");
  DirectoryEntry PDCfsmo = new DirectoryEntry("LDAP://" + DomDn.Properties["fsmoRoleOwner"].Value.ToString());

  Console.WriteLine (PDCfsmo.Parent.Properties["dnsHostName"].Value.ToString());


Same as previoulsy, the following VBscript code returns the PDC role owner:

Set objDomDn = GetObject("LDAP://dc=concorp,dc=contoso,dc=com")
strfsmoRoleOwner = objDomDn.Get("fsmoRoleOwner")

Set objPDCfsmo = GetObject("LDAP://" &  strfsmoRoleOwner)
Set objPDCfsmoParent = GetObject(objPDCfsmo.Parent)
Wscript.Echo  objPDCfsmoParent.Get("dnsHostName")

How Can I Get a List of All the Domains in a Forest

Here’s a sample C# code that searches for all the domain objects.
Because we want to search the global catalog we need to use the global catalog provider. Thus instead of specifying LDAP: in our binding string we specify GC.

static void Main(string[] args)
	DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
	String gcPath = rootDSE.Properties["rootDomainNamingContext"].Value.ToString();
	DirectoryEntry gcRoot = new DirectoryEntry("GC://" + gcPath);

	DirectorySearcher ds = new DirectorySearcher();
	ds.SearchRoot = gcRoot;
	ds.SearchScope = SearchScope.OneLevel;
	ds.PageSize = 200;
	ds.CacheResults = false;
	ds.ClientTimeout = TimeSpan.FromSeconds(60);
	ds.Filter = "(&(objectClass=domain))";

	SearchResultCollection src = ds.FindAll();
	foreach (SearchResult result in src)
		if (result.Properties.Contains("DC"))

With .NET Framework 4.5 there is a very simple way to get all domains in the forest by using the class System.DirectoryServices.ActiveDirectory.Forest

static void Main(string[] args)
	using (Forest forest = Forest.GetCurrentForest())
		Console.WriteLine("Forest:  {0}", forest.Name);
		foreach (Domain domain in forest.Domains)
			Console.WriteLine(String.Format("Domain:  {0}", domain.Name));