如何获取Windows域名?

18

如何获取计算机的域名(如果该计算机实际上已加入了域)?

当然,如果计算机没有加入域,则该函数应返回:

  • null,或者
  • 一个空字符串,或者
  • 计算机名称,或者
  • "."

  • NetGetJoinInformation Win32 函数返回域的旧版 NetBIOS 名称(例如 AVATOPIA),而不是域名(例如 avatopia.local

  • USERDOMAIN 环境变量返回登录用户的域,可能与计算机不同;也会返回域的旧版 NetBIOS 名称(例如 AVATOPIA

  • USERDNSDOMAIN 环境变量返回登录用户的域名,可能与计算机不同

Microsoft 有一篇知识库文章如何检索 Windows NT、Windows 2000 或 Windows XP 上的当前用户和域名,该文章依赖于获取用户的安全令牌并调用 LookupAccountSid。

  • LookupAccountSid Win32 函数返回域的旧版 NetBIOS 名称(例如 AVATOPIA);也会返回登录用户所在的域,可能与计算机不同

更新一

我也尝试使用 ADs 对象来绑定到域的 IADs 接口:

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

这种方法存在以下问题:

  • 您无法获取域名(只能获取可分辨名称)。
  • 如果用户没有权限查询AD,则无法正常工作。
  • 如果用户不是活动目录中的有效用户,则无法正常工作。
  • 它仅适用于Active Directory域。

更新二:

我想要的是:

enter image description here

额外阅读


你使用哪种语言来获取它? - Taha Paksu
@tpaksu 本地代码,因此您可以假设使用C、C++、Delphi、C#与P/Invoke、汇编语言等(这是一种绕弯子的说法,意思是我没有从通用语言运行时或Java运行时中调用它,并且无法访问.NET Framework类库或Java类库)。 - Ian Boyd
2
我不清楚你引用的参考资料为什么不足够? - Mark Ransom
我意识到您希望从本机代码中完成此操作,但是 .NET 中的 System.DirectoryServices.ActiveDirectory.Domain 是否返回所需信息? - Cody Gray
你是否尝试过LsaOpenPolicyLsaQueryInformationPolicy 函数?例如请查看此文档:如何确定 Windows NT/Windows 2000 计算机是否为域成员 - RRUZ
显示剩余2条评论
3个回答

18

这里您可以看到:

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

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

#include <stdio.h>

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

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

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

    return 0;
}

在生产环境中使用DsRoleGetPrimaryDomainInformation的人应该考虑在不再需要信息时调用DsRoleFreeMemory来释放内存块(如评论中所述)。

该函数返回三个不同的域名,例如:

  • 域森林名称:例如stackoverflow.com
  • 域DNS名称:例如stackoverflow.com
  • 域NetBIOS名称:例如STACKOVERFLOW

如果计算机没有加入域,则Forestdns都为空,只有NetBios名称填充为工作组的名称,例如:

  • 域森林名称null
  • 域DNS名称:例如null
  • 域NetBIOS名称:例如WORKGROUP

该函数还返回一个指示计算机是否加入域的标志:

  • DsRole_RoleMemberWorkstation:是域成员的工作站
  • DsRole_RoleMemberServer:是域成员的服务器
  • DsRole_RolePrimaryDomainController:主域控制器
  • DsRole_RoleBackupDomainController:备份域控制器

或者不是:

  • DsRole_RoleStandaloneWorkstation:非域成员的工作站
  • DsRole_RoleStandaloneServer:非域成员的服务器

1
记录一下,我没有在非域计算机上测试过这个。但如果它不能很好地工作,可以先使用 NetGetJoinInformation 检查一下你是否在域中。 - Harry Johnston
它适用于非域加入计算机、AD域加入计算机、Windows 2000以及未连接到网络的计算机。我想我们有一个胜利者。我只需要弄清楚“DNS域名”和“Forest域名”的区别,以及哪一个是我的域名 (http://superuser.com/questions/403447/difference-between-domain-forest-name-and-dns-name)。 - Ian Boyd
@wishmesh:经过一些考虑,我决定回滚你的编辑。在这种情况下,对DsRoleFreeMemory的调用是多余的,因为我们接下来要做的就是退出程序,在生产代码中,您通常希望无限期地保留此信息,因此您也不会调用DsRoleFreeMemory。毕竟,它只是少量的数据。它之所以在动态分配的内存中,唯一的原因是它的长度是可变的。 - Harry Johnston
1
@harry-johnston:感谢您的评论。看起来DsRoleGetPrimaryDomainInformation在连续调用时不会返回不同的信息。我删除了之前的评论。 - Maris B.
1
@osullivj:一般情况下,您需要找到自己的IP地址并进行反向DNS查询。虽然有相应的API,但这个API不支持。:-) 在您的特定情况下,使用Amazon特定的数据可能更明智。 - Harry Johnston
显示剩余3条评论

6

使用GetComputerNameEx函数可以获取计算机名称和域名。

示例:

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

注意:ComputerNameDnsDomain 提供域名,而 ComputerNameNetBIOS 提供本地工作组(计算机)名称。

这将返回主DNS后缀,而不是计算机加入的域,如果您有不连续的命名空间,可能会导致问题。 DsRoleGetPrimaryDomainInformation没有这个问题。 - Shane Spoor

0

您可以使用Win32_NTDomain类通过WMI获取域名。该链接包含其他示例链接,介绍如何与WMI交互。


查询“select * from Win32_NTDomain”似乎需要约15秒才能返回;并且它不能在Windows 2000上运行。 - Ian Boyd
WMI 很慢且不可靠。最好使用本地 API GetComputerNameEx(),如 @Sanju-Monu 所建议的那样。此外,GetComputerNameEx 在 Windows 2000 中也存在。 - iPath ツ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接