【问题标题】:Get nETBIOSName from a UserPrincipal object从 UserPrincipal 对象中获取 nETBIOSName
【发布时间】:2010-11-26 10:54:49
【问题描述】:

我正在使用 .Net 库的 System.DirectoryServices.AccountManagement 部分来连接 ActiveDirectory。

在 GroupPrincipal 对象上调用 GetMembers() 并过滤结果后,我现在有了 UserPrincipal 对象的集合

GroupPrincipal myGroup;  // population of this object omitted here 

foreach (UserPrincipal user in myGroup.GetMembers(false).OfType<UserPrincipal>())
{
    Console.WriteLine(user.SamAccountName);
}

上面的代码示例将打印出像“TestUser1”这样的用户名。我需要将这些与来自“DOMAIN\TestUser1”格式的另一个应用程序的列表进行比较。

如何从 UserPrincipal 对象中获取“DOMAIN”部分?

我不能只附加一个已知域名,因为涉及多个域,我需要区分 DOMAIN1\TestUser1 和 DOMAIN2\TestUser2。

【问题讨论】:

  • @marc_s UserPrincipleName 包含 name@fully.qualified.domain.name 格式的名称 - 我看不出如何轻松将其转换为 DOMAIN\user 格式(尤其是涉及的域是已知列表 - 每个生产环境将是与我的开发环境不同的域列表)
  • 您也可以使用msDS-PrincipalName 属性,如此处所述stackoverflow.com/questions/10702188
  • 或使用user.Sid.Translate(typeof(System.Security.Principal.NTAccount)).ToString() 获取每个组成员的域\用户名。见stackoverflow.com/questions/6759463
  • @GregBray msDs-Principalname 在 Win2003 中对于 AD LDS 系统不存在(请参阅msdn.microsoft.com/en-us/library/cc221208.aspx),并且在 AD DS 上可能包含 NETBIOS 名称(请参阅msdn.microsoft.com/en-us/library/cc223404.aspx) .我不再有权访问我最初遇到此问题的域以进行检查 - 但您的建议可能对那些关注的人有用...

标签: c# .net active-directory userprincipal


【解决方案1】:

你有两个我能想到的选择。

  1. 解析或获取name@fully.qualified.domain.name 右侧的所有内容;
  2. 使用System.DirectoryServices 命名空间。

我不知道 UserPrincipal,我也不知道 GroupPrincipal。另一方面,我知道一种实现您想要的工作的方法。

[TestCase("LDAP://fully.qualified.domain.name", "TestUser1")] 
public void GetNetBiosName(string ldapUrl, string login)
    string netBiosName = null;
    string foundLogin = null;

    using (DirectoryEntry root = new DirectoryEntry(ldapUrl))
        Using (DirectorySearcher searcher = new DirectorySearcher(root) {
            searcher.SearchScope = SearchScope.Subtree;
            searcher.PropertiesToLoad.Add("sAMAccountName");
            searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", login);

            SearchResult result = null;

            try {
                result = searcher.FindOne();

                if (result == null) 
                    if (string.Equals(login, result.GetDirectoryEntry().Properties("sAMAccountName").Value)) 
                        foundLogin = result.GetDirectoryEntry().Properties("sAMAccountName").Value
            } finally {
                searcher.Dispose();
                root.Dispose();
                if (result != null) result = null;
            }
        }

    if (!string.IsNullOrEmpty(foundLogin)) 
        using (DirectoryEntry root = new DirectoryEntry(ldapUrl.Insert(7, "CN=Partitions,CN=Configuration,DC=").Replace(".", ",DC=")) 
            Using DirectorySearcher searcher = new DirectorySearcher(root)
                searcher.Filter = "nETBIOSName=*";
                searcher.PropertiesToLoad.Add("cn");

                SearchResultCollection results = null;

                try {
                    results = searcher.FindAll();

                    if (results != null && results.Count > 0 && results[0] != null) {
                        ResultPropertyValueCollection values = results[0].Properties("cn");
                        netBiosName = rpvc[0].ToString();
                } finally {
                    searcher.Dispose();
                    root.Dispose();

                    if (results != null) {
                        results.Dispose();
                        results = null;
                    }
                }
            }

    Assert.AreEqual("INTRA\TESTUSER1", string.Concat(netBiosName, "\", foundLogin).ToUpperInvariant())
}

此 SO 问题中提供的其他相关信息或链接。
C# Active Directory: Get domain name of user?
How to find the NetBIOS name of a domain

【讨论】:

  • 看起来不错,但不起作用。 result.GetDirectoryEntry() 没有“nETBIOSName”属性 - 它始终为空。 (另外我必须使用 Properties["nETBIOSName"].Value 并且我的结果对象没有 Dispose() - 如果有区别,请使用 .Net4)
  • @Grmh:我编辑了我的答案。请看一下并告诉我它是否有效。为了便于测试,我将它封装在一个 NUnit 测试用例中。
  • @Will:我的域中似乎没有“CN=Partitions,CN=Configuration”。我的域显然是一个子域,而父域有一个 CN=Copnfiguration 部分。我得调查一下……
  • 如果我查询父域,它会得到两个结果。 results[0].Properties["cn"][0] 给出父域 NetBIOS 名称,而 results[1].Properties["cn"][0] 给出子域 NetBIOS 名称。这给出了可能的 NETBIOS 名称的列表。我想我必须查找每个 netbiosname\loginname 组合,看看它是否返回一个有效用户并且它是否与原始用户匹配。不过好像有点曲折。 :(
  • @Grhm:同意,很曲折。我认为最简单的可能方法是在login@fully.qualified.domain.name 上取@ 符号的正确部分并将其解析连接以形成fully.qualified.domain.name\login。这对你最有效吗?
【解决方案2】:

使用 ActiveDs COM 库,它具有内置的名称转换功能,并且不做任何假设(就像这里的其他答案一样)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ActiveDs;

namespace Foo.Repository.AdUserProfile
{
    public class ADUserProfileValueTranslate
    {
        public static string ConvertUserPrincipalNameToNetBiosName(string userPrincipleName)
        {
            NameTranslate nameTranslate = new NameTranslate();
            nameTranslate.Set((int)ADS_NAME_TYPE_ENUM.ADS_NAME_TYPE_USER_PRINCIPAL_NAME, userPrincipleName);
            return nameTranslate.Get((int) ADS_NAME_TYPE_ENUM.ADS_NAME_TYPE_NT4);
        }
    }
}

【讨论】:

    【解决方案3】:

    您可以在 user.DistinguishedName 属性中查找可能的域。 域 1 中的用户应包含字符串“DC=DOMAIN1”。它绝对不应该包含字符串“DC=DOMAIN2”。

    【讨论】:

    • 不一定。我的域是 user1@dev.project.local 或 PROJECTDEV\User1 user.DistinguishedName 以 DC=dev,DC=project,DC=local 结尾,它不包含 DC=PROJECTDEV
    • 啊-谢谢纠正。我曾认为专有名称在某种意义上是一个计算字段 - 它在我的环境中是一致的。
    【解决方案4】:

    正如其中一个问题中提到的,我认为这是最近一段时间的一个很好的答案:

     user.Sid.Translate(typeof(System.Security.Principal.NTAccount)).ToString()
    

    【讨论】:

      【解决方案5】:

      您是否尝试过将完全限定域名传递给其他应用程序?如果您使用fully_qualified_domain\USER,大多数 Windows API 都不会抱怨。

      【讨论】:

      • 不幸的是,其他应用程序将用户名存储在数据库中,并希望用户名是唯一的。它还可以连接到我无法访问的许多其他应用程序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-19
      相关资源
      最近更新 更多