2013-01-02 4 views
11

L'acquisizione del nome di dominio NETBIOS da un nome di dominio di Active Directory completamente qualificato è talvolta un'operazione noiosa. Ho trovato una buona risposta here.Come ottenere il nome dominio NETBIOS utilizzando l'FQDN in un ambiente complesso

In un ambiente con più foreste questo approccio tuttavia non funzionerà se il PC non si trova nella foresta che si sta interrogando. Questo perché LDAP://RootDSE interrogherà le informazioni per il dominio del computer.

Alcuni potrebbero chiedere: perché così complicato? Basta usare il nome prima del primo punto recuperato da:

ActiveDirectory.Domain.GetComputerDomain().Name; 

O semplicemente ottenere il nome di dominio dell'utente:

Environment.GetEnvironmentVariable("USERDOMAIN"); 

o

Environment.UserDomainName; 

ma il nome di dominio NetBIOS può essere qualcosa di completamente diverso, e tu o il tuo computer potrebbe essere in un dominio o una foresta diversi! Quindi questo approccio è utilizzabile solo in un ambiente semplice.

DJ KRAZE’s soluzione richiede solo una piccola modifica per consentire query tra domini. Questo presuppone una relazione di fiducia!

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

Si dovrebbe scrivere questo in Q & A formato, o (forse) la tua risposta migliorata dovrebbe andare con la domanda originale. –

+0

La mia richiesta di modifica è stata rifiutata perché "La modifica cambia troppo nel post originale" – Daro

+0

Pubblicalo come risposta separata. Qualcuno con più rappresentanti dovrebbe essere in grado di unirli in seguito. –

risposta

8

È anche possibile utilizzare la DsGetDcName API, che farà tutto il monkeying intorno per voi. Memorizza anche le chiamate e non colpisce nemmeno la rete se il dominio che stai interrogando è il computer locale.

Se si dispone di ulteriori requisiti sulle capacità del

Usa:

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

Funziona come descritto, ma ho dovuto apportare una modifica: la struttura 'DomainControllerInfo' avrebbe dovuto essere una classe. Il metodo "Marshal.PtrToStructure" lo richiedeva. –