DsGetDcNameA 函数 (dsgetdc.h)

DsGetDcName 函数返回指定域中域控制器的名称。 此函数接受其他域控制器选择条件,以指示对具有特定特征的域控制器的首选项。

语法

DSGETDCAPI DWORD DsGetDcNameA(
  [in]  LPCSTR                   ComputerName,
  [in]  LPCSTR                   DomainName,
  [in]  GUID                     *DomainGuid,
  [in]  LPCSTR                   SiteName,
  [in]  ULONG                    Flags,
  [out] PDOMAIN_CONTROLLER_INFOA *DomainControllerInfo
);

参数

[in] ComputerName

指向以 null 结尾的字符串的指针,该字符串指定要处理此函数的服务器的名称。 通常,此参数 NULL,指示使用本地计算机。

[in] DomainName

指向以 null 结尾的字符串的指针,该字符串指定要查询的域或应用程序分区的名称。 此名称可以是 DNS 样式名称,例如,fabrikam.com 或平面样式名称,例如 Fabrikam。 如果指定了 DNS 样式名称,可以使用尾随句点或不使用尾随句点指定名称。

如果 标志 参数包含 DS_GC_SERVER_REQUIRED 标志,DomainName 必须是林的名称。 在这种情况下,如果 DomainName 指定不是林根的名称,DsGetDcName 将失败。

如果 标志 参数包含 DS_GC_SERVER_REQUIRED 标志,DomainNameNULLDsGetDcName 尝试在 ComputerName标识的计算机林中查找全局目录,如果 ComputerName为 NULL,则为本地计算机。

如果 DomainName为 NULL,并且 Flags 参数不包含 DS_GC_SERVER_REQUIRED 标志,则 ComputerName 设置为由 ComputerName标识的计算机的主域的默认域名。

[in] DomainGuid

指向 GUID 结构的指针,该结构指定所查询的域 GUID。 如果 DomainGuidNULL,并且找不到由 DomainNameComputerName 指定的域,DsGetDcName 尝试在由 DomainGuid指定的域中查找域控制器。

[in] SiteName

指向以 null 结尾的字符串的指针,该字符串指定返回的域控制器应实际存在的站点的名称。 如果此参数 NULLDsGetDcName 尝试返回离 ComputerName指定的计算机站点最近的站点中的域控制器。 默认情况下,此参数应 NULL

[in] Flags

包含一组标志,这些标志提供用于处理请求的其他数据。 此参数可以是以下值的组合。

DS_AVOID_SELF

从域控制器调用时,指定返回的域控制器名称不应为当前计算机。 如果当前计算机不是域控制器,则忽略此标志。 此标志可用于获取域中另一个域控制器的名称。

DS_BACKGROUND_ONLY

如果未指定 DS_FORCE_REDISCOVERY 标志,则此函数使用缓存的域控制器数据。 如果缓存的数据超过 15 分钟,则通过 ping 域控制器刷新缓存。 如果指定了此标志,即使缓存的数据已过期,也会避免此刷新。 如果定期调用 DsGetDcName 函数,则应使用此标志。

DS_DIRECTORY_SERVICE_PREFERRED

DsGetDcName 尝试查找支持目录服务功能的域控制器。 如果支持目录服务的域控制器不可用,DsGetDcName 返回非目录服务域控制器的名称。 但是,DsGetDcName 在尝试查找目录服务域控制器超时后仅返回非目录服务域控制器。

DS_DIRECTORY_SERVICE_REQUIRED

要求返回的域控制器支持目录服务。

DS_DIRECTORY_SERVICE_6_REQUIRED

要求返回的域控制器运行 Windows Server 2008 或更高版本。

DS_DIRECTORY_SERVICE_8_REQUIRED

要求返回的域控制器运行 Windows Server 2012 或更高版本。

DS_FORCE_REDISCOVERY

强制忽略缓存的域控制器数据。 如果未指定 DS_FORCE_REDISCOVERY 标志,DsGetDcName 可能会返回缓存的域控制器数据。 如果指定了此标志,DsGetDcName 将不会使用缓存信息(如果有),而是会执行新的域控制器发现。

此标志不应在正常情况下使用,因为使用缓存的域控制器信息具有更好的性能特征,有助于确保所有应用程序一致地使用相同的域控制器。 只有在应用程序确定 DsGetDcName 返回的域控制器(在没有此标志的情况下调用时)不可访问后,才应使用此标志。 在这种情况下,应用程序应使用此标志重复 DsGetDcName 调用,以确保忽略未使用的缓存信息(如果有),并发现可访问的域控制器。

DS_GC_SERVER_REQUIRED

要求返回的域控制器是作为根域的域林的全局编录服务器。 如果设置了此标志并且 DomainName 参数未 NULLDomainName 必须指定林名称。 此标志不能与 DS_PDC_REQUIREDDS_KDC_REQUIRED 标志结合使用。

DS_GOOD_TIMESERV_PREFERRED

DsGetDcName 尝试查找可靠时间服务器的域控制器。 可以将 Windows 时间服务配置为将一个或多个域控制器声明为可靠的时间服务器。 有关详细信息,请参阅 Windows 时间服务 文档。 此标志仅供 Windows 时间服务使用。

DS_IP_REQUIRED

此参数指示域控制器必须具有 IP 地址。 在这种情况下,DsGetDcName 会将域控制器的 Internet 协议地址放置在 DomainControllerAddressDomainControllerInfo的成员中。

DS_IS_DNS_NAME

指定 DomainName 参数是 DNS 名称。 此标志不能与 DS_IS_FLAT_NAME 标志组合在一起。

指定 DS_IS_DNS_NAMEDS_IS_FLAT_NAME。 如果未指定这两个标志,DsGetDcName 查找域控制器可能需要更长的时间,因为它可能需要同时搜索 DNS 样式和平面名称。

DS_IS_FLAT_NAME

指定 DomainName 参数是平面名称。 此标志不能与 DS_IS_DNS_NAME 标志组合在一起。

DS_KDC_REQUIRED

要求返回的域控制器当前正在运行 Kerberos 密钥分发中心服务。 此标志不能与 DS_PDC_REQUIREDDS_GC_SERVER_REQUIRED 标志组合在一起。

DS_ONLY_LDAP_NEEDED

指定返回的服务器是 LDAP 服务器。 返回的服务器不一定是域控制器。 服务器上没有暗示其他任何服务。 返回的服务器不一定具有可写 配置 容器,也不一定具有可写 架构 容器。 返回的服务器不一定用于创建或修改安全原则。 此标志可与 DS_GC_SERVER_REQUIRED 标志一起使用,以返回同时托管全局编录服务器的 LDAP 服务器。 返回的全局编录服务器不一定是域控制器。 服务器上没有暗示其他任何服务。 如果指定了此标志,则忽略 DS_PDC_REQUIREDDS_TIMESERV_REQUIREDDS_GOOD_TIMESERV_PREFERREDDS_DIRECTORY_SERVICES_PREFEREDDS_DIRECTORY_SERVICES_REQUIREDDS_KDC_REQUIRED 标志。

DS_PDC_REQUIRED

要求返回的域控制器是域的主域控制器。 此标志不能与 DS_KDC_REQUIREDDS_GC_SERVER_REQUIRED 标志结合使用。

DS_RETURN_DNS_NAME

指定在 DomainControllerName 中返回的名称,DomainNameDomainControllerInfo 的成员应为 DNS 名称。 如果 DNS 名称不可用,则返回错误。 不能使用 DS_RETURN_FLAT_NAME 标志指定此标志。 此标志表示 DS_IP_REQUIRED 标志。

DS_RETURN_FLAT_NAME

指定在 DomainControllerName 中返回的名称,DomainNameDomainControllerInfo 的成员应是平面名称。 如果平面名称不可用,则返回错误。 不能使用 DS_RETURN_DNS_NAME 标志指定此标志。

DS_TIMESERV_REQUIRED

要求返回的域控制器当前正在运行 Windows 时间服务。

DS_TRY_NEXTCLOSEST_SITE

指定此标志后,DsGetDcName 尝试在调用方所在的同一站点中找到域控制器。 如果未找到此类域控制器,它将找到可以提供拓扑信息的域控制器,并调用 DsBindToISTG 以获取绑定句柄,然后通过 UDP 调用 DsQuerySitesByCost 以确定“下一个最近的站点”,最后缓存找到的站点的名称。 如果未在该站点中找到域控制器,DsGetDcName 回退到查找域控制器的默认方法。

如果此标志与输入参数中的非 NULL 值结合使用 SiteName,则会引发 ERROR_INVALID_FLAGS

此外,与 DS_TRY_NEXT_CLOSEST_SITE 一起使用的搜索类型特定于网站,因此,如果与 DS_PDC_REQUIRED结合使用,则忽略此标志。 最后,当与 DS_RETURN_FLAT_NAME 结合使用时,将忽略 DS_TRY_NEXTCLOSEST_SITE,因为它使用 NetBIOS 解析名称,但找到的域控制器的域不一定与客户端加入的域匹配。

注意 此标志已启用组策略。 如果启用“下一个最近的站点”策略设置,则会针对所有可用但未配置的网络适配器的计算机启用“下一个最近的站点 DC 位置”。 如果禁用策略设置,默认情况下不会对所有可用但未配置的网络适配器的计算机使用下一个最近的站点 DC 位置。 但是,如果显式使用 DS_TRY_NEXTCLOSEST_SITE 标志进行 DC 定位符调用,DsGetDcName 遵循下一个最接近的站点行为。 如果未配置此策略设置,则默认情况下不会对所有可用但未配置的网络适配器的计算机使用下一个最近的站点 DC 位置。 如果显式使用 DS_TRY_NEXTCLOSEST_SITE 标志,将使用下一个最接近的网站行为。
 

DS_WRITABLE_REQUIRED

要求返回的域控制器可写;也就是说,托管目录服务的可写副本。

DS_WEB_SERVICE_REQUIRED

要求返回的域控制器当前正在运行 Active Directory Web 服务。

[out] DomainControllerInfo

指向 PDOMAIN_CONTROLLER_INFO 值的指针,该值接收指向包含所选域控制器数据的 DOMAIN_CONTROLLER_INFO 结构的指针。 此结构由 DsGetDcName分配。 当不再需要该函数时,调用方必须使用 NetApiBufferFree 函数释放结构。

返回值

如果函数返回域控制器数据,则返回值 ERROR_SUCCESS

如果函数失败,则返回值可以是以下错误代码之一。

言论

DsGetDcName 函数将发送到由 ComputerName指定的远程计算机上的 Netlogon 服务。 如果 ComputerNameNULL,则会在本地计算机上处理该函数。

DsGetDcName 不验证返回的域控制器名称是否为实际域控制器或全局目录的名称。 如果需要相互身份验证,调用方必须执行身份验证。

DsGetDcName 不需要对指定域的任何特定访问。 默认情况下,此函数不确保返回的域控制器当前可用。 相反,调用方应尝试使用返回的域控制器。 如果域控制器不可用,调用方应再次调用 DsGetDcName 函数,并指定 DS_FORCE_REDISCOVERY 标志。

响应时间

使用 DsGetDcName 请注意以下计时详细信息:
  • DsGetDcName 进行网络调用,可能需要几秒钟到一分钟,具体取决于网络流量、拓扑、DC 负载等。
  • 不建议从 UI 或其他计时关键线程调用 DsGetDcName
  • DC 定位器确实使用优化的逻辑来尽快提供 DC 信息。 它还使用站点上的缓存信息来联系最近的 DC。

有关域控制器粘性 说明

在 Active Directory 域服务中,域控制器定位器功能旨在使客户端找到首选域控制器后,除非域控制器停止响应或重新启动客户端,否则客户端将不会查找另一个域控制器。 这称为“域控制器粘性”。 由于工作站通常运行数月而不会出现问题或重启,因此此行为的一个意外后果是,如果某个特定域控制器出现故障进行维护,则连接到该控制器的所有客户端都会将其连接转移到另一个域控制器。 但是,当域控制器恢复时,任何客户端都不会重新连接到它,因为客户端不会经常重启。 这可能会导致负载均衡问题。

以前,此问题的最常见解决方案是在每个客户端计算机上部署脚本,该脚本使用 DS_FORCE_REDISCOVERY 标志定期调用 DsGetDcName。 这是一种有点繁琐的解决方案,因此 Windows Server 2008 和 Windows Vista 引入了一种导致域控制器粘性问题的新机制。

每当 DsGetDcName 从其缓存中检索域控制器名称时,它会检查此缓存条目是否已过期,如果是,则放弃该域控制器名称并尝试重新发现域控制器名称。 缓存项的生命周期由以下注册表项中的值控制

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\参数\ForceRediscoveryInterval

HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Netlogon\Parameters\ForceRediscoveryInterval

这些注册表项中的值的类型为 REG_DWORD。 它们指定 DsGetDcName 前的长度(以秒为单位)应尝试重新发现域控制器名称。 默认值为 43200 秒(12 小时)。 如果 ForceRediscoveryInterval 注册表项的值设置为 0,客户端将始终执行重新发现。 如果该值设置为4294967295,缓存永远不会过期,并且缓存的域控制器将继续使用。 建议不要将 ForceRediscoveryInterval 注册表项设置为小于 3600 秒(60 分钟)的值。

注意 已启用组策略 ForceRediscoveryInterval 的注册表设置。 如果禁用策略设置,则默认每隔 12 小时对计算机使用 Force Rediscovery。 如果未配置此策略设置,则除非注册表中的本地计算机设置是不同的值,否则默认情况下,强制重新发现将每隔 12 小时对计算机使用一次。
 
请注意,如果指定了 DS_BACKGROUND_ONLY 标志,DsGetDcName 永远不会尝试重新发现域控制器名称,因为该标志的点是强制 DsGetDcName 使用缓存的域控制器名称,即使它已过期也是如此。

在 DsGetDcName 中 ETW 跟踪

若要为 DsGetDcName启用 ETW 跟踪,请创建以下注册表项:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\DCLocator\跟踪

密钥将具有以下结构:

String ProcessName
  DWORD  PID <optional>

ProcessName 必须是全名,包括要获取其跟踪信息的进程的扩展。 仅当存在同名的多个进程时,才需要 PID。 如果已定义,则仅启用具有该 PID 的进程进行跟踪。 不能只跟踪 3 个(或更多)具有相同名称的进程中的 2 个。 可以启用一个实例或所有实例(如果存在具有相同进程名称的多个实例且未指定 PID,则所有实例都将启用跟踪)。

例如,这会跟踪 App1.exe 和 App2.exe的所有实例,但仅跟踪 PID 为 999 的 App3.exe 实例:

App1.exe 
App2.exe
App3.exe
     PID 999

运行以下命令以启动跟踪会话:

tracelog.exe -start <sessionname> -guid #cfaa5446-c6c4-4f5c-866f-31c9b55b962d -f <filename> -flag <traceFlags>

会话名称 为跟踪会话提供的名称。 DCLocator 跟踪提供程序 guid 为“cfaa5446-c6c4-4f5c-866f-31c9b55b962d”。 文件名 是写入事件的日志文件的名称。 traceFlags 是以下一个或多个标志,表示要跟踪的区域:

十六进制值 描述
DCLOCATOR_MISC 0x00000002 其他调试
DCLOCATOR_MAILSLOT 0x00000010 Mailslot 邮件
DCLOCATOR_SITE 0x00000020 网站
DCLOCATOR_CRITICAL 0x00000100 重要错误
DCLOCATOR_SESSION_SETUP 0x00000200 受信任的域维护
DCLOCATOR_DNS 0x00004000 名称注册
DCLOCATOR_DNS_MORE 0x00020000 详细名称注册
DCLOCATOR_MAILBOX_TEXT 0x02000000 详细邮箱邮件
DCLOCATOR_SITE_MORE 0x08000000 详细网站
 

运行以下命令以停止跟踪会话:

tracelog.exe -stop <sessionname>

会话名称 与启动会话时使用的名称相同。

注意 跟踪进程的注册表项必须在启动跟踪会话时存在于注册表中。 会话启动时,进程将验证它是否应生成跟踪消息(基于该进程名称和可选 PID 是否存在注册表项)。 此过程仅在会话开始时检查注册表。 注册表中发生的任何更改都将对跟踪没有任何影响。
 

注意

dsgetdc.h 标头将 DsGetDcName 定义为一个别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将中性编码别名与不中性编码的代码混合使用可能会导致编译或运行时错误不匹配。 有关详细信息,请参阅函数原型的 约定。

要求

要求 价值
最低支持的客户端 Windows Vista
支持的最低服务器 Windows Server 2008
目标平台 窗户
标头 dsgetdc.h
NetApi32.lib
DLL NetApi32.dll

另请参阅

DOMAIN_CONTROLLER_INFO

目录服务函数

DsGetSiteName

DsValidateSubnetName

GUID

NetApiBufferFree

Windows 时间服务