26

私はこの種の質問が以前に尋ねられたことを知っていますが、他の方法が今私を失敗させています。

現状では、LDAP(つまり、LDAP://10.32.16.80)と、検索するADサーバー内のユーザーグループのリストを指定して、WindowsサービスがADをポーリングします。それらの指定されたグループ内のすべてのユーザーを取得し、それらのグループでさらに多くのグループを繰り返し検索します。次に、各ユーザーは別のアプリケーション認証済みユーザーリストに追加されます。

アプリケーションのこの部分は正常に実行されています。ただし、各ユーザーのわかりやすいドメイン名(つまり、ログインドメイン/ユーザー名の一部)が必要です。

したがって、TESTドメインの一部であるSteveという名前のユーザーがいる場合:TEST/steveが彼のログインです。ADでスティーブを見つけることができますが、彼のAD情報と一緒に「TEST」を保存する必要もあります。

繰り返しになりますが、ディレクトリサーチャーと指定されたLDAP IPを使用して「スティーブ」を正常に見つけることができますが、LDAP IPが与えられた場合、フレンドリドメイン名を見つけるにはどうすればよいですか?

次のコードを試してみると、「defaultNamingContext」にアクセスしようとするとエラーが発生します。

System.Runtime.InteropServices.COMException(0x8007202A):認証メカニズムが不明です。

コードは次のとおりです。

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

編集

提案を試みるためにこのサンプルメソッドを追加しましたが、サーチャーで「FindAll()」呼び出しを押すと「不特定のエラー」という例外が発生します。渡される文字列は次のとおりです: "CN = TEST USER、CN = Users、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;
4

4 に答える 4

29

この記事は、Active Directory の操作方法を理解するのに大いに役立ちました。
Howto: (Almost) Everything In Active Directory via C#

これ以降、さらにサポートが必要な場合は、コメントで適切な質問をお知らせください。私の知る限りお答えします。

編集#1

代わりに、この例のフィルターを使用することをお勧めします。System.DirectoryServicesSystem.DirectoryServices.ActiveDirectory名前空間の操作方法を簡単に示すサンプル コードをいくつか作成しました。System.DirectoryServices.ActiveDirectory名前空間は、フォレスト内のドメインに関する情報を取得するために使用されます。

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

ここでは、このコードをテストしていないため、修正が必要な軽微な問題がある可能性があります。このサンプルは、お客様を支援するために現状のまま提供されています。これが役立つことを願っています。

編集#2

私は別の方法を見つけました:

  1. まず、ドメイン内でユーザー アカウントを見つけることができるかどうかを確認する必要があります。
  2. 見つかった場合は、ドメインの NetBIOS 名を取得します。と
  3. バックスラッシュ (****) と見つかったログインに連結します。

以下の例では、NUnit TestCaseを使用しています。これは、自分でテストして、要求どおりに動作するかどうかを確認できます。

[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())
}

私がインスピレーションを得たソースは次のとおりです。
AD でドメインの NetBios 名を検索する

于 2010-11-22T19:30:18.487 に答える
6

Environment.UserDomainName プロパティを使用して、現在のユーザーが所属しているドメインの名前を取得できます。

string domainName;
domainName = System.Environment.UserDomainName;
于 2012-10-10T12:47:45.893 に答える
2

完全に正解ではないかもしれませんが...

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

de.Path の値は

LDAP://CN=フルネーム、DC=ドメイン、DC=ローカル

于 2016-03-01T13:20:08.223 に答える