using System; using System.Runtime.InteropServices; using System.Linq; using Vanara.InteropServices; using static Vanara.PInvoke.AdvApi32; using static Vanara.PInvoke.Ws2_32; namespace Vanara.PInvoke { public static partial class NetApi32 { /// Enumeration supporting . [PInvokeData("DsGetDC.h", MSDNShortId = "ms675912")] public enum DomainControllerAddressType { /// The address is a string IP address (for example, "\\157.55.94.74") of the domain controller. DS_INET_ADDRESS = 1, /// The address is a NetBIOS name, for example, "\\phoenix", of the domain controller. DS_NETBIOS_ADDRESS = 2 } /// Enumeration supporting . [Flags] [PInvokeData("DsGetDC.h", MSDNShortId = "ms675912")] public enum DomainControllerType : uint { /// The domain controller is PDC of Domain. DS_PDC_FLAG = 0x00000001, /// The domain controller is a GC of forest. DS_GC_FLAG = 0x00000004, /// Server supports an LDAP server. DS_LDAP_FLAG = 0x00000008, /// The domain controller supports a DS and is a Domain Controller. DS_DS_FLAG = 0x00000010, /// The domain controller is running KDC service. DS_KDC_FLAG = 0x00000020, /// The domain controller is running time service. DS_TIMESERV_FLAG = 0x00000040, /// The domain controller is in closest site to client. DS_CLOSEST_FLAG = 0x00000080, /// The domain controller has a writable DS. DS_WRITABLE_FLAG = 0x00000100, /// The domain controller is running time service (and has clock hardware). DS_GOOD_TIMESERV_FLAG = 0x00000200, /// DomainName is non-domain NC serviced by the LDAP server. DS_NDNC_FLAG = 0x00000400, /// The domain controller has some secrets. DS_SELECT_SECRET_DOMAIN_6_FLAG = 0x00000800, /// The domain controller has all secrets. DS_FULL_SECRET_DOMAIN_6_FLAG = 0x00001000, /// The domain controller is running web service. DS_WS_FLAG = 0x00002000, /// The domain controller is running Win8 or later. DS_DS_8_FLAG = 0x00004000, /// The domain controller is running Win8.1 or later. DS_DS_9_FLAG = 0x00008000, /// The domain controller is running WinThreshold or later. DS_DS_10_FLAG = 0x00010000, /// Flags returned on ping. DS_PING_FLAGS = 0x000FFFFF, /// The DomainControllerName is a DNS name. DS_DNS_CONTROLLER_FLAG = 0x20000000, /// The DomainName is a DNS name. DS_DNS_DOMAIN_FLAG = 0x40000000, /// The DnsForestName is a DNS name. DS_DNS_FOREST_FLAG = 0x80000000, } /// /// A set of flags that specify more data about the domain trust. This can be zero or a combination of one or more of the following values. /// [PInvokeData("dsgetdc.h", MSDNShortId = "cd260fd1-dc38-4405-95ba-097a23faf668")] public enum DomainTrustFlag { /// /// The domain represented by this structure is a member of the same forest as the server specified in the ServerName parameter /// of the DsEnumerateDomainTrusts function. /// DS_DOMAIN_IN_FOREST = 0x0001, /// /// The domain represented by this structure is directly trusted by the domain that the server specified in the ServerName /// parameter of the DsEnumerateDomainTrusts function is a member of. /// DS_DOMAIN_DIRECT_OUTBOUND = 0x0002, /// /// The domain represented by this structure is the root of a tree and a member of the same forest as the server specified in the /// ServerName parameter of the DsEnumerateDomainTrusts function. /// DS_DOMAIN_TREE_ROOT = 0x0004, /// /// The domain represented by this structure is the primary domain of the server specified in the ServerName parameter of the /// DsEnumerateDomainTrusts function. /// DS_DOMAIN_PRIMARY = 0x0008, /// The domain represented by this structure is running in the Windows 2000 native mode. DS_DOMAIN_NATIVE_MODE = 0x0010, /// /// The domain represented by this structure directly trusts the domain that the server specified in the ServerName parameter of /// the DsEnumerateDomainTrusts function is a member of. /// DS_DOMAIN_DIRECT_INBOUND = 0x0020, } /// Flags supporting behavior of . [Flags] [PInvokeData("DsGetDC.h", MSDNShortId = "ms675983")] public enum DsGetDcNameFlags : uint { /// /// Forces cached domain controller data to be ignored. When the DS_FORCE_REDISCOVERY flag is not specified, DsGetDcName may /// return cached domain controller data. If this flag is specified, DsGetDcName will not use cached information (if any exists) /// but will instead perform a fresh domain controller discovery. /// /// This flag should not be used under normal conditions, as using the cached domain controller information has better /// performance characteristics and helps to ensure that the same domain controller is used consistently by all applications. /// This flag should be used only after the application determines that the domain controller returned by DsGetDcName (when /// called without this flag) is not accessible. In that case, the application should repeat the DsGetDcName call with this flag /// to ensure that the unuseful cached information (if any) is ignored and a reachable domain controller is discovered. /// /// DS_FORCE_REDISCOVERY = 0x1, /// Requires that the returned domain controller support directory services. DS_DIRECTORY_SERVICE_REQUIRED = 0x10, /// /// DsGetDcName attempts to find a domain controller that supports directory service functions. If a domain controller that /// supports directory services is not available, DsGetDcName returns the name of a non-directory service domain controller. /// However, DsGetDcName only returns a non-directory service domain controller after the attempt to find a directory service /// domain controller times out. /// DS_DIRECTORY_SERVICE_PREFERRED = 0x20, /// /// Requires that the returned domain controller be a global catalog server for the forest of domains with this domain as the /// root. If this flag is set and the DomainName parameter is not NULL, DomainName must specify a forest name. This flag cannot /// be combined with the DS_PDC_REQUIRED or DS_KDC_REQUIRED flags. /// DS_GC_SERVER_REQUIRED = 0x40, /// /// Requires that the returned domain controller be the primary domain controller for the domain. This flag cannot be combined /// with the DS_KDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// DS_PDC_REQUIRED = 0x80, /// /// If the DS_FORCE_REDISCOVERY flag is not specified, this function uses cached domain controller data. If the cached data is /// more than 15 minutes old, the cache is refreshed by pinging the domain controller. If this flag is specified, this refresh is /// avoided even if the cached data is expired. This flag should be used if the DsGetDcName function is called periodically. /// DS_BACKGROUND_ONLY = 0x100, /// /// This parameter indicates that the domain controller must have an IP address. In that case, DsGetDcName will place the /// Internet protocol address of the domain controller in the DomainControllerAddress member of DomainControllerInfo. /// DS_IP_REQUIRED = 0x200, /// /// Requires that the returned domain controller be currently running the Kerberos Key Distribution Center service. This flag /// cannot be combined with the DS_PDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// DS_KDC_REQUIRED = 0x400, /// Requires that the returned domain controller be currently running the Windows Time Service. DS_TIMESERV_REQUIRED = 0x800, /// Requires that the returned domain controller be writable; that is, host a writable copy of the directory service. DS_WRITABLE_REQUIRED = 0x1000, /// /// DsGetDcName attempts to find a domain controller that is a reliable time server. The Windows Time Service can be configured /// to declare one or more domain controllers as a reliable time server. For more information, see the Windows Time Service /// documentation. This flag is intended to be used only by the Windows Time Service. /// DS_GOOD_TIMESERV_PREFERRED = 0x2000, /// /// When called from a domain controller, specifies that the returned domain controller name should not be the current computer. /// If the current computer is not a domain controller, this flag is ignored. This flag can be used to obtain the name of another /// domain controller in the domain. /// DS_AVOID_SELF = 0x4000, /// /// Specifies that the server returned is an LDAP server. The server returned is not necessarily a domain controller. No other /// services are implied to be present at the server. The server returned does not necessarily have a writable config container /// nor a writable schema container. The server returned may not necessarily be used to create or modify security principles. /// This flag may be used with the DS_GC_SERVER_REQUIRED flag to return an LDAP server that also hosts a global catalog server. /// The returned global catalog server is not necessarily a domain controller. No other services are implied to be present at the /// server. If this flag is specified, the DS_PDC_REQUIRED, DS_TIMESERV_REQUIRED, DS_GOOD_TIMESERV_PREFERRED, /// DS_DIRECTORY_SERVICES_PREFERED, DS_DIRECTORY_SERVICES_REQUIRED, and DS_KDC_REQUIRED flags are ignored. /// DS_ONLY_LDAP_NEEDED = 0x8000, /// /// Specifies that the DomainName parameter is a flat name. This flag cannot be combined with the DS_IS_DNS_NAME flag. /// DS_IS_FLAT_NAME = 0x10000, /// /// Specifies that the DomainName parameter is a DNS name. This flag cannot be combined with the DS_IS_FLAT_NAME flag. /// /// Specify either DS_IS_DNS_NAME or DS_IS_FLAT_NAME. If neither flag is specified, DsGetDcName may take longer to find a domain /// controller because it may have to search for both the DNS-style and flat name. /// /// DS_IS_DNS_NAME = 0x20000, /// /// When this flag is specified, DsGetDcName attempts to find a domain controller in the same site as the caller. If no such /// domain controller is found, it will find a domain controller that can provide topology information and call DsBindToISTG to /// obtain a bind handle, then call DsQuerySitesByCost over UDP to determine the "next closest site," and finally cache the name /// of the site found. If no domain controller is found in that site, then DsGetDcName falls back on the default method of /// locating a domain controller. /// /// If this flag is used in conjunction with a non-NULL value in the input parameter SiteName, then ERROR_INVALID_FLAGS is thrown. /// /// /// Also, the kind of search employed with DS_TRY_NEXT_CLOSEST_SITE is site-specific, so this flag is ignored if it is used in /// conjunction with DS_PDC_REQUIRED. Finally, DS_TRY_NEXTCLOSEST_SITE is ignored when used in conjunction with /// DS_RETURN_FLAT_NAME because that uses NetBIOS to resolve the name, but the domain of the domain controller found won't /// necessarily match the domain to which the client is joined. /// /// Note This flag is Group Policy enabled. If you enable the "Next Closest Site" policy setting, Next Closest Site DC /// Location will be turned on for the machine across all available but un-configured network adapters. If you disable the policy /// setting, Next Closest Site DC Location will not be used by default for the machine across all available but un-configured /// network adapters. However, if a DC Locator call is made using the DS_TRY_NEXTCLOSEST_SITE flag explicitly, DsGetDcName honors /// the Next Closest Site behavior. If you do not configure this policy setting, Next Closest Site DC Location will be not be /// used by default for the machine across all available but un-configured network adapters. If the DS_TRY_NEXTCLOSEST_SITE flag /// is used explicitly, the Next Closest Site behavior will be used. /// DS_TRY_NEXTCLOSEST_SITE = 0x40000, /// Requires that the returned domain controller be running Windows Server 2008 or later. DS_DIRECTORY_SERVICE_6_REQUIRED = 0x80000, /// Requires that the returned domain controller be currently running the Active Directory web service. DS_WEB_SERVICE_REQUIRED = 0x100000, /// Requires that the returned domain controller be running Windows Server 2012 or later. DS_DIRECTORY_SERVICE_8_REQUIRED = 0x200000, /// Requires that the returned domain controller be running Windows Server 2012 R2 or later. DS_DIRECTORY_SERVICE_9_REQUIRED = 0x400000, /// Requires that the returned domain controller be running Windows Server 2016 or later. DS_DIRECTORY_SERVICE_10_REQUIRED = 0x800000, /// /// Specifies that the names returned in the DomainControllerName and DomainName members of DomainControllerInfo should be DNS /// names. If a DNS name is not available, an error is returned. This flag cannot be specified with the DS_RETURN_FLAT_NAME flag. /// This flag implies the DS_IP_REQUIRED flag. /// DS_RETURN_DNS_NAME = 0x40000000, /// /// Specifies that the names returned in the DomainControllerName and DomainName members of DomainControllerInfo should be flat /// names. If a flat name is not available, an error is returned. This flag cannot be specified with the DS_RETURN_DNS_NAME flag. /// DS_RETURN_FLAT_NAME = 0x80000000, } /// Flags used by DsGetDcOpen. [PInvokeData("dsgetdc.h", MSDNShortId = "2811cc30-f367-4f1a-8f0c-ed0a77dad24c")] [Flags] public enum DsGetDcOpenOptions { /// Only site-specific domain controllers are enumerated. DS_ONLY_DO_SITE_NAME = 0x01, /// /// The DsGetDcNext function will return the ERROR_FILEMARK_DETECTED value after all of the site-specific domain controllers are /// retrieved. DsGetDcNext will then enumerate the second group, which contains all domain controllers in the domain, including /// the site-specific domain controllers contained in the first group. /// DS_NOTIFY_AFTER_SITE_RECORDS = 0x02, } /// Flags used by DsGetForestTrustInformationW. [PInvokeData("dsgetdc.h", MSDNShortId = "c94fdc5b-920b-4807-9cbf-3172ec1c7386")] [Flags] public enum DsGetForestTrustInformationFlags { /// /// If this flag is set, DsGetForestTrustInformationW will update the forest trust data of the trusted domain identified by the /// TrustedDomainNameparameter. In this case, the TrustedDomainName parameter cannot be NULL. The caller must have access to /// modify the trust data or ERROR_ACCESS_DENIED is returned. /// This flag is only valid if ServerName specifies the primary domain controller of the domain. /// DS_GFTI_UPDATE_TDO = 1 } /// The DsAddressToSiteNames function obtains the site names corresponding to the specified addresses. /// /// Pointer to a null-terminated string that specifies the name of the remote server to process this function. This parameter must be /// the name of a domain controller. A non-domain controller can call this function by calling DsGetDcName to find the domain controller. /// /// Contains the number of elements in the SocketAddresses array. /// /// Contains an array of SOCKET_ADDRESS structures that contain the addresses to convert. Each address in this array must be of the /// type AF_INET. EntryCount contains the number of elements in this array. /// /// /// Receives an array of null-terminated string pointers that contain the site names for the addresses. Each element in this array /// corresponds to the same element in the SocketAddresses array. An element is NULL if the corresponding address does not map /// to any known site or if the address entry is not of the proper form. The caller must free this array when it is no longer /// required by calling NetApiBufferFree. /// /// /// Returns NO_ERROR if successful or a Win32 or RPC error otherwise. The following list lists possible error codes. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsaddresstositenamesa DSGETDCAPI DWORD // DsAddressToSiteNamesA( IN LPCSTR ComputerName, IN DWORD EntryCount, IN PSOCKET_ADDRESS SocketAddresses, OUT LPSTR **SiteNames ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "4d70dbee-be33-4d2a-a200-3696443fa853")] public static extern Win32Error DsAddressToSiteNames(string ComputerName, uint EntryCount, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] SOCKET_ADDRESS[] SocketAddresses, out SafeNetApiBuffer SiteNames); /// The DsAddressToSiteNamesEx function obtains the site and subnet names corresponding to the addresses specified. /// /// Pointer to a null-terminated string that specifies the name of the remote server to process this function. This parameter must be /// the name of a domain controller. A non-domain controller can call this function by calling DsGetDcName to find the domain controller. /// /// Contains the number of elements in the SocketAddresses array. /// /// Contains an array of SOCKET_ADDRESS structures that contain the addresses to convert. Each address in this array must be of the /// type AF_INET. EntryCount contains the number of elements in this array. /// /// /// Receives an array of null-terminated string pointers that contain the site names for the addresses. Each element in this array /// corresponds to the same element in the SocketAddresses array. An element is NULL if the corresponding address does not map /// to any known site or if the address entry is not of the proper form. The caller must free this array when it is no longer /// required by calling NetApiBufferFree. /// /// /// Receives an array of null-terminated string pointers that contain the subnet names used to perform the address to site name /// mappings. Each element in this array corresponds to the same element in the SocketAddresses array. An element is NULL if /// the corresponding address to site name mapping was not determined or if no subnet was used to perform the corresponding address /// to site mapping. The latter will be the case when there is exactly one site in the enterprise with no subnet objects mapped to /// it. The caller must free this array when it is no longer required by calling NetApiBufferFree. /// /// Returns NO_ERROR if successful or a Win32 or RPC error otherwise. The following are possible error codes. // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsaddresstositenamesexw // DSGETDCAPI DWORD DsAddressToSiteNamesExW( IN LPCWSTR ComputerName, IN DWORD EntryCount, IN PSOCKET_ADDRESS SocketAddresses, OUT LPWSTR **SiteNames, OUT LPWSTR **SubnetNames ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "60ac6195-6e43-46da-a1e6-74ec989cd0c4")] public static extern Win32Error DsAddressToSiteNamesEx(string ComputerName, uint EntryCount, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] SOCKET_ADDRESS[] SocketAddresses, out SafeNetApiBuffer SiteNames, out SafeNetApiBuffer SubnetNames); /// /// /// The DsDeregisterDnsHostRecords function deletes DNS entries, except for type A records registered by a domain controller. /// Only an administrator, account operator, or server operator may call this function. /// /// /// /// /// The null-terminated string that specifies the name of the remote domain controller. Can be set to NULL if the calling /// application is running on the domain controller being updated. /// /// /// /// /// The null-terminated string that specifies the DNS domain name of the domain occupied by the domain controller. It is unnecessary /// for this to be a domain hosted by this domain controller. If NULL, the DnsHostName with the leftmost label removed is specified. /// /// /// /// Pointer to the Domain GUID of the domain. If NULL, GUID specific names are not removed. /// /// /// /// Pointer to the GUID of the NTDS-DSA object to be deleted. If NULL, NTDS-DSA specific names are not removed. /// /// /// /// /// Pointer to the null-terminated string that specifies the DNS host name of the domain controller whose DNS records are being deleted. /// /// /// /// This function returns DSGETDCAPI DWORD. /// /// /// /// This function deregisters SRV and CNAME records only. It leaves type A records intact. Deletion of site specific records, for /// example, _ldap.tcp.<SiteName>._sites.dc._msdcs.<DnsDomainName>, is attempted for every site (<SiteName> in this /// example) in the enterprise of the domain controller on which the function is executed. Therefore, this function call could create /// a time-consuming run and may generate significant network traffic for enterprises with many sites. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsderegisterdnshostrecordsa DSGETDCAPI DWORD // DsDeregisterDnsHostRecordsA( LPSTR ServerName, LPSTR DnsDomainName, GUID *DomainGuid, GUID *DsaGuid, LPSTR DnsHostName ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "18ab6455-dab2-42d9-b68e-a8f0ad2d8091")] public static extern Win32Error DsDeregisterDnsHostRecords([Optional] string ServerName, string DnsDomainName, in Guid DomainGuid, in Guid DsaGuid, string DnsHostName); /// /// /// The DsDeregisterDnsHostRecords function deletes DNS entries, except for type A records registered by a domain controller. /// Only an administrator, account operator, or server operator may call this function. /// /// /// /// /// The null-terminated string that specifies the name of the remote domain controller. Can be set to NULL if the calling /// application is running on the domain controller being updated. /// /// /// /// /// The null-terminated string that specifies the DNS domain name of the domain occupied by the domain controller. It is unnecessary /// for this to be a domain hosted by this domain controller. If NULL, the DnsHostName with the leftmost label removed is specified. /// /// /// /// Pointer to the Domain GUID of the domain. If NULL, GUID specific names are not removed. /// /// /// /// Pointer to the GUID of the NTDS-DSA object to be deleted. If NULL, NTDS-DSA specific names are not removed. /// /// /// /// /// Pointer to the null-terminated string that specifies the DNS host name of the domain controller whose DNS records are being deleted. /// /// /// /// This function returns DSGETDCAPI DWORD. /// /// /// /// This function deregisters SRV and CNAME records only. It leaves type A records intact. Deletion of site specific records, for /// example, _ldap.tcp.<SiteName>._sites.dc._msdcs.<DnsDomainName>, is attempted for every site (<SiteName> in this /// example) in the enterprise of the domain controller on which the function is executed. Therefore, this function call could create /// a time-consuming run and may generate significant network traffic for enterprises with many sites. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsderegisterdnshostrecordsa DSGETDCAPI DWORD // DsDeregisterDnsHostRecordsA( LPSTR ServerName, LPSTR DnsDomainName, GUID *DomainGuid, GUID *DsaGuid, LPSTR DnsHostName ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "18ab6455-dab2-42d9-b68e-a8f0ad2d8091")] public static extern Win32Error DsDeregisterDnsHostRecords([Optional] string ServerName, string DnsDomainName, IntPtr DomainGuid, IntPtr DsaGuid, string DnsHostName); /// The DsEnumerateDomainTrusts function obtains domain trust data for a specified domain. /// /// Pointer to a null-terminated string that specifies the name of a computer in the domain to obtain the trust information for. If /// this parameter is NULL, the name of the local computer is used. The caller must be an authenticated user in this domain. /// /// /// If this computer is a domain controller, this function returns the trust data immediately. If this computer is not a domain /// controller, this function obtains the trust data from cached data if the cached data is not expired. If the cached data is /// expired, this function obtains the trust data from a domain controller in the domain that this computer is a member of and /// updates the cache. The cached data automatically expires after five minutes. /// /// /// Contains a set of flags that determines which domain trusts to enumerate. This can be zero or a combination of one or more of the /// following values. /// /// DS_DOMAIN_DIRECT_INBOUND /// Enumerate domains that directly trust the domain which has ServerName as a member. /// DS_DOMAIN_DIRECT_OUTBOUND /// Enumerate domains directly trusted by the domain which has ServerName as a member. /// DS_DOMAIN_IN_FOREST /// Enumerate domains that are a member of the same forest which has ServerName as a member. /// DS_DOMAIN_NATIVE_MODE /// Enumerate domains where the primary domain is running in Windows 2000 native mode. /// DS_DOMAIN_PRIMARY /// Enumerate domains that are the primary domain of the domain which has ServerName as a member. /// DS_DOMAIN_TREE_ROOT /// Enumerate domains that are at the root of the forest which has ServerName as a member. /// Pointer to a PDS_DOMAIN_TRUSTS value that receives an array of DS_DOMAIN_TRUSTS structures. Each structure in this array /// contains trust data about a domain. The caller must free this memory when it is no longer required by calling NetApiBufferFree. /// Pointer to a ULONG value that receives the number of elements returned in the Domains array. /// /// Returns ERROR_SUCCESS if successful or a Win32 error code otherwise. Possible error codes include those listed in the /// following list. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsenumeratedomaintrustsa DSGETDCAPI DWORD // DsEnumerateDomainTrustsA( LPSTR ServerName, ULONG Flags, PDS_DOMAIN_TRUSTSA *Domains, PULONG DomainCount ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "6c3b788f-ee53-4637-acdb-04316e8464fe")] public static extern Win32Error DsEnumerateDomainTrusts([Optional] string ServerName, [Optional] DomainTrustFlag Flags, out SafeNetApiBuffer Domains, out uint DomainCount); /// /// The DsGetDcClose function closes a domain controller enumeration operation. /// /// /// Contains the domain controller enumeration context handle provided by the DsGetDcOpen function. /// /// /// This function does not return a value. /// /// /// When this function is called, GetDcContextHandle is invalid and cannot be used. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetdcclosew DSGETDCAPI VOID DsGetDcCloseW( IN HANDLE // GetDcContextHandle ); [DllImport(Lib.NetApi32, SetLastError = false, EntryPoint = "DsGetDcCloseW")] [PInvokeData("dsgetdc.h", MSDNShortId = "d193e4cd-ad66-4d93-b912-348f17e93a6f")] public static extern void DsGetDcClose(HANDLE GetDcContextHandle); /// /// The DsGetDcName function returns the name of a domain controller in a specified domain. This function accepts additional /// domain controller selection criteria to indicate preference for a domain controller with particular characteristics. /// /// /// Pointer to a null-terminated string that specifies the name of the server to process this function. Typically, this parameter is /// NULL, which indicates that the local computer is used. /// /// /// /// Pointer to a null-terminated string that specifies the name of the domain or application partition to query. This name can either /// be a DNS style name, for example, fabrikam.com, or a flat-style name, for example, Fabrikam. If a DNS style name is specified, /// the name may be specified with or without a trailing period. /// /// /// If the Flags parameter contains the DS_GC_SERVER_REQUIRED flag, DomainName must be the name of the forest. In this case, /// DsGetDcName fails if DomainName specifies a name that is not the forest root. /// /// /// If the Flags parameter contains the DS_GC_SERVER_REQUIRED flag and DomainName is NULL, DsGetDcName attempts /// to find a global catalog in the forest of the computer identified by ComputerName, which is the local computer if ComputerName is NULL. /// /// /// If DomainName is NULL and the Flags parameter does not contain the DS_GC_SERVER_REQUIRED flag, ComputerName is set /// to the default domain name of the primary domain of the computer identified by ComputerName. /// /// /// /// Pointer to a GUID structure that specifies the GUID of the domain queried. If DomainGuid is not NULL and the domain /// specified by DomainName or ComputerName cannot be found, DsGetDcName attempts to locate a domain controller in the domain /// having the GUID specified by DomainGuid. /// /// /// Pointer to a null-terminated string that specifies the name of the site where the returned domain controller should physically /// exist. If this parameter is NULL, DsGetDcName attempts to return a domain controller in the site closest to the /// site of the computer specified by ComputerName. This parameter should be NULL, by default. /// /// /// /// Contains a set of flags that provide additional data used to process the request. This parameter can be a combination of the /// following values. /// /// DS_AVOID_SELF /// /// When called from a domain controller, specifies that the returned domain controller name should not be the current computer. If /// the current computer is not a domain controller, this flag is ignored. This flag can be used to obtain the name of another domain /// controller in the domain. /// /// DS_BACKGROUND_ONLY /// /// If the DS_FORCE_REDISCOVERY flag is not specified, this function uses cached domain controller data. If the cached data is /// more than 15 minutes old, the cache is refreshed by pinging the domain controller. If this flag is specified, this refresh is /// avoided even if the cached data is expired. This flag should be used if the DsGetDcName function is called periodically. /// /// DS_DIRECTORY_SERVICE_PREFERRED /// /// DsGetDcName attempts to find a domain controller that supports directory service functions. If a domain controller that /// supports directory services is not available, DsGetDcName returns the name of a non-directory service domain controller. /// However, DsGetDcName only returns a non-directory service domain controller after the attempt to find a directory service /// domain controller times out. /// /// DS_DIRECTORY_SERVICE_REQUIRED /// Requires that the returned domain controller support directory services. /// DS_DIRECTORY_SERVICE_6_REQUIRED /// Requires that the returned domain controller be running Windows Server 2008 or later. /// DS_DIRECTORY_SERVICE_8_REQUIRED /// Requires that the returned domain controller be running Windows Server 2012 or later. /// DS_FORCE_REDISCOVERY /// /// Forces cached domain controller data to be ignored. When the DS_FORCE_REDISCOVERY flag is not specified, /// DsGetDcName may return cached domain controller data. If this flag is specified, DsGetDcName will not use cached /// information (if any exists) but will instead perform a fresh domain controller discovery. /// /// /// This flag should not be used under normal conditions, as using the cached domain controller information has better performance /// characteristics and helps to ensure that the same domain controller is used consistently by all applications. This flag should be /// used only after the application determines that the domain controller returned by DsGetDcName (when called without this /// flag) is not accessible. In that case, the application should repeat the DsGetDcName call with this flag to ensure that /// the unuseful cached information (if any) is ignored and a reachable domain controller is discovered. /// /// DS_GC_SERVER_REQUIRED /// /// Requires that the returned domain controller be a global catalog server for the forest of domains with this domain as the root. /// If this flag is set and the DomainName parameter is not NULL, DomainName must specify a forest name. This flag cannot be /// combined with the DS_PDC_REQUIRED or DS_KDC_REQUIRED flags. /// /// DS_GOOD_TIMESERV_PREFERRED /// /// DsGetDcName attempts to find a domain controller that is a reliable time server. The Windows Time Service can be /// configured to declare one or more domain controllers as a reliable time server. For more information, see the Windows Time /// Service documentation. This flag is intended to be used only by the Windows Time Service. /// /// DS_IP_REQUIRED /// /// This parameter indicates that the domain controller must have an IP address. In that case, DsGetDcName will place the /// Internet protocol address of the domain controller in the DomainControllerAddress member of DomainControllerInfo. /// /// DS_IS_DNS_NAME /// Specifies that the DomainName parameter is a DNS name. This flag cannot be combined with the DS_IS_FLAT_NAME flag. /// /// Specify either DS_IS_DNS_NAME or DS_IS_FLAT_NAME. If neither flag is specified, DsGetDcName may take longer /// to find a domain controller because it may have to search for both the DNS-style and flat name. /// /// DS_IS_FLAT_NAME /// Specifies that the DomainName parameter is a flat name. This flag cannot be combined with the DS_IS_DNS_NAME flag. /// DS_KDC_REQUIRED /// /// Requires that the returned domain controller be currently running the Kerberos Key Distribution Center service. This flag cannot /// be combined with the DS_PDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// /// DS_ONLY_LDAP_NEEDED /// /// Specifies that the server returned is an LDAP server. The server returned is not necessarily a domain controller. No other /// services are implied to be present at the server. The server returned does not necessarily have a writable config /// container nor a writable schema container. The server returned may not necessarily be used to create or modify security /// principles. This flag may be used with the DS_GC_SERVER_REQUIRED flag to return an LDAP server that also hosts a global /// catalog server. The returned global catalog server is not necessarily a domain controller. No other services are implied to be /// present at the server. If this flag is specified, the DS_PDC_REQUIRED, DS_TIMESERV_REQUIRED, /// DS_GOOD_TIMESERV_PREFERRED, DS_DIRECTORY_SERVICES_PREFERED, DS_DIRECTORY_SERVICES_REQUIRED, and /// DS_KDC_REQUIRED flags are ignored. /// /// DS_PDC_REQUIRED /// /// Requires that the returned domain controller be the primary domain controller for the domain. This flag cannot be combined with /// the DS_KDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// /// DS_RETURN_DNS_NAME /// /// Specifies that the names returned in the DomainControllerName and DomainName members of DomainControllerInfo should /// be DNS names. If a DNS name is not available, an error is returned. This flag cannot be specified with the /// DS_RETURN_FLAT_NAME flag. This flag implies the DS_IP_REQUIRED flag. /// /// DS_RETURN_FLAT_NAME /// /// Specifies that the names returned in the DomainControllerName and DomainName members of DomainControllerInfo should /// be flat names. If a flat name is not available, an error is returned. This flag cannot be specified with the /// DS_RETURN_DNS_NAME flag. /// /// DS_TIMESERV_REQUIRED /// Requires that the returned domain controller be currently running the Windows Time Service. /// DS_TRY_NEXTCLOSEST_SITE /// /// When this flag is specified, DsGetDcName attempts to find a domain controller in the same site as the caller. If no such /// domain controller is found, it will find a domain controller that can provide topology information and call DsBindToISTG to /// obtain a bind handle, then call DsQuerySitesByCost over UDP to determine the "next closest site," and finally cache the name of /// the site found. If no domain controller is found in that site, then DsGetDcName falls back on the default method of /// locating a domain controller. /// /// /// If this flag is used in conjunction with a non-NULL value in the input parameter SiteName, then ERROR_INVALID_FLAGS is thrown. /// /// /// Also, the kind of search employed with DS_TRY_NEXT_CLOSEST_SITE is site-specific, so this flag is ignored if it is used in /// conjunction with DS_PDC_REQUIRED. Finally, DS_TRY_NEXTCLOSEST_SITE is ignored when used in conjunction with /// DS_RETURN_FLAT_NAME because that uses NetBIOS to resolve the name, but the domain of the domain controller found won't /// necessarily match the domain to which the client is joined. /// /// /// Note This flag is Group Policy enabled. If you enable the "Next Closest Site" policy setting, Next Closest Site DC /// Location will be turned on for the machine across all available but un-configured network adapters. If you disable the policy /// setting, Next Closest Site DC Location will not be used by default for the machine across all available but un-configured network /// adapters. However, if a DC Locator call is made using the DS_TRY_NEXTCLOSEST_SITE flag explicitly, DsGetDcName /// honors the Next Closest Site behavior. If you do not configure this policy setting, Next Closest Site DC Location will be not be /// used by default for the machine across all available but un-configured network adapters. If the DS_TRY_NEXTCLOSEST_SITE /// flag is used explicitly, the Next Closest Site behavior will be used. /// /// DS_WRITABLE_REQUIRED /// Requires that the returned domain controller be writable; that is, host a writable copy of the directory service. /// DS_WEB_SERVICE_REQUIRED /// Requires that the returned domain controller be currently running the Active Directory web service. /// /// /// Pointer to a PDOMAIN_CONTROLLER_INFO value that receives a pointer to a DOMAIN_CONTROLLER_INFO structure that contains /// data about the domain controller selected. This structure is allocated by DsGetDcName. The caller must free the structure /// using the NetApiBufferFree function when it is no longer required. /// /// /// If the function returns domain controller data, the return value is ERROR_SUCCESS. /// If the function fails, the return value can be one of the following error codes. /// /// /// /// The DsGetDcName function is sent to the Netlogon service on the remote computer specified by ComputerName. If ComputerName /// is NULL, the function is processed on the local computer. /// /// /// DsGetDcName does not verify that the domain controller name returned is the name of an actual domain controller or global /// catalog. If mutual authentication is required, the caller must perform the authentication. /// /// /// DsGetDcName does not require any particular access to the specified domain. By default, this function does not ensure that /// the returned domain controller is currently available. Instead, the caller should attempt to use the returned domain controller. /// If the domain controller is not available, the caller should call the DsGetDcName function again, specifying the /// DS_FORCE_REDISCOVERY flag. /// /// Response Time /// When using DsGetDcName be aware of the following timing details: /// /// /// /// DsGetDcName makes network calls and can take from a few seconds up to one minute, depending on network traffic, topology, /// DC load, and so on. /// /// /// /// It is NOT recommended to call DsGetDcName from a UI or other timing critical thread. /// /// /// /// The DC Locator does use optimized logic to provide the DC information as quickly as possible. It also uses cached information at /// the site to contact the closest DC. /// /// /// /// Notes on Domain Controller Stickiness /// /// In Active Directory Domain Services, the domain controller locator function is designed so that once a client finds a preferred /// domain controller, the client will not look for another unless that domain controller stops responding or the client is /// restarted. This is referred to as "Domain Controller Stickiness." Because workstations typically operate for months without a /// problem or restart, one unintended consequence of this behavior is that if a particular domain controller goes down for /// maintenance, all of the clients that were connected to it shift their connections to another domain controller. But when the /// domain controller comes back up, no clients ever reconnect to it because the clients do not restart very often. This can cause /// load-balancing problems. /// /// /// Previously, the most common solution to this problem was to deploy a script on each client machine that periodically called /// DsGetDcName using the flag. This was a somewhat cumbersome solution, so Windows Server 2008 and Windows Vista introduced a /// new mechanism that caused issues with domain controller stickiness. /// /// /// Whenever DsGetDcName retrieves a domain controller name from its cache, it checks to see if this cached entry is expired, /// and if so, discards that domain controller name and tries to rediscover a domain controller name. The life span of a cached entry /// is controlled by the value in the following registry keys /// /// HKEY_LOCAL_MACHINE<b>SYSTEM<b>CurrentControlSet<b>Services<b>Netlogon<b>Parameters<b>ForceRediscoveryInterval /// and /// HKEY_LOCAL_MACHINE<b>Software<b>Policies<b>Microsoft<b>Netlogon<b>Parameters<b>ForceRediscoveryInterval /// /// The values in these registry keys are of type REG_DWORD. They specify the length in seconds before DsGetDcName /// should try to rediscover the domain controller name. The default value is 43200 seconds (12 hours). If the value of the /// ForceRediscoveryInterval registry entry is set to 0, the client always performs rediscovery. If the value is set to /// 4294967295, the cache never expires, and the cached domain controller continues to be used. We recommend that you do not set the /// ForceRediscoveryInterval registry entry to a value that is less than 3600 seconds (60 minutes). /// /// /// Note The registry settings of ForceRediscoveryInterval are group policy enabled. If you disable the policy setting, /// Force Rediscovery will used by default for the machine at every 12 hour interval. If you do not configure this policy setting, /// Force Rediscovery will used by default for the machine at every 12 hour interval, unless the local machine setting in the /// registry is a different value. /// /// /// Note that if the DS_BACKGROUND_ONLY flag is specified, DsGetDcName will never try to rediscover the domain /// controller name, since the point of that flag is to force DsGetDcName to use the cached domain controller name even if it /// is expired. /// /// ETW Tracing in DsGetDcName /// To turn on ETW Tracing for DsGetDcName, create the following registry key: /// HKEY_LOCAL_MACHINE<b>System<b>CurrentControlSet<b>Services<b>DCLocator<b>Tracing /// The key will have a structure as follows: /// /// ProcessName must be the full name including extension of the process that you want to get trace information for. PID is only /// required when multiple processes with the same name exist. If it is defined, then only the process with that PID will be enabled /// for tracing. It is not possible to trace only 2 out of 3 (or more) processes with the same name. You can enable one instance or /// all instances (when multiple instances with the same process name exist and PID is not specified, all instances will be enabled /// for tracing). /// /// /// For example, this would trace all instances of App1.exe and App2.exe, but only the instance of App3.exe that has a PID of 999: /// /// Run the following command to start the tracing session: /// tracelog.exe -start <sessionname> -guid #cfaa5446-c6c4-4f5c-866f-31c9b55b962d -f <filename> -flag <traceFlags> /// /// sessionname is the name given for the trace session. The guid for the DCLocator tracing provider is /// "cfaa5446-c6c4-4f5c-866f-31c9b55b962d". filename is the name of the log file to which the events are written. traceFlags is one /// or more of the following flags which signify which areas to trace: /// /// /// /// Flag /// Hex Value /// Description /// /// /// DCLOCATOR_MISC /// 0x00000002 /// Miscellaneous debugging /// /// /// DCLOCATOR_MAILSLOT /// 0x00000010 /// Mailslot messages /// /// /// DCLOCATOR_SITE /// 0x00000020 /// Sites /// /// /// DCLOCATOR_CRITICAL /// 0x00000100 /// Important errors /// /// /// DCLOCATOR_SESSION_SETUP /// 0x00000200 /// Trusted Domain Maintenance /// /// /// DCLOCATOR_DNS /// 0x00004000 /// Name Registration /// /// /// DCLOCATOR_DNS_MORE /// 0x00020000 /// Verbose Name Registration /// /// /// DCLOCATOR_MAILBOX_TEXT /// 0x02000000 /// Verbose Mailbox Messages /// /// /// DCLOCATOR_SITE_MORE /// 0x08000000 /// Verbose sites /// /// /// Run the following command to stop the trace session: /// tracelog.exe -stop <sessionname> /// sessionname is the same name as the name you used when starting the session. /// /// Note The registry key for the process being traced must be present in the registry at the time the trace session is /// started. When the session starts, the process will verify whether or not it should be generating trace messages (based on the /// presence or absence of a registry key for that process name and optional PID). The process checks the registry only at the start /// of the session. Any changes in the registry occurring after that will not have any effect on tracing. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetdcnamea // DSGETDCAPI DWORD DsGetDcNameA( IN LPCSTR ComputerName, IN LPCSTR DomainName, IN GUID *DomainGuid, IN LPCSTR SiteName, IN ULONG Flags, OUT PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "da8b2983-5e45-40b0-b552-c9b3a1d8ae94")] public static extern Win32Error DsGetDcName([Optional] string ComputerName, [Optional] string DomainName, in Guid DomainGuid, [Optional] string SiteName, DsGetDcNameFlags Flags, out SafeNetApiBuffer DomainControllerInfo); /// /// The DsGetDcName function returns the name of a domain controller in a specified domain. This function accepts additional domain /// controller selection criteria to indicate preference for a domain controller with particular characteristics. /// /// /// Pointer to a null-terminated string that specifies the name of the server to process this function. Typically, this parameter is /// NULL, which indicates that the local computer is used. /// /// /// Pointer to a null-terminated string that specifies the name of the domain or application partition to query. This name can either /// be a DNS style name, for example, fabrikam.com, or a flat-style name, for example, Fabrikam. If a DNS style name is specified, /// the name may be specified with or without a trailing period. /// /// If the Flags parameter contains the DS_GC_SERVER_REQUIRED flag, DomainName must be the name of the forest. In this case, /// DsGetDcName fails if DomainName specifies a name that is not the forest root. /// /// /// If the Flags parameter contains the DS_GC_SERVER_REQUIRED flag and DomainName is NULL, DsGetDcName attempts to find a global /// catalog in the forest of the computer identified by ComputerName, which is the local computer if ComputerName is NULL. /// /// /// If DomainName is NULL and the Flags parameter does not contain the DS_GC_SERVER_REQUIRED flag, ComputerName is set to the default /// domain name of the primary domain of the computer identified by ComputerName. /// /// /// /// Pointer to a GUID structure that specifies the GUID of the domain queried. If DomainGuid is not NULL and the domain specified by /// DomainName or ComputerName cannot be found, DsGetDcName attempts to locate a domain controller in the domain having the GUID /// specified by DomainGuid. /// /// /// Pointer to a null-terminated string that specifies the name of the site where the returned domain controller should physically /// exist. If this parameter is NULL, DsGetDcName attempts to return a domain controller in the site closest to the site of the /// computer specified by ComputerName. This parameter should be NULL, by default. /// /// /// Contains a set of flags that provide additional data used to process the request. This parameter can be a combination of the /// following values. /// /// /// Pointer to a PDOMAIN_CONTROLLER_INFO value that receives a pointer to a DOMAIN_CONTROLLER_INFO structure that contains data about /// the domain controller selected. This structure is allocated by DsGetDcName. The caller must free the structure using the /// NetApiBufferFree function when it is no longer required. /// /// /// If the function returns domain controller data, the return value is ERROR_SUCCESS. /// If the function fails, the return value can be one of the following error codes. /// [DllImport(Lib.NetApi32, CharSet = CharSet.Auto)] [PInvokeData("DsGetDC.h", MSDNShortId = "ms675983")] public static extern Win32Error DsGetDcName([Optional] string ComputerName, [Optional] string DomainName, [Optional] IntPtr DomainGuid, [Optional] string SiteName, DsGetDcNameFlags Flags, out SafeNetApiBuffer DomainControllerInfo); /// /// The DsGetDcNext function retrieves the next domain controller in a domain controller enumeration operation. /// /// /// Contains the domain controller enumeration context handle provided by the DsGetDcOpen function. /// /// /// /// Pointer to a ULONG value that receives the number of elements in the SockAddresses array. If this parameter is /// NULL, socket addresses are not retrieved. /// /// /// /// /// Pointer to an array of SOCKET_ADDRESS structures that receives the socket address data for the domain controller. /// SockAddressCount receives the number of elements in this array. /// /// /// All returned addresses will be of type AF_INET or AF_INET6. The sin_port member contains the port from the /// server record. A port of 0 indicates no port is available from DNS. /// /// The caller must free this memory when it is no longer required by calling LocalFree. /// This parameter is ignored if SockAddressCount is NULL. /// /// /// /// Pointer to a string pointer that receives the DNS name of the domain controller. This parameter receives NULL if no host /// name is known. The caller must free this memory when it is no longer required by calling NetApiBufferFree. /// /// /// /// Returns ERROR_SUCCESS if successful or a Win32 or RPC error otherwise. Possible error values include the following. /// /// /// /// To reset the enumeration, close the current enumeration by calling DsGetDcClose and then reopen the enumeration by calling /// DsGetDcOpen again. /// /// /// The DC returned by DsGetDcNext will not be a Read-only DC (RODC) because those DCs only register site-specific and CName /// records, and both DsGetDcNext and DsGetDcOpen look for DNS SRV records. /// /// The following procedure shows how to get a complete DC list from a computer running Windows Server 2008. /// To obtain a complete list of domain controllers /// /// /// Use DsGetDcName to get a domain controller name. /// /// /// Use DsBind to connect to that domain controller. /// /// /// /// Call DsGetDomainControllerInfo with InfoLevel 3 ( DS_DOMAIN_CONTROLLER_INFO_3) to get the complete list, including RODCs. /// /// /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/Dsgetdc/nf-dsgetdc-dsgetdcnexta DSGETDCAPI DWORD DsGetDcNextA( IN HANDLE // GetDcContextHandle, OUT PULONG SockAddressCount, OUT LPSOCKET_ADDRESS *SockAddresses, OUT LPSTR *DnsHostName ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "2906772f-4391-411b-b0a9-5a20ebb6c0ee")] public static extern Win32Error DsGetDcNext(SafeDCEnumHandle GetDcContextHandle, out uint SockAddressCount, out SafeLocalHandle SockAddresses, out SafeNetApiBuffer DnsHostName); /// /// The DsGetDcOpen function opens a new domain controller enumeration operation. /// /// /// /// Pointer to a null-terminated string that contains the domain naming system (DNS) name of the domain to enumerate the domain /// controllers for. This parameter cannot be NULL. /// /// /// /// /// Contains a set of flags that modify the behavior of the function. This can be zero or a combination of one or more of the /// following values. /// /// DS_ONLY_DO_SITE_NAME /// Only site-specific domain controllers are enumerated. /// DS_NOTIFY_AFTER_SITE_RECORDS /// /// The DsGetDcNext function will return the ERROR_FILEMARK_DETECTED value after all of the site-specific domain controllers /// are retrieved. DsGetDcNext will then enumerate the second group, which contains all domain controllers in the domain, /// including the site-specific domain controllers contained in the first group. /// /// /// /// /// Pointer to a null-terminated string that contains the name of site the client is in. This parameter is optional and may be NULL. /// /// /// /// /// Pointer to a GUID value that contains the identifier of the domain specified by DnsName. This identifier is used to handle /// the case of a renamed domain. If this value is specified and the domain specified in DnsName is renamed, this function attempts /// to enumerate domain controllers in the domain that contains the specified identifier. This parameter is optional and may be NULL. /// /// /// /// /// Pointer to a null-terminated string that contains the name of the forest that contains the DnsName domain. This value is used in /// conjunction with DomainGuidto enumerate the domain controllers if the domain has been renamed. This parameter is optional and may /// be NULL. /// /// /// /// /// Contains a set of flags that identify the type of domain controllers to enumerate. This can be zero or a combination of one or /// more of the following values. /// /// DS_FORCE_REDISCOVERY /// /// Forces cached domain controller data to be ignored. When this flag is not specified, DsGetDcOpen obtains the domain /// controller enumeration from cached domain controller data. /// /// DS_GC_SERVER_REQUIRED /// /// Requires that the enumerated domain controllers be global catalog servers for the forest of domains with this domain as the root. /// This flag cannot be combined with the DS_PDC_REQUIRED flag. /// /// DS_KDC_REQUIRED /// /// Requires that the enumerated domain controllers currently be running the Kerberos Key Distribution Center service. This flag /// cannot be combined with the DS_PDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// /// DS_ONLY_LDAP_NEEDED /// /// Specifies that the enumerated servers are LDAP servers. The servers are not necessarily domain controllers. No other services are /// implied to be present at each enumerated server. The servers do not necessarily have a writable config container nor a /// writable schema container. The servers may not necessarily be used to create or modify security principles. This flag may /// be used with the DS_GC_SERVER_REQUIRED flag to enumerate LDAP servers that also host a global catalog server. In that /// case, the enumerated global catalog servers are not necessarily domain controllers and other services are implied to be present /// at each server. If this flag is specified, the DS_PDC_REQUIRED, DS_TIMESERV_REQUIRED, /// DS_GOOD_TIMESERV_PREFERRED, DS_DIRECTORY_SERVICES_PREFERED, DS_DIRECTORY_SERVICES_REQUIRED, and /// DS_KDC_REQUIRED flags are ignored. /// /// DS_PDC_REQUIRED /// /// Requires that the enumerated domain controllers be the primary domain controllers for the domain. This flag cannot be combined /// with the DS_GC_SERVER_REQUIRED flag. /// /// /// /// /// Pointer to a HANDLE value that receives the domain controller enumeration context handle. This handle is used with the /// DsGetDcNext function to identify the domain controller enumeration operation. This handle is passed to DsGetDcClose to close the /// domain controller enumeration operation. /// /// /// /// Returns ERROR_SUCCESS if successful or a Win32 or RPC error otherwise. Possible error values include the following. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetdcopena DSGETDCAPI DWORD DsGetDcOpenA( IN LPCSTR // DnsName, IN ULONG OptionFlags, IN LPCSTR SiteName, IN GUID *DomainGuid, IN LPCSTR DnsForestName, IN ULONG DcFlags, OUT PHANDLE // RetGetDcContext ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "2811cc30-f367-4f1a-8f0c-ed0a77dad24c")] public static extern Win32Error DsGetDcOpen(string DnsName, DsGetDcOpenOptions OptionFlags, [Optional] string SiteName, in Guid DomainGuid, [Optional] string DnsForestName, DsGetDcNameFlags DcFlags, out SafeDCEnumHandle RetGetDcContext); /// /// The DsGetDcOpen function opens a new domain controller enumeration operation. /// /// /// /// Pointer to a null-terminated string that contains the domain naming system (DNS) name of the domain to enumerate the domain /// controllers for. This parameter cannot be NULL. /// /// /// /// /// Contains a set of flags that modify the behavior of the function. This can be zero or a combination of one or more of the /// following values. /// /// DS_ONLY_DO_SITE_NAME /// Only site-specific domain controllers are enumerated. /// DS_NOTIFY_AFTER_SITE_RECORDS /// /// The DsGetDcNext function will return the ERROR_FILEMARK_DETECTED value after all of the site-specific domain controllers /// are retrieved. DsGetDcNext will then enumerate the second group, which contains all domain controllers in the domain, /// including the site-specific domain controllers contained in the first group. /// /// /// /// /// Pointer to a null-terminated string that contains the name of site the client is in. This parameter is optional and may be NULL. /// /// /// /// /// Pointer to a GUID value that contains the identifier of the domain specified by DnsName. This identifier is used to handle /// the case of a renamed domain. If this value is specified and the domain specified in DnsName is renamed, this function attempts /// to enumerate domain controllers in the domain that contains the specified identifier. This parameter is optional and may be NULL. /// /// /// /// /// Pointer to a null-terminated string that contains the name of the forest that contains the DnsName domain. This value is used in /// conjunction with DomainGuidto enumerate the domain controllers if the domain has been renamed. This parameter is optional and may /// be NULL. /// /// /// /// /// Contains a set of flags that identify the type of domain controllers to enumerate. This can be zero or a combination of one or /// more of the following values. /// /// DS_FORCE_REDISCOVERY /// /// Forces cached domain controller data to be ignored. When this flag is not specified, DsGetDcOpen obtains the domain /// controller enumeration from cached domain controller data. /// /// DS_GC_SERVER_REQUIRED /// /// Requires that the enumerated domain controllers be global catalog servers for the forest of domains with this domain as the root. /// This flag cannot be combined with the DS_PDC_REQUIRED flag. /// /// DS_KDC_REQUIRED /// /// Requires that the enumerated domain controllers currently be running the Kerberos Key Distribution Center service. This flag /// cannot be combined with the DS_PDC_REQUIRED or DS_GC_SERVER_REQUIRED flags. /// /// DS_ONLY_LDAP_NEEDED /// /// Specifies that the enumerated servers are LDAP servers. The servers are not necessarily domain controllers. No other services are /// implied to be present at each enumerated server. The servers do not necessarily have a writable config container nor a /// writable schema container. The servers may not necessarily be used to create or modify security principles. This flag may /// be used with the DS_GC_SERVER_REQUIRED flag to enumerate LDAP servers that also host a global catalog server. In that /// case, the enumerated global catalog servers are not necessarily domain controllers and other services are implied to be present /// at each server. If this flag is specified, the DS_PDC_REQUIRED, DS_TIMESERV_REQUIRED, /// DS_GOOD_TIMESERV_PREFERRED, DS_DIRECTORY_SERVICES_PREFERED, DS_DIRECTORY_SERVICES_REQUIRED, and /// DS_KDC_REQUIRED flags are ignored. /// /// DS_PDC_REQUIRED /// /// Requires that the enumerated domain controllers be the primary domain controllers for the domain. This flag cannot be combined /// with the DS_GC_SERVER_REQUIRED flag. /// /// /// /// /// Pointer to a HANDLE value that receives the domain controller enumeration context handle. This handle is used with the /// DsGetDcNext function to identify the domain controller enumeration operation. This handle is passed to DsGetDcClose to close the /// domain controller enumeration operation. /// /// /// /// Returns ERROR_SUCCESS if successful or a Win32 or RPC error otherwise. Possible error values include the following. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetdcopena DSGETDCAPI DWORD DsGetDcOpenA( IN LPCSTR // DnsName, IN ULONG OptionFlags, IN LPCSTR SiteName, IN GUID *DomainGuid, IN LPCSTR DnsForestName, IN ULONG DcFlags, OUT PHANDLE // RetGetDcContext ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "2811cc30-f367-4f1a-8f0c-ed0a77dad24c")] public static extern Win32Error DsGetDcOpen(string DnsName, DsGetDcOpenOptions OptionFlags, [Optional] string SiteName, [Optional] IntPtr DomainGuid, [Optional] string DnsForestName, DsGetDcNameFlags DcFlags, out SafeDCEnumHandle RetGetDcContext); /// /// The DsGetDcSiteCoverage function returns the site names of all sites covered by a domain controller. /// /// /// The null-terminated string value that specifies the name of the remote domain controller. /// /// /// Pointer to a ULONG value that receives the number of sites covered by the domain controller. /// /// /// /// Pointer to an array of pointers to null-terminated strings that receives the site names. To free the returned buffer, call the /// NetApiBufferFree function. /// /// /// /// This function returns DSGETDCAPI DWORD. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetdcsitecoveragew DSGETDCAPI DWORD // DsGetDcSiteCoverageW( IN LPCWSTR ServerName, OUT PULONG EntryCount, OUT LPWSTR **SiteNames ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "e0f757d9-36b6-40f8-a1db-fb5b9862b46a")] public static extern Win32Error DsGetDcSiteCoverage([Optional] string ServerName, out uint EntryCount, out SafeNetApiBuffer SiteNames); /// /// The DsGetForestTrustInformationW function obtains forest trust data for a specified domain. /// /// /// /// Contains the name of the domain controller that DsGetForestTrustInformationW is connected to remotely. The caller must be /// an authenticated user on this server. If this parameter is NULL, the local server is used. /// /// /// /// /// Contains the NETBIOS or DNS name of the trusted domain that the forest trust data is to be retrieved for. This domain must have /// the TRUST_ATTRIBUTE_FOREST_TRANSITIVE trust attribute. For more information, see TRUSTED_DOMAIN_INFORMATION_EX. /// /// If this parameter is NULL, the forest trust data for the domain hosted by ServerName is retrieved. /// /// /// Contains a set of flags that modify the behavior of this function. This can be zero or the following value. /// DS_GFTI_UPDATE_TDO /// /// If this flag is set, DsGetForestTrustInformationW will update the forest trust data of the trusted domain identified by /// the TrustedDomainNameparameter. In this case, the TrustedDomainName parameter cannot be NULL. The caller must have access /// to modify the trust data or ERROR_ACCESS_DENIED is returned. /// /// This flag is only valid if ServerName specifies the primary domain controller of the domain. /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure pointer that receives the forest trust data that describes the namespaces /// claimed by the domain specified by TrustedDomainName. The Time member of all returned records will be zero. /// /// The caller must free this structure when it is no longer required by calling NetApiBufferFree. /// /// /// Returns NO_ERROR if successful or a Win32 error code otherwise. Possible error codes include the following. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetforesttrustinformationw DSGETDCAPI DWORD // DsGetForestTrustInformationW( IN LPCWSTR ServerName, IN LPCWSTR TrustedDomainName, IN DWORD Flags, OUT // PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo ); [DllImport(Lib.NetApi32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)] [PInvokeData("dsgetdc.h", MSDNShortId = "c94fdc5b-920b-4807-9cbf-3172ec1c7386")] public static extern Win32Error DsGetForestTrustInformationW([Optional] string ServerName, [Optional] string TrustedDomainName, DsGetForestTrustInformationFlags Flags, out SafeNetApiBuffer ForestTrustInfo); /// /// /// The DsGetSiteName function returns the name of the site where a computer resides. For a domain controller (DC), the name /// of the site is the location of the configured DC. For a member workstation or member server, the name specifies the workstation /// site as configured in the domain of the computer. /// /// /// /// /// Pointer to a null-terminated string that specifies the name of the server to send this function. A NULL implies the local computer. /// /// /// /// /// Pointer to a variable that receives a pointer to a null-terminated string specifying the site location of this computer. /// /// /// /// If the function returns account information, the return value is NO_ERROR. /// If the function fails, the return value can be one of the following error codes. /// /// /// /// The DsGetSiteName function does not require any particular access to the specified domain. The function is sent to the /// "NetLogon" service on the computer specified by ComputerName. /// /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsgetsitenamea DSGETDCAPI DWORD DsGetSiteNameA( IN LPCSTR // ComputerName, OUT LPSTR *SiteName ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "2dfffd9a-af4f-4a93-8b3c-966e4f7c455f")] public static extern Win32Error DsGetSiteName([Optional] string ComputerName, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NetApiBufferUnicodeStringMarshaler))] out string SiteName); /// /// /// The DsMergeForestTrustInformationW function merges the changes from a new forest trust data structure with an old forest /// trust data structure. /// /// /// /// Pointer to a null-terminated Unicode string that specifies the trusted domain to update. /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure that contains the new forest trust data to be merged. The /// Flags and Time members of the entries are ignored. /// /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure that contains the old forest trust data to be merged. This parameter /// may be NULL if no records exist. /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure pointer that receives the merged forest trust data. /// The caller must free this structure when it is no longer required by calling NetApiBufferFree. /// /// /// Returns NO_ERROR if successful or a Windows error code otherwise. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsmergeforesttrustinformationw DSGETDCAPI DWORD // DsMergeForestTrustInformationW( IN LPCWSTR DomainName, IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo, IN // PLSA_FOREST_TRUST_INFORMATION OldForestTrustInfo, OUT PLSA_FOREST_TRUST_INFORMATION *MergedForestTrustInfo ); [DllImport(Lib.NetApi32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)] [PInvokeData("dsgetdc.h", MSDNShortId = "f42e16d0-62b2-49c4-b182-d1e744afe58c")] public static extern Win32Error DsMergeForestTrustInformationW(string DomainName, in LSA_FOREST_TRUST_INFORMATION NewForestTrustInfo, in LSA_FOREST_TRUST_INFORMATION OldForestTrustInfo, out SafeNetApiBuffer MergedForestTrustInfo); /// /// /// The DsMergeForestTrustInformationW function merges the changes from a new forest trust data structure with an old forest /// trust data structure. /// /// /// /// Pointer to a null-terminated Unicode string that specifies the trusted domain to update. /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure that contains the new forest trust data to be merged. The /// Flags and Time members of the entries are ignored. /// /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure that contains the old forest trust data to be merged. This parameter /// may be NULL if no records exist. /// /// /// /// Pointer to an LSA_FOREST_TRUST_INFORMATION structure pointer that receives the merged forest trust data. /// The caller must free this structure when it is no longer required by calling NetApiBufferFree. /// /// /// Returns NO_ERROR if successful or a Windows error code otherwise. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsmergeforesttrustinformationw DSGETDCAPI DWORD // DsMergeForestTrustInformationW( IN LPCWSTR DomainName, IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo, IN // PLSA_FOREST_TRUST_INFORMATION OldForestTrustInfo, OUT PLSA_FOREST_TRUST_INFORMATION *MergedForestTrustInfo ); [DllImport(Lib.NetApi32, SetLastError = false, ExactSpelling = true, CharSet = CharSet.Unicode)] [PInvokeData("dsgetdc.h", MSDNShortId = "f42e16d0-62b2-49c4-b182-d1e744afe58c")] public static extern Win32Error DsMergeForestTrustInformationW(string DomainName, in LSA_FOREST_TRUST_INFORMATION NewForestTrustInfo, [Optional] IntPtr OldForestTrustInfo, out SafeNetApiBuffer MergedForestTrustInfo); /// /// /// The DsValidateSubnetName function validates a subnet name in the form xxx.xxx.xxx.xxx/YY. The Xxx.xxx.xxx.xxx portion must /// be a valid IP address. Yy must be the number of leftmost significant bits included in the mask. All bits of the IP address that /// are not covered by the mask must be specified as zero. /// /// /// /// Pointer to a null-terminated string that specifies the name of the subnet to validate. /// /// /// If the function returns account information, the return value is NO_ERROR. /// If the function fails, the return value is the following error code. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/nf-dsgetdc-dsvalidatesubnetnamew DSGETDCAPI DWORD // DsValidateSubnetNameW( IN LPCWSTR SubnetName ); [DllImport(Lib.NetApi32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("dsgetdc.h", MSDNShortId = "bed49e08-4cb7-439c-bfb7-815263ec7568")] public static extern Win32Error DsValidateSubnetName(string SubnetName); /// The DOMAIN_CONTROLLER_INFO structure is used with the DsGetDcName function to receive data about a domain controller. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] [PInvokeData("DsGetDC.h", MSDNShortId = "ms675912")] public struct DOMAIN_CONTROLLER_INFO { /// /// Pointer to a null-terminated string that specifies the computer name of the discovered domain controller. The returned /// computer name is prefixed with "\\". The DNS-style name, for example, "\\phoenix.fabrikam.com", is returned, if available. If /// the DNS-style name is not available, the flat-style name (for example, "\\phoenix") is returned. This example would apply if /// the domain is a Windows NT 4.0 domain or if the domain does not support the IP family of protocols. /// public string DomainControllerName; /// /// Pointer to a null-terminated string that specifies the address of the discovered domain controller. The address is prefixed /// with "\\". This string is one of the types defined by the DomainControllerAddressType member. /// public string DomainControllerAddress; /// Indicates the type of string that is contained in the DomainControllerAddress member. public DomainControllerAddressType DomainControllerAddressType; /// /// The GUID of the domain. This member is zero if the domain controller does not have a Domain GUID; for example, the domain /// controller is not a Windows 2000 domain controller. /// public Guid DomainGuid; /// /// Pointer to a null-terminated string that specifies the name of the domain. The DNS-style name, for example, "fabrikam.com", /// is returned if available. Otherwise, the flat-style name, for example, "fabrikam", is returned. This name may be different /// than the requested domain name if the domain has been renamed. /// public string DomainName; /// /// Pointer to a null-terminated string that specifies the name of the domain at the root of the DS tree. The DNS-style name, for /// example, "fabrikam.com", is returned if available. Otherwise, the flat-style name, for example, "fabrikam" is returned. /// public string DnsForestName; /// /// Contains a set of flags that describe the domain controller. This can be zero or a combination of one or more of the /// following values. /// public DomainControllerType Flags; /// /// Pointer to a null-terminated string that specifies the name of the site where the domain controller is located. This member /// may be NULL if the domain controller is not in a site; for example, the domain controller is a Windows NT 4.0 domain controller. /// public string DcSiteName; /// /// Pointer to a null-terminated string that specifies the name of the site that the computer belongs to. The computer is /// specified in the ComputerName parameter passed to DsGetDcName. This member may be NULL if the site that contains the computer /// cannot be found; for example, if the DS administrator has not associated the subnet that the computer is in with a valid site. /// public string ClientSiteName; } /// /// The DS_DOMAIN_TRUSTS structure is used with the DsEnumerateDomainTrusts function to contain trust data for a domain. /// // https://docs.microsoft.com/en-us/windows/desktop/api/dsgetdc/ns-dsgetdc-_ds_domain_trustsa typedef struct _DS_DOMAIN_TRUSTSA { // LPSTR NetbiosDomainName; LPSTR DnsDomainName; ULONG Flags; ULONG ParentIndex; ULONG TrustType; ULONG TrustAttributes; PSID // DomainSid; GUID DomainGuid; } DS_DOMAIN_TRUSTSA, *PDS_DOMAIN_TRUSTSA; [PInvokeData("dsgetdc.h", MSDNShortId = "cd260fd1-dc38-4405-95ba-097a23faf668")] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DS_DOMAIN_TRUSTS { /// /// Pointer to a null-terminated string that contains the NetBIOS name of the domain. /// public string NetbiosDomainName; /// /// Pointer to a null-terminated string that contains the DNS name of the domain. This member may be NULL. /// public string DnsDomainName; /// /// /// Contains a set of flags that specify more data about the domain trust. This can be zero or a combination of one or more of /// the following values. /// /// DS_DOMAIN_IN_FOREST (1 (0x1)) /// /// The domain represented by this structure is a member of the same forest as the server specified in the ServerName parameter /// of the DsEnumerateDomainTrusts function. /// /// DS_DOMAIN_DIRECT_OUTBOUND (2 (0x2)) /// /// The domain represented by this structure is directly trusted by the domain that the server specified in the ServerName /// parameter of the DsEnumerateDomainTrusts function is a member of. /// /// DS_DOMAIN_TREE_ROOT (4 (0x4)) /// /// The domain represented by this structure is the root of a tree and a member of the same forest as the server specified in the /// ServerName parameter of the DsEnumerateDomainTrusts function. /// /// DS_DOMAIN_PRIMARY (8 (0x8)) /// /// The domain represented by this structure is the primary domain of the server specified in the ServerName parameter of the /// DsEnumerateDomainTrusts function. /// /// DS_DOMAIN_NATIVE_MODE (16 (0x10)) /// The domain represented by this structure is running in the Windows 2000 native mode. /// DS_DOMAIN_DIRECT_INBOUND (32 (0x20)) /// /// The domain represented by this structure directly trusts the domain that the server specified in the ServerName parameter of /// the DsEnumerateDomainTrusts function is a member of. /// /// public DomainTrustFlag Flags; /// /// /// Contains the index in the Domains array returned by the DsEnumerateDomainTrusts function that corresponds to the parent /// domain of the domain represented by this structure. This member is only valid if the all of the following conditions are met: /// /// /// /// The DS_DOMAIN_IN_FOREST flag was specified in the Flags parameter of the DsEnumerateDomainTrusts function. /// /// /// The Flags member of this structure does not contain the DS_DOMAIN_TREE_ROOT flag. /// /// /// public uint ParentIndex; /// /// /// Contains a value that indicates the type of trust represented by this structure. Possible values for this member are /// documented in the TrustType member of the TRUSTED_DOMAIN_INFORMATION_EX structure. /// /// public TrustType TrustType; /// /// /// Contains a value that indicates the attributes of the trust represented by this structure. Possible values for this member /// are documented in the TrustAttribute member of the TRUSTED_DOMAIN_INFORMATION_EX structure. /// /// public TrustAttributes TrustAttributes; /// /// Contains the security identifier of the domain represented by this structure. /// public IntPtr DomainSid; /// /// Contains the GUID of the domain represented by this structure. /// public Guid DomainGuid; } /// /// Provides a to a domain controller enumeration handle that is released at disposal using DsGetDcClose. /// public class SafeDCEnumHandle : SafeHANDLE { /// Initializes a new instance of the class and assigns an existing handle. /// An object that represents the pre-existing handle to use. /// /// to reliably release the handle during the finalization phase; otherwise, (not recommended). /// public SafeDCEnumHandle(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } /// Initializes a new instance of the class. private SafeDCEnumHandle() : base() { } /// protected override bool InternalReleaseHandle() { DsGetDcClose(handle); return true; } } } }