2013-01-02 9 views
11

Uzyskanie nazwy domeny NETBIOS z w pełni kwalifikowanej nazwy domeny Active Directory jest czasami żmudnym zadaniem. Znalazłem dobrą odpowiedź here.Jak uzyskać nazwę domeny NETBIOS przy użyciu nazwy FQDN w złożonym środowisku?

W środowisku z wieloma lasami takie podejście nie będzie jednak działać, jeśli komputer nie znajduje się w szukanym lesie. Dzieje się tak, ponieważ LDAP://RootDSE będzie wyszukiwać informacje dotyczące domeny komputera.

Niektórzy mogą zapytać: dlaczego tak skomplikowane? Wystarczy użyć nazwy przed pierwszą kropką pobierane przez:

ActiveDirectory.Domain.GetComputerDomain().Name; 

lub po prostu dostać nazwę domeny użytkownika:

Environment.GetEnvironmentVariable("USERDOMAIN"); 

lub

Environment.UserDomainName; 

ale nazwa NetBIOS domeny może być coś zupełnie inny, a ty lub twój komputer może być w innej domenie lub lesie! Tak więc to podejście jest możliwe do zastosowania tylko w prostym środowisku.

DJ KRAZE’s rozwiązanie wymaga tylko jednej małej modyfikacji, aby umożliwić kwerendy międzydomenowe. Zakłada to związek zaufania!

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; 
    } 
+0

Należy napisać to w Q & A formacie lub (ewentualnie) swój poprawiona odpowiedź powinna iść z pierwotnym pytaniem. –

+0

Moje żądanie edycji zostało odrzucone, ponieważ "Zmiana zbyt wiele w oryginalnym wpisie". – Daro

+0

Opublikuj jako osobną odpowiedź. Ktoś, kto ma więcej przedstawicieli, powinien móc je później scalić. –

Odpowiedz

8

Można również użyć DsGetDcName API, który zrobi wszystko monkeying wokół dla Ciebie. Będzie również buforował połączenia, a nawet nie trafi do sieci, jeśli domena, której dotyczy zapytanie, jest komputerem lokalnym.

Jeśli masz dodatkowe wymagania dotyczące zdolności do

użytku:

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); 
    } 
} 

P/Invoke:

[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; 
+2

Działa to jak opisano, ale musiałem dokonać jednej zmiany: struct "DomainControllerInfo" powinny być klasy. Metoda "Marshal.PtrToStructure" nakazała to. –

Powiązane problemy