Je sais que ce type de question a déjà été posé, mais d’autres méthodes me manquent actuellement.
Dans l'état actuel des choses, notre service Windows interroge AD, à l'aide d'un LDAP (c.-à-d. LDAP: //10.32.16.80) et d'une liste de groupes d'utilisateurs au sein de ce serveur AD à rechercher .. .. Il extrait tous les utilisateurs de ces groupes, en effectuant une recherche récursive sur ceux-ci. groupes pour plus de groupes aussi . Chaque utilisateur est ensuite ajouté à une autre liste d'utilisateurs authentifiés par applications.
Cette partie de l'application s'exécute avec succès. Cependant, nous avons besoin du nom de domaine convivial de chaque utilisateur (c'est-à-dire la partie de son nom d'utilisateur DOMAIN/login).
Donc, s’il ya un utilisateur faisant partie du domaine TEST, nommé Steve: TEST/steve est son identifiant de connexion . Je suis en mesure de trouver steve dans l’AD, mais j’ai aussi besoin que "TEST" soit stocké avec son Informations AD.
Encore une fois, je peux trouver 'steve' fine en utilisant un chercheur d’annuaire et l’adresse IP LDAP qui m’est donnée, mais étant donné l’adresse IP LDAP, comment puis-je trouver le nom de domaine convivial?
Lorsque j'essaie le code suivant, une erreur survient lorsque j'essaie d'accéder au 'defaultNamingContext':
System.Runtime.InteropServices.COMException (0x8007202A): Le mécanisme d'authentification est inconnu.
Voici le code:
private string SetCurrentDomain(string server)
{
string result = string.Empty;
try
{
logger.Debug("'SetCurrentDomain'; Instantiating rootDSE LDAP");
DirectoryEntry ldapRoot = new DirectoryEntry(server + "/rootDSE", username, password);
logger.Debug("'SetCurrentDomain'; Successfully instantiated rootDSE LDAP");
logger.Debug("Attempting to retrieve 'defaultNamingContext'...");
string domain = (string)ldapRoot.Properties["defaultNamingContext"][0]; //THIS IS WHERE I HIT THE COMEXCEPTION
logger.Debug("Retrieved 'defaultNamingContext': " + domain);
if (!domain.IsEmpty())
{
logger.Debug("'SetCurrentDomain'; Instantiating partitions/configuration LDAP entry");
DirectoryEntry parts = new DirectoryEntry(server + "/CN=Partitions,CN=Configuration," + domain, username, password);
logger.Debug("'SetCurrentDomain'; Successfully instantiated partitions/configuration LDAP entry");
foreach (DirectoryEntry part in parts.Children)
{
if (part.Properties["nCName"] != null && (string)part.Properties["nCName"][0] != null)
{
logger.Debug("'SetCurrentDomain'; Found property nCName");
if ((string)part.Properties["nCName"][0] == domain)
{
logger.Debug("'SetCurrentDomain'; nCName matched defaultnamingcontext");
result = (string)part.Properties["NetBIOSName"][0];
logger.Debug("'SetCurrentDomain'; Found NetBIOSName (friendly domain name): " + result);
break;
}
}
}
}
logger.Debug("finished setting current domain...");
}
catch (Exception ex)
{
logger.Error("error attempting to set domain:" + ex.ToString());
}
return result;
}
modifier
J'ai ajouté cet exemple de méthode afin de tenter une suggestion mais j'obtiens une exception: "Erreur non spécifiée" lorsque je clique sur l'appel "FindAll ()" sur le chercheur . La chaîne transmise est: "CN = TEST USER , CN = Utilisateurs, DC = tempe, DC = ktregression, DC = com "
private string GetUserDomain(string dn)
{
string domain = string.Empty;
string firstPart = dn.Substring(dn.IndexOf("DC="));
string secondPart = "CN=Partitions,CN=Configuration," + firstPart;
DirectoryEntry root = new DirectoryEntry(secondPart, textBox2.Text, textBox3.Text);
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.Filter = "(&(nCName=" + firstPart + ")(nETBIOSName=*))";
try
{
SearchResultCollection rs = searcher.FindAll();
if (rs != null)
{
domain = GetProperty(rs[0], "nETBIOSName");
}
}
catch (Exception ex)
{
}
return domain;
Cet article m'a beaucoup aidé à comprendre comment utiliser Active Directory.Howto: (Almost) Everything In Active Directory via C#
À partir de ce moment-là, si vous avez besoin d'aide supplémentaire, merci de me le faire savoir en posant les bonnes questions, et j'y répondrai pour vous au meilleur de ma connaissance.
EDIT # 1
Vous feriez mieux de choisir plutôt le filtre de cet exemple. J'ai écrit quelques exemples de code pour montrer brièvement comment utiliser les System.DirectoryServices
et System.DirectoryServices.ActiveDirectory
namespaces. L'espace de noms System.DirectoryServices.ActiveDirectory permet d'extraire des informations sur les domaines de votre forêt.
private IEnumerable<DirectoryEntry> GetDomains() {
ICollection<string> domains = new List<string>();
// Querying the current Forest for the domains within.
foreach(Domain d in Forest.GetCurrentForest().Domains)
domains.Add(d.Name);
return domains;
}
private string GetDomainFullName(string friendlyName) {
DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, friendlyName);
Domain domain = Domain.GetDomain(context);
return domain.Name;
}
private IEnumerable<string> GetUserDomain(string userName) {
foreach(string d in GetDomains())
// From the domains obtained from the Forest, we search the domain subtree for the given userName.
using (DirectoryEntry domain = new DirectoryEntry(GetDomainFullName(d))) {
using (DirectorySearcher searcher = new DirectorySearcher()){
searcher.SearchRoot = domain;
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
// The Filter is very important, so is its query string. The 'objectClass' parameter is mandatory.
// Once we specified the 'objectClass', we want to look for the user whose login
// login is userName.
searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", userName);
try {
SearchResultCollection results = searcher.FindAll();
// If the user cannot be found, then let's check next domain.
if (results == null || results.Count = 0)
continue;
// Here, we yield return for we want all of the domain which this userName is authenticated.
yield return domain.Path;
} finally {
searcher.Dispose();
domain.Dispose();
}
}
}
Ici, je n'ai pas testé ce code et j'ai peut-être un problème mineur à résoudre. Cet échantillon est fourni en l'état pour vous aider. J'espère que cela aidera.
EDIT # 2
J'ai découvert un autre moyen de sortir:
L'exemple ci-dessous utilise un NUnit TestCase que vous pouvez tester vous-même et voir s'il fait ce qu'il vous est demandé de faire.
[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("FULLY\TESTUSER1", string.Concat(netBiosName, "\", foundLogin).ToUpperInvariant())
}
La source dont je me suis inspiré est:
Trouver le nom NetBios d’un domaine dans AD
N'ayant pu trouver aucun exemple de code, j'aimerais partager ma propre solution. Cela recherchera les parents de l'objet DirectoryEntry jusqu'à ce qu'il atteigne la classe domainDNS.
using System.DirectoryServices;
public static class Methods
{
public static T ldap_get_value<T>(PropertyValueCollection property)
{
object value = null;
foreach (object tmpValue in property) value = tmpValue;
return (T)value;
}
public static string ldap_get_domainname(DirectoryEntry entry)
{
if (entry == null || entry.Parent == null) return null;
using (DirectoryEntry parent = entry.Parent)
{
if (ldap_get_value<string>(parent.Properties["objectClass"]) == "domainDNS")
return ldap_get_value<string>(parent.Properties["dc"]);
else
return ldap_get_domainname(parent);
}
}
}
Utilisez-le comme ceci:
string[] _properties = new string[] { "objectClass", "distinguishedName", "samAccountName", "userPrincipalName", "displayName", "mail", "title", "company", "thumbnailPhoto", "useraccountcontrol" };
string account = "my-user-name";
// OR even better:
// string account = "[email protected]";
using (DirectoryEntry ldap = new DirectoryEntry())
{
using (DirectorySearcher searcher = new DirectorySearcher(ldap))
{
searcher.PropertiesToLoad.AddRange(_properties);
if (account.Contains('@')) searcher.Filter = "(userPrincipalName=" + account + ")";
else searcher.Filter = "(samAccountName=" + account + ")";
var user = searcher.FindOne().GetDirectoryEntry();
Console.WriteLine("Name: " + Methods.ldap_get_value<string>(user.Properties["displayName"]));
Console.WriteLine("Domain: " + Methods.ldap_get_domainname(user));
Console.WriteLine("Login: " + Methods.ldap_get_domainname(user) + "\\" + Methods.ldap_get_value<string>(user.Properties["samAccountName"]));
}
}
Je n'ai pas de forêt pour la tester, mais en théorie, cela devrait suffire.
Vous pouvez récupérer le nom du domaine sur lequel se trouve l'utilisateur actuel à l'aide de la propriété Environment.UserDomainName .
string domainName;
domainName = System.Environment.UserDomainName;
Peut-être pas tout à fait correct mais ...
DirectoryEntry dirEntry = new DirectoryEntry();
DirectorySearcher dirSearcher = new DirectorySearcher(dirEntry);
dirSearcher.SearchScope = SearchScope.Subtree;
dirSearcher.Filter = string.Format("(&(objectClass=user)(|(cn={0})(sn={0}*)(givenName={0})(sAMAccountName={0}*)))", userName);
var searchResults = dirSearcher.FindAll();
foreach (SearchResult sr in searchResults)
{
var de = sr.GetDirectoryEntry();
string user = de.Properties["SAMAccountName"][0].ToString();
string domain = de.Path.ToString().Split(new [] { ",DC=" },StringSplitOptions.None)[1];
MessageBox.Show(domain + "/" + user);
}
Parce que la valeur de de.Path est
LDAP: // CN = Nom complet , DC = domaine , DC = local