Jump to content

Hello everyone! I'm a beginner C# programmer. I work as a Junior IT Engineer in a pretty big company. My manager asked me some time ago to create a program that will search our Active Directory for users that password expires within 14, 7 and 1 day and send an e-mail to those people with the information about it and with instructions of how to do that. So I searched for a solution in the internet and found a source code of a program that will do everything that I need it to do, at least I thought so... When I run the program everything looks nice, but if you look closer I'm getting weird pwdLastSet values. 

 

This is how it should look so the program is able to calculate the number of days until the password expiration:

PassExpNot - good.png

 

And this is how it looks for some accounts even thought I personally changed the password for this particular account a month ago from within our Domain Controller:

PassExpNot - bad.png

Here is the code:

Spoiler

using System;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using ActiveDs;
using System.IO;
using System.Net.Mail;


namespace PasswordNotifcation
{

    class Program
    {
        const int ADS_SCRIPT = 0x0001;
        const int ADS_ACCOUNTDISABLE = 0x0002;
        const int ADS_HOMEDIR_REQUIRED = 0x0008;
        const int ADS_LOCKOUT = 0x0010;
        const int ADS_PASSWD_NOTREQD = 0x0020;
        const int ADS_PASSWD_CANT_CHANGE = 0x0040;
        const int ADS_ENCRYPTED_TEXT_PWD_ALLOWED = 0x0080;
        const int ADS_TEMP_DUPLICATE_ACCOUNT = 0x0100;
        const int ADS_NORMAL_ACCOUNT = 0x0200;
        const int ADS_INTERDOMAIN_TRUST_ACCOUNT = 0x0800;
        const int ADS_WORKSTATION_TRUST_ACCOUNT = 0x1000;
        const int ADS_SERVER_TRUST_ACCOUNT = 0x2000;
        const int ADS_DONT_EXPIRE_PASSWORD = 0x10000;
        const int ADS_MNS_LOGON_ACCOUNT = 0x20000;
        const int ADS_SMARTCARD_REQUIRED = 0x40000;
        const int ADS_TRUSTED_FOR_DELEGATION = 0x80000;
        const int ADS_NOT_DELEGATED = 0x100000;
        const int ADS_USE_DES_KEY_ONLY = 0x200000;
        const int ADS_DONT_REQ_PREAUTH = 0x400000;
        const int ADS_PASSWORD_EXPIRED = 0x800000;
        const int ADS_TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000;




        //public static void SendMailMessage(string ToAddress, string FromAddress, string MessageSubject, string MessageText, string ToCC, string ToBCC, string MailServer)
        //{
        //    MailMessage mail = new MailMessage(FromAddress, ToAddress, MessageSubject, MessageText);
        //    SmtpClient cli = new SmtpClient();
        //    cli.Host = MailServer;
        //    cli.Send(mail);
        //}



        static void Main(string[] args)
        {
            
            try
            {

                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

                doc.Load(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"\settings.config");

                System.Xml.XmlNodeList nl = doc.SelectNodes("//Warning");



                System.Xml.XmlNode nodtmp = doc.SelectSingleNode("//StartingOU");
                string strStartingOU = nodtmp.Attributes["Value"].Value;


                nodtmp = doc.SelectSingleNode("//SmtpServer");
                string strSmtpServer = nodtmp.Attributes["Value"].Value;

                nodtmp = doc.SelectSingleNode("//MailFrom");
                string strEmailFrom = nodtmp.Attributes["Value"].Value;

                string userNameEditStringForProcessing = string.Empty;

                TimeSpan tsMaxPasswordAge = GetMaxPasswordAge();
                int iMaxPwdAge = tsMaxPasswordAge.Days;

                

                DirectoryEntry objDirEnt = new DirectoryEntry(strStartingOU);

                DirectorySearcher ds = new DirectorySearcher(objDirEnt);
                SearchResultCollection src = null;
                

                ds.Filter = "(objectClass=user)";
                src = ds.FindAll();

              

                if (src.Count > 0)
                {

                    foreach (SearchResult sr in src)
                    {
                        DirectoryEntry UserEntry = sr.GetDirectoryEntry();

                       if (sr.GetDirectoryEntry().Properties["mail"].Value != null)
                       {
                            if (UserEntry.Name.StartsWith("CN="))
                            {
                                userNameEditStringForProcessing = UserEntry.Name.Remove(0, "CN=".Length);
                                WriteLogMessage("Processing:" + userNameEditStringForProcessing);
                                WriteLogMessage("Max Password Age:" + iMaxPwdAge);
                                WriteLogMessage("E-mail: " + sr.GetDirectoryEntry().Properties["mail"].Value.ToString());
                                //WriteLogMessage("Password never expires for: " + userNameEditStringForProcessing);
                            }
                            else
                            {
                                WriteLogMessage("Processing:" + UserEntry.Name);
                                WriteLogMessage("E-mail address was not found for: " + UserEntry.Name);
                                WriteLogMessage("Max Password Age:" + iMaxPwdAge);
                                //WriteLogMessage("E-mail: " + sr.GetDirectoryEntry().Properties["mail"].Value.ToString());
                            }
                           
                           

                        

                        //Console.WriteLine("Account control:" + UserEntry.Properties["userAccountcontrol"].Value);

                        int userAccountControl = Convert.ToInt32(UserEntry.Properties["userAccountcontrol"].Value);
                        string userNameEditString = string.Empty;   

                        if ((userAccountControl & ADS_DONT_EXPIRE_PASSWORD) > 0)
                        {
                                if (UserEntry.Name.StartsWith("CN="))
                                {
                                    userNameEditString = UserEntry.Name.Remove(0, "CN=".Length);
                                    
                                    WriteLogMessage("Password never expires for: " + userNameEditString);
                                }
                                else
                                {
                                    //userNameEditString = UserEntry.Name;
                                    WriteLogMessage("Password never expires for: " + userNameEditString);
                                }
                                
                        }
                        else
                        {
                                if (UserEntry.Name.StartsWith("CN="))
                                {
                                    //userNameEditString = UserEntry.Name.Remove(0, "CN=".Length);
                                    WriteLogMessage("Password expiration date for: " + UserEntry.Name.Remove(0, "CN=".Length) + " was found!");                                 
                                }
                                else
                                {
                                    WriteLogMessage("Password expiration date for: " + UserEntry.Name + " was found!");
                                }
                               

                            IADsUser native = (IADsUser)UserEntry.NativeObject;

                            DateTime passwordLastChanged = new DateTime(9999, 1, 1);
                            try
                            {
                                passwordLastChanged = native.PasswordLastChanged;
                            }

                            catch { }
                            string strEmailTo = "";
                            try
                            {
                                strEmailTo = native.EmailAddress;
                            }
                            catch { };

                            if (passwordLastChanged != null)
                                {
                                    WriteLogMessage("Password last changed date: " + passwordLastChanged.ToString());
                                }
                                else
                                {
                                    WriteLogMessage("Password last changed date was not found.");
                                }
                            

                            if (passwordLastChanged.Year != 9999)
                            {
                                DateTime expireDate = passwordLastChanged.AddDays(iMaxPwdAge);

                                TimeSpan ts = expireDate - DateTime.Now;

                                int iDaysTilExpired = ts.Days;

                                WriteLogMessage("Time(in days) untill password expire: " + iDaysTilExpired);


                                foreach (System.Xml.XmlNode nod in nl)
                                {
                                    int iDays = Convert.ToInt32(nod.Attributes["Days"].Value);


                                    if (iDays == iDaysTilExpired)
                                    {

                                        if (strEmailTo != "")
                                        {

                                            string strSubject = nod.Attributes["Subject"].Value;
                                            string strTemplatePath = nod.Attributes["Template"].Value;


                                            using (TextReader streamReader = new StreamReader(strTemplatePath))
                                            {
                                                string strContents = streamReader.ReadToEnd();
                                                    strContents.Replace("%%NAME%%", userNameEditString);

                                                    //strContents = strContents.Replace("%%days%%", iDays.ToString());

                                                    Console.WriteLine("Sending email to: " + strEmailTo);
                                                    Console.WriteLine("Sending email to: " + userNameEditString + " " + strEmailTo);
                                                    //SendMailMessage(strEmailTo, strEmailFrom, strSubject, strContents, "", "", strSmtpServer);
                                                    WriteLogMessage("Email sent to: " + userNameEditString + " " + strEmailTo);

                                                }
                                        }
                                        else
                                        {
                                            WriteLogMessage("E-mail address field is blank. E-mail will not be sent.");
                                        }

                                    }
                                }
                            }
                            else
                            {
                                //WriteLogMessage("Password last changed date was not found.");

                            }
                        }
                        }
                        else
                        {
                            //WriteLogMessage("-=Specified account is not a user account=-");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WriteLogMessage("Error -- Exception thrown: " + ex.ToString());
            }

        }

        static private void WriteLogMessage(string Message)
        {
            Console.WriteLine(Message);
            StreamWriter sw = new StreamWriter(@"log" + DateTime.Now.ToString("d-MM-yyyy") + ".txt", true);
            DateTime dtTimestamp = DateTime.Now;

            string strLine = dtTimestamp.Day + "-" + dtTimestamp.Month + "-" + dtTimestamp.Year + " " + dtTimestamp.Hour + ":" + dtTimestamp.Minute + ":" + dtTimestamp.Second + "." + dtTimestamp.Millisecond + "\t";
            strLine += Message;

            sw.WriteLine(strLine);
            sw.Flush();
            sw.Close();

        }


        public static TimeSpan GetMaxPasswordAge()
        {
            using (Domain d = Domain.GetCurrentDomain())
            using (DirectoryEntry domain = d.GetDirectoryEntry())
            {
                DirectorySearcher ds = new DirectorySearcher(domain,"(objectClass=*)",null,SearchScope.Base);
                SearchResult sr = ds.FindOne();
                TimeSpan maxPwdAge = TimeSpan.MinValue;
                if (sr.Properties.Contains("maxPwdAge"))
                    maxPwdAge = TimeSpan.FromTicks((long)sr.Properties["maxPwdAge"][0]);
                return maxPwdAge.Duration();
            }
        }

    }
}

 

 

Does anyone know why am I getting this weird password last changed date(01-Jan-99 00:00:00)? Oh, and don't bother about the SendMailMessage class I have to modify it. As I said I found this code somewhere in the internet and I'm only modifying it. It is not my code. I will be glad for any help.

Main Rig - AMD Ryzen 1800X @ 3.9 - NZXT Kraken X62 - MSI X370 SLI PLUS - G.Skill TRIDENT Z RGB 16GB 2667MHz - 2 x Gigabyte GeForce GTX1080 WindForce OC - NZXT S340 (Purple-White) - OCZ 120GB, Seagate 1TB - Corsair RM750i 80+ Gold - SAMSUNG S24D590 24", HP L1950g - Logitech G810 Orion Spectrum - Logitech G502 Proteus Spectrum - Creative Cambridge Sound Works + two random Philips speakers, Logitech G430 headset - Win 10 Pro x64

Retro Gaming PC - ASUS T3

Server - HP ProLiant DL380 G6(Currently assembling it) - 2 x Intel Xeon E5520 2.26GHz 8MB Quad Core Processor

NAS - Zyxel NSA320S 2 x Seagate Constellation ES 2TB(RAID1) - QNAP TS-212 1 x 500GB

 

-=Logitech FanBoiiiiiiii=-

I love NZXT as well <3

Link to comment
https://linustechtips.com/topic/594873-c-password-expiration-notifier/
Share on other sites

Link to post
Share on other sites

i had to do research once for the exact thing, i do not have anything to do with AD servers but i used Powershell for it not C#

Might aswell take a look for that on the internet.

 

 

something like this i think.

https://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27

 

Quote or mention me if not feel ignored 

Link to post
Share on other sites

10 minutes ago, Cruorzy said:

i had to do research once for the exact thing, i do not have anything to do with AD servers but i used Powershell for it not C#

Might aswell take a look for that on the internet.

 

 

something like this i think.

https://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27

 

Hmm... That's exactly what I need, I will consider using it, thanks a lot! But still if there are any C# programmers that know the solution to my problem I will be glad for any help ;) 

Main Rig - AMD Ryzen 1800X @ 3.9 - NZXT Kraken X62 - MSI X370 SLI PLUS - G.Skill TRIDENT Z RGB 16GB 2667MHz - 2 x Gigabyte GeForce GTX1080 WindForce OC - NZXT S340 (Purple-White) - OCZ 120GB, Seagate 1TB - Corsair RM750i 80+ Gold - SAMSUNG S24D590 24", HP L1950g - Logitech G810 Orion Spectrum - Logitech G502 Proteus Spectrum - Creative Cambridge Sound Works + two random Philips speakers, Logitech G430 headset - Win 10 Pro x64

Retro Gaming PC - ASUS T3

Server - HP ProLiant DL380 G6(Currently assembling it) - 2 x Intel Xeon E5520 2.26GHz 8MB Quad Core Processor

NAS - Zyxel NSA320S 2 x Seagate Constellation ES 2TB(RAID1) - QNAP TS-212 1 x 500GB

 

-=Logitech FanBoiiiiiiii=-

I love NZXT as well <3

Link to post
Share on other sites

No problem, it was kinda funny since the internship i have just implemented the exact same thing and i did some research for it.

But i did not apply the script or even know if they use it or found an other.

Quote or mention me if not feel ignored 

Link to post
Share on other sites

4 hours ago, Marine_Boy said:

Hmm... That's exactly what I need, I will consider using it, thanks a lot! But still if there are any C# programmers that know the solution to my problem I will be glad for any help ;) 

If you're willing to stick your neck out a little bit then you could suggest that work like this is usually done in the realm of operations / system administration.  Typically you find more powershell tooling used in that type of role than writing custom applications in C#.

 

My suggestion would be to keep functionality like this in Powershell scripts that can be used by Sys Admins and be part of their "toolbox".  If you want to further integrate these into a bigger system then call out to powershell from .NET like this:

https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/

Link to post
Share on other sites

@clegger, thanks! I will read more about calling PS scripts from within the .NET programs. That might be an option ;) 

Main Rig - AMD Ryzen 1800X @ 3.9 - NZXT Kraken X62 - MSI X370 SLI PLUS - G.Skill TRIDENT Z RGB 16GB 2667MHz - 2 x Gigabyte GeForce GTX1080 WindForce OC - NZXT S340 (Purple-White) - OCZ 120GB, Seagate 1TB - Corsair RM750i 80+ Gold - SAMSUNG S24D590 24", HP L1950g - Logitech G810 Orion Spectrum - Logitech G502 Proteus Spectrum - Creative Cambridge Sound Works + two random Philips speakers, Logitech G430 headset - Win 10 Pro x64

Retro Gaming PC - ASUS T3

Server - HP ProLiant DL380 G6(Currently assembling it) - 2 x Intel Xeon E5520 2.26GHz 8MB Quad Core Processor

NAS - Zyxel NSA320S 2 x Seagate Constellation ES 2TB(RAID1) - QNAP TS-212 1 x 500GB

 

-=Logitech FanBoiiiiiiii=-

I love NZXT as well <3

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×