Дата истечения срока действия пароля пользователя Active Directory. .NET / OU Group Policy

Я искал информацию на сайте и нашел следующее: ASP.NET C # Active Directory - узнайте, сколько времени осталось до истечения срока действия пароля пользователя

в котором объясняется, как получить значение истечения срока действия пароля в соответствии с политикой домена.

У меня такой вопрос: что, если у пользователя есть групповая политика подразделения, у которой другое значение MaxPasswordAge, превосходящее значение, указанное в групповой политике домена? Как программно получить объект групповой политики подразделения?

Изменить: Чтобы прояснить этот вопрос, я добавляю это изменение. Мне нужно знать, когда истекает срок действия пароля пользователя. Насколько я понимаю, значение даты может регулироваться либо локальной политикой домена, либо политикой группового объекта. У меня есть поставщик Linq2DirectoryService, который переводит запросы Linq в Ldap. Таким образом, запрос LDAP для получения значения даты истечения срока действия будет оптимальным для этого subj. Если вы ответите, какие объекты-обертки, поддерживаемые .net, включены в это уравнение - это будет мертвым ответом!


person dexter    schedule 21.09.2010    source источник
comment
Без комментариев...? Как насчет консоли управления групповой политикой, моя среда - Server 2003, есть ли у кого-нибудь опыт работы с этой частью программного обеспечения. Помочь людям!   -  person dexter    schedule 27.09.2010


Ответы (4)


Позвольте мне начать с http://support.microsoft.com/kb/323750, который содержит Visual Basic и примеры VBScript и http://www.anitkb.com/2010/03/how-to-implement-active-directory.html, в котором показано, как параметр maxPwdAge OU влияет на компьютеры, а не на пользователей. В нем также есть комментарий, указывающий на AloInfo.exe как инструмент от MS, который можно использовать для определения возраста пароля.

Вот пример:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;

namespace LDAP
{
    class Program
    {
        static void Main(string[] args)
        {
            string domainAndUsername = string.Empty;
            string domain = string.Empty;
            string userName = string.Empty;
            string passWord = string.Empty;
            AuthenticationTypes at = AuthenticationTypes.Anonymous;
            StringBuilder sb = new StringBuilder();

            domain = @"LDAP://w.x.y.z";
            domainAndUsername = @"LDAP://w.x.y.z/cn=Lawrence E."+
                        " Smithmier\, Jr.,cn=Users,dc=corp,"+
                        "dc=productiveedge,dc=com";
            userName = "Administrator";
            passWord = "xxxpasswordxxx";
            at = AuthenticationTypes.Secure;

            DirectoryEntry entry = new DirectoryEntry(
                        domain, userName, passWord, at);

            DirectorySearcher mySearcher = new DirectorySearcher(entry);

            SearchResultCollection results;
            string filter = "maxPwdAge=*";
            mySearcher.Filter = filter;

            results = mySearcher.FindAll();
            long maxDays = 0;
            if(results.Count>=1)
            {
                Int64 maxPwdAge=(Int64)results[0].Properties["maxPwdAge"][0];
                maxDays = maxPwdAge/-864000000000;
            }

            DirectoryEntry entryUser = new DirectoryEntry(
                        domainAndUsername, userName, passWord, at);
            mySearcher = new DirectorySearcher(entryUser);

            results = mySearcher.FindAll();
            long daysLeft=0;
            if (results.Count >= 1)
            {
                var lastChanged = results[0].Properties["pwdLastSet"][0];
                daysLeft = maxDays - DateTime.Today.Subtract(
                        DateTime.FromFileTime((long)lastChanged)).Days;
            }
            Console.WriteLine(
                        String.Format("You must change your password within"+
                                      " {0} days"
                                     , daysLeft));
            Console.ReadLine();
        }
    }
}
person Larry Smithmier    schedule 15.11.2010
comment
А, перечитывая, я заметил, что ваша серверная среда - 2003, поэтому вы не можете использовать детальные политики паролей, описанные в technet.microsoft.com/en-us/library/cc770394%28WS.10%29.aspx, так как для этого требуется версия 2008+. Я считаю, что указанная статья - это решение, подходящее для любого вашего сценария. - person Larry Smithmier; 15.11.2010
comment
да, я знаком с этим примером, чтобы прочитать значение maxPwdAge через фильтр. Но мой вопрос ... перезаписывается ли значение, если для пользователя существует объект групповой политики, который управляет паролями? Если это значение не перезаписывается тем фактом, что для этого конкретного пользователя определен gpo, то предоставленный вами код не годится. Я должен это проверить сейчас .. - person dexter; 22.11.2010
comment
смог вернуться к задаче. Как и предполагалось, вашего кода будет недостаточно для общего обнаружения истечения срока действия пароля. Причина в том, что объект групповой политики может переопределить политику домена по умолчанию на любом уровне. Похоже, что нужно использовать следующее: pinvoke.net/default.aspx/ advapi32.lsaopenpolicy - person dexter; 26.11.2010
comment
Затем я еще раз посмотрю, смогу ли я изменить существующий код для обработки GPO. - person Larry Smithmier; 29.11.2010
comment
@LarrySmithmier У вас есть альтернативный подход к тому, о чем спрашивает Декстер? - person FMFF; 07.10.2013
comment
@FMFF Я не делал версию pinvoke. Вам нужно что-то большее, чем указано выше? Я не смотрел на это недавно, вероятно, есть более простой / лучший способ сделать это сейчас. - person Larry Smithmier; 07.10.2013
comment
@FMFF взгляните на stackoverflow.com/questions/9768944/ и посмотреть, работает ли он для вас. - person Larry Smithmier; 07.10.2013
comment
@LarrySmithmier Есть шанс, что пользователь (в имени пользователя) не имеет права видеть maxPwdAge (кроме тех, которые влияют на него)? - person a.farkas2508; 03.04.2014
comment
Я могу получить maxPwdAge. Но pwdLastSet выбросил Index вне связанного исключения. Я отладил код и увидел, что свойства pwdLastSet недоступно. - person kamalpreet; 09.10.2015

Следующий код помог мне получить дату истечения срока действия пароля как для доменных, так и для локальных учетных записей пользователей:

public static DateTime GetPasswordExpirationDate(string userId, string domainOrMachineName)
{
    using (var userEntry = new DirectoryEntry("WinNT://" + domainOrMachineName + '/' + userId + ",user"))
    {
        return (DateTime)userEntry.InvokeGet("PasswordExpirationDate");
    }
}
person Gerke Geurts    schedule 20.07.2011
comment
Я получил ошибку: исключение было выброшено целью вызова. - person Vikalp Kapadiya; 10.06.2013
comment
@GerkeGeurts Как обычно выглядит userId? Это то же самое, что samAccountName? - person styfle; 06.10.2015
comment
userId - это действительно имя учетной записи SAM. - person Gerke Geurts; 12.11.2015
comment
userEntry.InvokeGet (PasswordExpirationDate); возвращает и Object not a Date time, безопасно ли просто использовать его? - person Eric Brown - Cal; 08.09.2016
comment
Да, забрасывать безопасно. Я соответственно обновил образец кода. - person Gerke Geurts; 21.09.2016
comment
MS не рекомендует использовать DirectoryEntry.InvokeGet (см. msdn.microsoft.com/en-us/library/). Я опубликовал альтернативное решение. - person Tawab Wakil; 16.05.2018

Используйте следующий метод, чтобы узнать дату истечения срока действия учетной записи:

public static DateTime GetPasswordExpirationDate(string userId)
    {
        string forestGc = String.Format("GC://{0}", Forest.GetCurrentForest().Name);
        var searcher = new DirectorySearcher();
        searcher = new DirectorySearcher(new DirectoryEntry(forestGc));
        searcher.Filter = "(sAMAccountName=" + userId + ")";
        var results = searcher.FindOne().GetDirectoryEntry();
        return (DateTime)results.InvokeGet("PasswordExpirationDate");
    }
person Mukesh Kumar    schedule 12.07.2017
comment
MS не рекомендует использовать DirectoryEntry.InvokeGet (см. msdn.microsoft.com/en-us/library/). Я опубликовал альтернативное решение. - person Tawab Wakil; 16.05.2018

Некоторые из предыдущих ответов полагаются на метод DirectoryEntry.InvokeGet, , который, по словам MS, использовать не следует. Итак, вот еще один подход:

public static DateTime GetPasswordExpirationDate(UserPrincipal user)
{
    DirectoryEntry deUser = (DirectoryEntry)user.GetUnderlyingObject();
    ActiveDs.IADsUser nativeDeUser = (ActiveDs.IADsUser)deUser.NativeObject;
    return nativeDeUser.PasswordExpirationDate;
}

Вам нужно будет добавить ссылку на COM-библиотеку ActiveDS, которая обычно находится в C: \ Windows \ System32 \ activeds.tlb.

person Tawab Wakil    schedule 16.05.2018
comment
Фактически это решение делает то же самое, что и использование DirectoryEntry.InvokeGet (PasswordExpirationDate). Оба обращаются к COM-интерфейсу ActiveDS. Однако это происходит гораздо сложнее! - person Gerke Geurts; 29.05.2018
comment
Я не могу подтвердить или опровергнуть эту точку зрения. Но ссылка, которую я предоставил, авторитетно говорит, что InvokeGet не следует использовать, тогда как я не смог найти аналогичного явного заявления относительно интерфейса COM. - person Tawab Wakil; 30.05.2018
comment
Использование InvokeGet не рекомендуется, поскольку оно позволяет обойти кэширование свойств, которое эффективно при использовании DirectoryEntry.Properties. Поскольку свойство PasswordExpirationDate не хранится в коллекции DirectoryEntry.Properties, для доступа к нему необходимо использовать метод InvokeGet. - person Gerke Geurts; 31.05.2018
comment
Что касается реализации InvokeGet, см. github.com/dotnet/corefx/blob/master/src/. - person Gerke Geurts; 31.05.2018
comment
Все хорошие моменты. Тогда единственная причина использовать мой ответ может заключаться в том, что производительность была превыше всего или вам нужно было реализовать какое-то настраиваемое поведение. Но эти причины должны быть редкими. - person Tawab Wakil; 01.06.2018