AD 搜索和属性以及字典使用

发布于 2024-12-19 18:10:32 字数 7165 浏览 0 评论 0原文

为了确定计算机帐户是否是孤立的,我想查询所有受信任域的所有域控制器以检索所有计算机的lastLogon 和lastLogonTimeStamp。我有一个可以运行的程序(至少在我的测试环境中),但我有几个问题,希望您能够回答。

  1. 我使用的方法是否尽可能使用最少的资源(网络/域控制器 CPU 和 RAM)来查找域和域控制器,然后检索 AD 信息?如何改进它们?

  2. 字典键/值对中是否可以有超过 1 个值? 拥有一个 LastLogIn 字典和一个不同的 LastLogInTimestamp 字典似乎是一种浪费。

  3. 参考字典和 AD 属性:与使用 Try / Catch 不同,如何检查不存在的值?

    尝试一下 { // 这个 DC 电流比上一个更大吗? if (dict_LastLogIn[pc] < (long)result.Properties["lastlogon"][0]) { dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0]; } } 抓住 { // 该项目尚不存在.. 尝试 { dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0]; } 抓住 { // .. 或者 // 没有最后一次LastLogin... dict_LastLogIn[pc] = 0; } }

是完整的代码:

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;


namespace dictionary
{
    class Program
    {
        internal static Dictionary<string, long> dict_LastLogIn =
            new Dictionary<string, long>();
        internal static Dictionary<string, long> dict_LastLogInTimeStamp =
            new Dictionary<string, long>();
        internal static Dictionary<string, DateTime> output =
            new Dictionary<string, DateTime>();

        internal static bool AreAllDCsResponding = true;

        static void Main(string[] args)
        {
            Console.BufferWidth = 150;
            Console.BufferHeight = 9999;
            Console.WindowWidth = 150;

            Dictionary<String, int> dict_domainList = new Dictionary<String, int>();
            Dictionary<String, int> dict_dcList = new Dictionary<String, int>();

            //Get the current domain's trusts.
            Domain currentDomain = Domain.GetCurrentDomain();
            Console.WriteLine("Retrieved the current Domain as {0}", currentDomain.ToString());
            var domainTrusts = currentDomain.GetAllTrustRelationships();
            Console.WriteLine("  {0} trusts were found.", domainTrusts.Count);
            //Add the current domain to the dictonary.  It won't be in domainTrusts!
            dict_domainList.Add(currentDomain.ToString(), 0);
            // Then add the other domains to the dictonary...
            foreach (TrustRelationshipInformation trust in domainTrusts)
            {
                dict_domainList.Add(trust.TargetName.Substring(0, trust.TargetName.IndexOf(".")).ToUpper(), 0);
                Console.WriteLine("    Adding {0} to the list of trusts.", trust.TargetName.Substring(0, trust.TargetName.IndexOf(".")).ToUpper());
            }
            // Now get all DCs per domain
            foreach (var pair in dict_domainList)
            {
                DirectoryContext dc = new DirectoryContext(DirectoryContextType.Domain, pair.Key);
                Domain _Domain = Domain.GetDomain(dc);
                foreach (DomainController Server in _Domain.DomainControllers)
                {
                    dict_dcList.Add(Server.Name, 0);
                    Console.WriteLine("      Adding {0} to the list of DCs.", Server.Name.ToUpper());

                }
                // Now search through every DC
                foreach (var _pair in dict_dcList)
                {
                    Console.WriteLine("        Querying {0} for Computer objects.", _pair.Key.ToUpper());
                    Search(pair.Key);
                    Console.WriteLine("\n");
                    Console.WriteLine("The following Computer objects were found:");
                }

                if (AreAllDCsResponding == true)
                {
                    ConvertTimeStamp(dict_LastLogIn);
                }
                else
                {
                    ConvertTimeStamp(dict_LastLogInTimeStamp);
                }
                Console.ReadLine();
            }
        }

        internal static void Search(string domainName)
        {
            DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName);
            DirectorySearcher mySearcher = new DirectorySearcher(entry);
            mySearcher.Filter = ("(&(ObjectCategory=computer))");//(lastlogon=*)(lastlogonTimeStamp=*))");
            mySearcher.SizeLimit = int.MaxValue;
            mySearcher.PropertiesToLoad.Add("DistinguishedName");
            mySearcher.PropertiesToLoad.Add("lastlogon");
            mySearcher.PropertiesToLoad.Add("lastlogonTimeStamp");
            try
            {
                foreach (System.DirectoryServices.SearchResult result in mySearcher.FindAll())
                {
                    string pc = result.Properties["DistinguishedName"][0].ToString();
                    try
                    {   // Is this DC more current than the last?
                        if (dict_LastLogIn[pc] < (long)result.Properties["lastlogon"][0])
                        {
                            dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
                        }
                    }
                    catch
                    {   // The item doesn't exist yet..
                        try
                        {
                            dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
                        }
                        catch
                        {   // .. or
                            // There is no last LastLogin...
                            dict_LastLogIn[pc] = 0;
                        }
                    }

                    try
                    {
                        // Not yet replicated?...
                        if (dict_LastLogInTimeStamp[pc] < (long)result.Properties["lastlogonTimeStamp"][0])
                        {
                            dict_LastLogInTimeStamp[pc] = (long)result.Properties["lastlogonTimeStamp"][0];
                        }
                    }
                    catch
                    {   // The item doesn't exist yet..
                        try
                        {
                            dict_LastLogInTimeStamp[pc] = (long)result.Properties["lastlogonTimeStamp"][0];
                        }
                        catch
                        {   // .. or
                            // There is no last LastLoginTimeStamp...
                            dict_LastLogInTimeStamp[pc] = 0;
                        }
                    }
                }
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                //If even one DC doesn't answer, don't use LastLogon!  
                //Use the less accurate, but replicated(!) LastLogonTimeStamp. 
                AreAllDCsResponding = false;
            }
        }

        internal static void ConvertTimeStamp(Dictionary<string, long> _dict)
        {
            foreach (var pair in _dict)
            {
                output.Add(pair.Key, DateTime.FromFileTime(pair.Value));
                Console.WriteLine("{0} - {1}", pair.Key, DateTime.FromFileTime(pair.Value));
            }
        }
    }
}

感谢您提供的任何帮助。

In order to determine if computer accounts are orphaned, I would like to query all domain controllers of all trusted domains to retrieve the lastLogon and lastLogonTimeStamp for all computers. I have a program that works (at least in my test environment), but I have a few questions, that I hope you might be able to answer.

  1. Are the methods I’m using to find the domains and domain controllers and then retrieve the AD information, using the least amount of resources (network / domain controller CPU and RAM) as possible? How could they be improved?

  2. Is it possible to have more than 1 value in a dictionary key / value pair?
    Having a dictionary for LastLogIn and a different one for LastLogInTimestamp seems a waste.

  3. Referring to the dictionary and the AD properties: How can I check for non-existent values as opposed to using Try / Catch?

    try
    { // Is this DC more current than the last?
    if (dict_LastLogIn[pc] < (long)result.Properties["lastlogon"][0])
    {
    dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
    }
    }
    catch
    { // The item doesn't exist yet..
    try
    {
    dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
    }
    catch
    { // .. or
    // There is no last LastLogin...
    dict_LastLogIn[pc] = 0;
    }
    }

Here the entire code:

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;


namespace dictionary
{
    class Program
    {
        internal static Dictionary<string, long> dict_LastLogIn =
            new Dictionary<string, long>();
        internal static Dictionary<string, long> dict_LastLogInTimeStamp =
            new Dictionary<string, long>();
        internal static Dictionary<string, DateTime> output =
            new Dictionary<string, DateTime>();

        internal static bool AreAllDCsResponding = true;

        static void Main(string[] args)
        {
            Console.BufferWidth = 150;
            Console.BufferHeight = 9999;
            Console.WindowWidth = 150;

            Dictionary<String, int> dict_domainList = new Dictionary<String, int>();
            Dictionary<String, int> dict_dcList = new Dictionary<String, int>();

            //Get the current domain's trusts.
            Domain currentDomain = Domain.GetCurrentDomain();
            Console.WriteLine("Retrieved the current Domain as {0}", currentDomain.ToString());
            var domainTrusts = currentDomain.GetAllTrustRelationships();
            Console.WriteLine("  {0} trusts were found.", domainTrusts.Count);
            //Add the current domain to the dictonary.  It won't be in domainTrusts!
            dict_domainList.Add(currentDomain.ToString(), 0);
            // Then add the other domains to the dictonary...
            foreach (TrustRelationshipInformation trust in domainTrusts)
            {
                dict_domainList.Add(trust.TargetName.Substring(0, trust.TargetName.IndexOf(".")).ToUpper(), 0);
                Console.WriteLine("    Adding {0} to the list of trusts.", trust.TargetName.Substring(0, trust.TargetName.IndexOf(".")).ToUpper());
            }
            // Now get all DCs per domain
            foreach (var pair in dict_domainList)
            {
                DirectoryContext dc = new DirectoryContext(DirectoryContextType.Domain, pair.Key);
                Domain _Domain = Domain.GetDomain(dc);
                foreach (DomainController Server in _Domain.DomainControllers)
                {
                    dict_dcList.Add(Server.Name, 0);
                    Console.WriteLine("      Adding {0} to the list of DCs.", Server.Name.ToUpper());

                }
                // Now search through every DC
                foreach (var _pair in dict_dcList)
                {
                    Console.WriteLine("        Querying {0} for Computer objects.", _pair.Key.ToUpper());
                    Search(pair.Key);
                    Console.WriteLine("\n");
                    Console.WriteLine("The following Computer objects were found:");
                }

                if (AreAllDCsResponding == true)
                {
                    ConvertTimeStamp(dict_LastLogIn);
                }
                else
                {
                    ConvertTimeStamp(dict_LastLogInTimeStamp);
                }
                Console.ReadLine();
            }
        }

        internal static void Search(string domainName)
        {
            DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName);
            DirectorySearcher mySearcher = new DirectorySearcher(entry);
            mySearcher.Filter = ("(&(ObjectCategory=computer))");//(lastlogon=*)(lastlogonTimeStamp=*))");
            mySearcher.SizeLimit = int.MaxValue;
            mySearcher.PropertiesToLoad.Add("DistinguishedName");
            mySearcher.PropertiesToLoad.Add("lastlogon");
            mySearcher.PropertiesToLoad.Add("lastlogonTimeStamp");
            try
            {
                foreach (System.DirectoryServices.SearchResult result in mySearcher.FindAll())
                {
                    string pc = result.Properties["DistinguishedName"][0].ToString();
                    try
                    {   // Is this DC more current than the last?
                        if (dict_LastLogIn[pc] < (long)result.Properties["lastlogon"][0])
                        {
                            dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
                        }
                    }
                    catch
                    {   // The item doesn't exist yet..
                        try
                        {
                            dict_LastLogIn[pc] = (long)result.Properties["lastlogon"][0];
                        }
                        catch
                        {   // .. or
                            // There is no last LastLogin...
                            dict_LastLogIn[pc] = 0;
                        }
                    }

                    try
                    {
                        // Not yet replicated?...
                        if (dict_LastLogInTimeStamp[pc] < (long)result.Properties["lastlogonTimeStamp"][0])
                        {
                            dict_LastLogInTimeStamp[pc] = (long)result.Properties["lastlogonTimeStamp"][0];
                        }
                    }
                    catch
                    {   // The item doesn't exist yet..
                        try
                        {
                            dict_LastLogInTimeStamp[pc] = (long)result.Properties["lastlogonTimeStamp"][0];
                        }
                        catch
                        {   // .. or
                            // There is no last LastLoginTimeStamp...
                            dict_LastLogInTimeStamp[pc] = 0;
                        }
                    }
                }
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                //If even one DC doesn't answer, don't use LastLogon!  
                //Use the less accurate, but replicated(!) LastLogonTimeStamp. 
                AreAllDCsResponding = false;
            }
        }

        internal static void ConvertTimeStamp(Dictionary<string, long> _dict)
        {
            foreach (var pair in _dict)
            {
                output.Add(pair.Key, DateTime.FromFileTime(pair.Value));
                Console.WriteLine("{0} - {1}", pair.Key, DateTime.FromFileTime(pair.Value));
            }
        }
    }
}

Thanks for any help you can offer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蹲在坟头点根烟 2024-12-26 18:10:32

在较高的层面上,我不确定你的最终结果是什么,但是,你确定你真的想查询每个 DC 的 lastLogon 吗?这可能真的很贵。另外,你为什么走信任链?您确定不只想要给定林 (Forest.Domains) 中的所有域吗?

回答您的问题:

  1. 这看起来不错,但是您应该做几件事:

    • 将过滤器调整为 (&(objectCategory=computer)(objectClass=computer))
    • 添加mySearcher.PageSize = 1000
    • 删除mySearcher.SizeLimit = int.MaxValue
  2. 您可以使用Tuple - http://msdn.microsoft.com/en-us/库/system.tuple(VS.90).aspx。或者只是定义一个自定义类作为您的值,然后将 Dictionary 声明为您的字典:

    公共类 LogonTimeStamps
    {

    公共长LastLogon {获取;放; }

    public long LastLogonTimeStamp { 获取;放; }

    }

  3. 对于字典,请使用myDictionary.ContainsKey(yourKey)。对于 AD,您应该能够使用 result.Properties.Contains("yourAttribute")

At a high level, I'm not sure what your end-game is with this, but, are you sure you really want to query every single DC for lastLogon? This could be really expensive. Also, why are you walking trust chains? Are you sure you don't just want all the domains in a given Forest (Forest.Domains)?

In answer to your questions:

  1. This looks OK perf-wise, however you should do a couple things:

    • Tweak your filter to (&(objectCategory=computer)(objectClass=computer))
    • Add mySearcher.PageSize = 1000
    • Remove mySearcher.SizeLimit = int.MaxValue
  2. You could use a Tuple - http://msdn.microsoft.com/en-us/library/system.tuple(VS.90).aspx. Or just define a custom class as your value and then declare Dictionary as your dictionary:

    public class LogonTimeStamps
    {

    public long LastLogon { get; set; }

    public long LastLogonTimeStamp { get; set; }

    }

  3. For the Dictionary, use myDictionary.ContainsKey(yourKey). For AD, you should be able to use result.Properties.Contains("yourAttribute").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文