C# 如何在复杂环境中使用FQDN获取NETBIOS域名

C# 如何在复杂环境中使用FQDN获取NETBIOS域名,c#,active-directory,directoryservices,C#,Active Directory,Directoryservices,从完全限定的Active Directory域名获取NETBIOS域名有时是一项繁琐的任务。我找到了一个好答案 但是,在具有多个林的环境中,如果PC不在您要查询的林中,此方法将不起作用。这是因为LDAP://RootDSE将查询计算机域的信息 有人可能会问:为什么这么复杂?只需在检索到的第一个点之前使用名称: ActiveDirectory.Domain.GetComputerDomain().Name; 或者只获取用户的域名: Environment.GetEnvironmentVariab

从完全限定的Active Directory域名获取NETBIOS域名有时是一项繁琐的任务。我找到了一个好答案

但是,在具有多个林的环境中,如果PC不在您要查询的林中,此方法将不起作用。这是因为
LDAP://RootDSE
将查询计算机域的信息

有人可能会问:为什么这么复杂?只需在检索到的第一个点之前使用名称:

ActiveDirectory.Domain.GetComputerDomain().Name;
或者只获取用户的域名:

Environment.GetEnvironmentVariable("USERDOMAIN");

但是NETBIOS域名可能完全不同,您或您的计算机可能位于不同的域或林中!因此,这种方法只能在简单的环境中使用

解决方案只需要一个小的修改就可以允许跨域查询。这是一种信任关系

private string GetNetbiosDomainName(string dnsDomainName)
{
      string netbiosDomainName = string.Empty;

      DirectoryEntry rootDSE = new DirectoryEntry(string.Format("LDAP://{0}/RootDSE",dnsDomainName));

      string configurationNamingContext = rootDSE.Properties["configurationNamingContext"][0].ToString();

      DirectoryEntry searchRoot = new DirectoryEntry("LDAP://cn=Partitions," + configurationNamingContext);

      DirectorySearcher searcher = new DirectorySearcher(searchRoot);
      searcher.SearchScope = SearchScope.OneLevel;
      searcher.PropertiesToLoad.Add("netbiosname");
      searcher.Filter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", dnsDomainName);

      SearchResult result = searcher.FindOne();

      if (result != null)
      {
        netbiosDomainName = result.Properties["netbiosname"][0].ToString();
      }

      return netbiosDomainName;
    }
您还可以使用API,它将为您完成所有的胡闹。如果您查询的域是本地计算机,它还会缓存调用,甚至不会访问网络

如果您对

使用:

p/调用:

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

[Flags]
private enum DSGETDCNAME_FLAGS : uint
{
    DS_FORCE_REDISCOVERY = 0x00000001,
    DS_DIRECTORY_SERVICE_REQUIRED = 0x00000010,
    DS_DIRECTORY_SERVICE_PREFERRED = 0x00000020,
    DS_GC_SERVER_REQUIRED = 0x00000040,
    DS_PDC_REQUIRED = 0x00000080,
    DS_BACKGROUND_ONLY = 0x00000100,
    DS_IP_REQUIRED = 0x00000200,
    DS_KDC_REQUIRED = 0x00000400,
    DS_TIMESERV_REQUIRED = 0x00000800,
    DS_WRITABLE_REQUIRED = 0x00001000,
    DS_GOOD_TIMESERV_PREFERRED = 0x00002000,
    DS_AVOID_SELF = 0x00004000,
    DS_ONLY_LDAP_NEEDED = 0x00008000,
    DS_IS_FLAT_NAME = 0x00010000,
    DS_IS_DNS_NAME = 0x00020000,
    DS_RETURN_DNS_NAME = 0x40000000,
    DS_RETURN_FLAT_NAME = 0x80000000
}

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

[DllImport("Netapi32.dll")]
private static extern int NetApiBufferFree(
    [In] IntPtr buffer);

private const int ERROR_SUCCESS = 0;

你应该以问答的形式写这篇文章,或者(可能)你的改进答案应该与原始问题一致。我的编辑请求被拒绝,因为“原始帖子中的编辑更改太多”将其作为单独的答案发布。具有更多代表性的人应该能够在以后合并它们。NetBIOS垃圾现在和永远被掩埋的另一个很好的原因是,最终让DNS这么做。这是如上所述的工作方式,但我必须做一个更改:结构“DomainControllerInfo”应该是一个类。“Marshal.PtrToStructure”方法强制执行它。
internal static string GetNetbiosNameForDomain(string dns)
{
    IntPtr pDomainInfo;
    int result = DsGetDcName(null, dns, IntPtr.Zero, null,
        DSGETDCNAME_FLAGS.DS_IS_DNS_NAME | DSGETDCNAME_FLAGS.DS_RETURN_FLAT_NAME,
        out pDomainInfo);
    try
    {
        if (result != ERROR_SUCCESS)
            throw new Win32Exception(result);

        var dcinfo = new DomainControllerInfo();
        Marshal.PtrToStructure(pDomainInfo, dcinfo);

        return dcinfo.DomainName;
    }
    finally
    {
        if (pDomainInfo != IntPtr.Zero)
            NetApiBufferFree(pDomainInfo);
    }
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private class DomainControllerInfo
{
    public string DomainControllerName;
    public string DomainControllerAddress;
    public int DomainControllerAddressType;
    public Guid DomainGuid;
    public string DomainName;
    public string DnsForestName;
    public int Flags;
    public string DcSiteName;
    public string ClientSiteName;
}

[Flags]
private enum DSGETDCNAME_FLAGS : uint
{
    DS_FORCE_REDISCOVERY = 0x00000001,
    DS_DIRECTORY_SERVICE_REQUIRED = 0x00000010,
    DS_DIRECTORY_SERVICE_PREFERRED = 0x00000020,
    DS_GC_SERVER_REQUIRED = 0x00000040,
    DS_PDC_REQUIRED = 0x00000080,
    DS_BACKGROUND_ONLY = 0x00000100,
    DS_IP_REQUIRED = 0x00000200,
    DS_KDC_REQUIRED = 0x00000400,
    DS_TIMESERV_REQUIRED = 0x00000800,
    DS_WRITABLE_REQUIRED = 0x00001000,
    DS_GOOD_TIMESERV_PREFERRED = 0x00002000,
    DS_AVOID_SELF = 0x00004000,
    DS_ONLY_LDAP_NEEDED = 0x00008000,
    DS_IS_FLAT_NAME = 0x00010000,
    DS_IS_DNS_NAME = 0x00020000,
    DS_RETURN_DNS_NAME = 0x40000000,
    DS_RETURN_FLAT_NAME = 0x80000000
}

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

[DllImport("Netapi32.dll")]
private static extern int NetApiBufferFree(
    [In] IntPtr buffer);

private const int ERROR_SUCCESS = 0;