国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

AD帳戶操作C#示例代碼(二)——檢查密碼將過期的用戶

2019-11-14 16:43:50
字體:
來源:轉載
供稿:網友

    本文接著和大家分享AD帳戶操作,這次開發一個簡單的檢查密碼將過期用戶的小工具。

     首先,新建一個用戶實體類,屬性是我們要取的用戶信息。

    public class UserInfo    {        /// <summary>        /// sAM帳戶名稱        /// </summary>        public string SamAccountName { get; set; }        /// <summary>        /// 名稱        /// </summary>        public string Name { get; set; }        /// <summary>        /// 郵箱        /// </summary>        public string Mail { get; set; }        /// <summary>        /// 已禁用        /// </summary>        public bool IsDisabled { get; set; }        /// <summary>        /// 設置為密碼永不過期        /// </summary>        public bool IsPassWordNeverExpire { get; set; }        /// <summary>        /// 設置為不需要密碼        /// </summary>        public bool IsNoPasswordRequired { get; set; }        /// <summary>        /// 系統密碼過期設置天數        /// </summary>        public long MaxPasswordAge { get; set; }        /// <summary>        /// 剩余過期天數        /// </summary>        public double? SurplusPasswordExpirationDays {            get             {                if (!PasswordExpirationDate.HasValue)                {                    return default(double?);                }                double days = PasswordExpirationDate.Value.Subtract(DateTime.Now).TotalDays;                if (days <= 0)                {                    return 0;                }                return Math.Round(days, 2);             }        }        /// <summary>        /// 最近密碼修改時間        /// </summary>        public DateTime PasswordLastSet { get; set; }        /// <summary>        /// 密碼過期時間        /// </summary>        public DateTime? PasswordExpirationDate { get; set; }    }
View Code

     然后是搜索用戶信息的方法。

PRivate IEnumerable<UserInfo> SearchUsers(string path, string username, string password, string sAMAccountName, string displayName, bool isDisabled, bool IsPasswordNeverExpire, long[] surplusExpirationDays)        {            using (DirectoryEntry directoryEntry = new DirectoryEntry(path, username, password))            {                using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry, @"&(objectCategory=person)(objectClass=user))", new string[] { "name", "sAMAccountName", "userAccountcontrol", "pwdLastSet", "mail" }, SearchScope.Subtree) { PageSize = 1000 })                {                    using (SearchResultCollection userResultCollection = directorySearcher.FindAll())                    {                        foreach (SearchResult userResult in userResultCollection)                        {                            UserInfo userInfo = new UserInfo();                            //TODO: 賦值                            yield return userInfo;                        }                    }                }            }        }

     這次我們主要用DirectorySearcher類:SearchRoot是搜索的DirectoryEntry根節點;SearchScope屬性是搜索的范圍,是個SearchScope枚舉:Base(限于基對象)、OneLevel(搜索基對象的直接子對象,但不搜索基對象)、Subtree(搜索整個子樹,包括基對象及其所有子對象)。我們要在指定的OU下搜索用戶,所以選擇子樹Subtree。

     DirectorySearcher類的Filter屬性是過濾條件,搜索用戶就是“&(objectCategory=person)(objectClass=user))"。注意:表示與或非的“&”、“|”、“!”要放在這些條件表達式前面而不是它們之間;如果要做模糊查詢用通配符*;可以用“=”、“>=”、“<=”、“~=”(約等于),但“>”和”<“是不行的;”pwdLastSet“要轉為Windows文件時間,因為存的是個long,還有處理”userAccountControl"的并運算,這里用“:1.2.840.113556.1.4.803:=”。我們可以把一些查詢條件放在Filter里,減少搜索結果的返回行數:

                    directorySearcher.SearchScope = SearchScope.Subtree;                    List<string> filterItems = new List<string>();                    if (!string.IsNullOrEmpty(sAMAccountName))                    {                        filterItems.Add(string.Format(@"(sAMAccountName={0})", sAMAccountName));                    }                    if (!string.IsNullOrEmpty(displayName))                    {                        filterItems.Add(string.Format(@"(name={0})", displayName));                    }                    if (!containsDisabled)                    {                        filterItems.Add(@"(!(userAccountControl:1.2.840.113556.1.4.803:=2))");                    }                    if (!containsPasswordNeverExpire)                    {                        filterItems.Add(@"(!(userAccountControl:1.2.840.113556.1.4.803:=65536))");                    }                    if (!containsNoPasswordRequired)                    {                        filterItems.Add(@"(!(userAccountControl:1.2.840.113556.1.4.803:=32))");                    }                    if (surplusExpirationDays != null && surplusExpirationDays.Length > 0)                    {                        StringBuilder surplusExpirationDaysFilter = new StringBuilder(@"(|");                        DateTime now = DateTime.Now;                        foreach (long surplusExpirationDay in surplusExpirationDays)                        {                            DateTime passwordExpirationDate = now.AddDays(surplusExpirationDay);                            DateTime passwordLastSet = passwordExpirationDate.AddDays(-1 * maxPwdAge);                            if (surplusExpirationDay != 0)                            {                                surplusExpirationDaysFilter.AppendFormat("(&(pwdLastSet>={0})(pwdLastSet<={1}))", passwordLastSet.ToFileTime().ToString(), passwordLastSet.AddDays(1).AddSeconds(-1).ToFileTime().ToString());                            }                            else                            {                                surplusExpirationDaysFilter.AppendFormat("(pwdLastSet<={0})(pwdLastSet=0)", passwordLastSet.AddDays(1).AddSeconds(-1).ToFileTime().ToString());                            }                        }                        surplusExpirationDaysFilter.Append(@")");                        filterItems.Add(surplusExpirationDaysFilter.ToString());                    }                    directorySearcher.Filter = string.Format(@"(&{0}(objectCategory=person)(objectClass=user))", string.Concat(filterItems));

     Filter語法請參考:http://msdn.microsoft.com/en-us/library/aa746475.aspx、http://www.ldapexplorer.com/en/manual/109010000-ldap-filter-syntax.htm。

     userAccountControl標志請參考:http://support.microsoft.com/kb/305144/zh-cn、http://msdn.microsoft.com/zh-cn/library/ms680832(VS.85).aspx、http://technet.microsoft.com/library/ee198831.aspx。

     DirectorySearcher類的PropertiesToLoad屬性是要檢索的屬性列表,這個就相當于我們訪問數據庫時寫SQL語句里SELECT后面的東西,最好按需指定,盡量不寫“SELECT *”; 注意DirectorySearcher類的PageSize屬性,如果要返回所有數據可以設為1000,默認是只返回1000條的。

 directorySearcher.PropertiesToLoad.AddRange(new string[] { "name", "sAMAccountName", "userAccountcontrol", "pwdLastSet", "mail" }); directorySearcher.PageSize = 1000;

      更多DirectorySearcher類屬性請參考:http://msdn.microsoft.com/zh-cn/library/System.DirectoryServices.DirectorySearcher_properties(v=vs.80).aspx

      用戶密碼的過期日期可以通過DirectoryEntry對象的InvokeGet方法獲得,不過要加載一次DirectoryEntry的話,總覺得很浪費!

    using (DirectoryEntry resultDirectoryEntry = userResult.GetDirectoryEntry())    {        userInfo.PasswordExpirationDate = DateTime.Parse(resultDirectoryEntry.InvokeGet("PasswordExpirationDate").ToString());    }

       所以我還是愿意自己算一下,用最近密碼設置時間+系統設置的密碼過期天數。最近密碼設置時間對應“pwdLastSet”,如果用DirectoryEntry對象的Properties取,那是個“System.__ComObject”類型值,幸好SearchResult對象的“pwdLastSet”可以直接取為long,這個值是Windows文件時間,可以再轉為本地時間。

long fileTime = (userResult.Properties["pwdLastSet"][0] as long?).GetValueOrDefault();userInfo.PasswordLastSet = DateTime.FromFileTime(fileTime);

      系統密碼過期天數是通過組策略設置的,可以在OU路徑下通過“maxPwdAge”屬性獲取,SearchResult對象的“maxPwdAge”也可以直接取為long。

 directorySearcher.SearchScope = SearchScope.Base; directorySearcher.Filter = @"(objectClass=*)"; directorySearcher.PropertiesToLoad.Add("maxPwdAge"); SearchResult ouResult = directorySearcher.FindOne(); long maxPwdAge = 0; if (ouResult.Properties.Contains("maxPwdAge")) {      maxPwdAge = TimeSpan.FromTicks((long)ouResult.Properties["maxPwdAge"][0]).Days * -1; }

      最后,用戶的密碼過期就可以這么求了!

 userInfo.MaxPasswordAge = maxPwdAge; if (!userInfo.IsPasswordNeverExpire) {      userInfo.PasswordExpirationDate = userInfo.PasswordLastSet.AddDays(userInfo.MaxPasswordAge); }

      查詢用戶信息OK,剩下貼段將用戶信息導出Excel的代碼:

                   string connectionString = string.Format("Provider = Microsoft.ACE.OLEDB.12.0;Data Source ={0};Extended Properties='Excel 12.0 xml;HDR=YES'", fileName);                    using (OleDbConnection oleDbConnection = new OleDbConnection(connectionString))                    {                        oleDbConnection.Open();                        using (OleDbCommand oleDbCommand = new OleDbCommand())                        {                            oleDbCommand.Connection = oleDbConnection;                            //const string sqlCreateTable = @"CREATE TABLE [Sheet1$] ([登錄名] TEXT,[顯示名] TEXT,[郵箱] TEXT,[已禁用] TEXT,[密碼永不過期] TEXT,[密碼過期設置天數] TEXT,[密碼最近設置時間] TEXT,[密碼過期時間] TEXT,[剩余密碼過期天數] TEXT)";                            //oleDbCommand.CommandText = sqlCreateTable;                            //oleDbCommand.ExecuteNonQuery();                            foreach (var user in users)                            {                                oleDbCommand.CommandText = string.Format(@"INSERT INTO [Sheet1$]([登錄名], [顯示名], [郵箱],[已禁用], [密碼永不過期], [密碼過期設置天數],[密碼最近設置時間],[密碼過期時間],[剩余密碼過期天數]) VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}');", user.SamAccountName, user.Name, user.Mail, user.IsDisabled ? "" : "", user.IsPasswordNeverExpire ? "" : "", user.MaxPasswordAge.ToString(), user.PasswordLastSet.ToString(), user.PasswordExpirationDate.ToString(), user.SurplusPasswordExpirationDays.ToString());                                oleDbCommand.ExecuteNonQuery();                            }                        }                    }
View Code

      還有使用SmtpClient發送郵件的代碼,可以自定義個HTML文件做模版內容:

            using (SmtpClient smtpClient = new SmtpClient())            {                if (!string.IsNullOrEmpty(mailMessageInfo.Host))                {                    smtpClient.Host = mailMessageInfo.Host;                }                if (!string.IsNullOrEmpty(mailMessageInfo.Port))                {                    smtpClient.Port = int.Parse(mailMessageInfo.Port);                }                smtpClient.Credentials = new System.Net.NetworkCredential();                if (!string.IsNullOrEmpty(mailMessageInfo.UserName))                {                    NetworkCredential networkCredential = new NetworkCredential { UserName = mailMessageInfo.UserName };                    if (!string.IsNullOrEmpty(mailMessageInfo.PassWord))                    {                        networkCredential.Password = mailMessageInfo.PassWord;                    }                    smtpClient.Credentials = networkCredential;                }                MailMessage mailMessage = new MailMessage();                if (!string.IsNullOrEmpty(mailMessageInfo.From))                {                    mailMessage.From = new MailAddress(mailMessageInfo.From);                }                foreach (string to in mailMessageInfo.ToList)                {                    if (!string.IsNullOrWhiteSpace(to))                    {                        mailMessage.To.Add(to);                    }                }                if (mailMessageInfo.CcList != null && mailMessageInfo.CcList.Length > 0)                {                    foreach (string cc in mailMessageInfo.CcList)                    {                        if (!string.IsNullOrWhiteSpace(cc))                        {                            mailMessage.To.Add(cc);                        }                    }                }                mailMessage.IsBodyHtml = true;                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "templates", mailMessageInfo.TemplateFileName);                string body = File.ReadAllText(path);                Regex regexImg = new Regex(@"<img/s[^>]*>", RegexOptions.IgnoreCase);                Regex regexSrc = new Regex(                    @"src=(?:(['""])(?<src>(?:(?!/1).)*)/1|(?<src>[^/s>]+))",                    RegexOptions.IgnoreCase | RegexOptions.Singleline);                MatchCollection matchCollection = regexImg.Matches(body);                Dictionary<string, string> contentIds = new Dictionary<string, string>();                foreach (Match matchImg in matchCollection)                {                    if (regexSrc.IsMatch(matchImg.Groups[0].Value))                    {                        Match matchSrc = regexSrc.Match(matchImg.Groups[0].Value);                        string srcValue = matchSrc.Groups["src"].Value;                        if (!srcValue.StartsWith("http:", System.StringComparison.OrdinalIgnoreCase)                            && !srcValue.StartsWith("file:", System.StringComparison.OrdinalIgnoreCase))                        {                            if (srcValue.IndexOf("/") == 0)                            {                                srcValue = srcValue.Substring(1);                            }                            string attachmentContentId = Path.GetFileName(srcValue).Replace(".", string.Empty);                            body = body.Replace(matchSrc.Groups["src"].Value, "cid:" + attachmentContentId);                            if (!contentIds.ContainsKey(attachmentContentId))                            {                                string inlinePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "templates", srcValue.Replace(@"/", @"/"));                                Attachment inline = new Attachment(inlinePath);                                inline.ContentDisposition.Inline = true;                                inline.ContentDisposition.DispositionType = DispositionTypeNames.Inline;                                inline.ContentId = attachmentContentId;                                if (srcValue.EndsWith("gif", StringComparison.OrdinalIgnoreCase))                                {                                    inline.ContentType.MediaType = MediaTypeNames.Image.Gif;                                }                                else                                {                                    inline.ContentType.MediaType = MediaTypeNames.Image.Jpeg;                                }                                inline.ContentType.Name = Path.GetFileName(inlinePath);                                mailMessage.Attachments.Add(inline);                                contentIds.Add(attachmentContentId, null);                            }                        }                    }                }                mailMessage.Body = body; ;                mailMessage.BodyEncoding = Encoding.UTF8;                mailMessage.Subject = mailMessageInfo.Subject;                mailMessage.SubjectEncoding = Encoding.UTF8;                smtpClient.Send(mailMessage);            }
View Code

 

     最后,將這些代碼整合起來,就是檢查用戶密碼過期的小工具了!由于筆者水平有限,文中難免會有些疏漏和錯誤,代碼也有待不斷優化,歡迎各位高手提出寶貴的建議!

參考資料:

DirectoryEntry 類使用 http://msdn.microsoft.com/zh-cn/library/z9cddzaa(v=vs.110).aspx

DirectorySearcher 類使用 http://msdn.microsoft.com/zh-cn/library/System.DirectoryServices.DirectorySearcher(v=vs.90).aspx

輕量目錄訪問協議 (LDAP) http://msdn.microsoft.com/en-us/library/aa367008(VS.85).aspx

檢查密碼將過期用戶小工具下載地址:http://files.VEVb.com/CSharpDevelopers/UserPasswordSetChecker.zip

 

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 中江县| 齐河县| 鹰潭市| 昔阳县| 滦平县| 丰宁| 天等县| 蚌埠市| 哈尔滨市| 益阳市| 彝良县| 南城县| 芷江| 武邑县| 保山市| 特克斯县| 天长市| 芜湖市| 高雄市| 防城港市| 和顺县| 革吉县| 墨江| 曲靖市| 蓝山县| 武宁县| 红河县| 定兴县| 精河县| 株洲县| 盐亭县| 咸丰县| 临夏县| 盈江县| 林甸县| 曲水县| 横峰县| 高淳县| 绥化市| 墨脱县| 奉新县|