14 votes

Date d'expiration du mot de passe de l'utilisateur Active Directory .NET/OU Group Policy

J'ai recherché sur le site pour obtenir des informations et trouvé ceci : ASP.NET C# Active Directory - Voir combien de temps avant l'expiration du mot de passe d'un utilisateur

qui explique comment obtenir la valeur de l'expiration du mot de passe selon la politique de domaine.

Ma question est la suivante : que se passe-t-il si l'utilisateur a une stratégie de groupe de OU qui a une valeur MaxPasswordAge différente, remplaçant celle spécifiée dans la stratégie de groupe de domaine ? Comment obtenir de manière programmatique l'objet de la stratégie de groupe de l'OU ?

Édition : Pour rendre cette question un peu plus claire, j'ajoute cette édition. Ce que je recherche, c'est de pouvoir dire quand le mot de passe de l'utilisateur expire. Autant que je comprenne, cette valeur de date peut être gouvernée par la politique locale des domaines ou par la politique de l'objet de groupe. J'ai un fournisseur Linq2DirectoryService qui traduit les requêtes Linq en requêtes Ldap. Donc, une requête LDAP pour obtenir la valeur d'expiration de la date serait optimale pour ce sujet. Si votre réponse inclut les objets wrappers pris en charge par .NET dans cette équation, ce serait une réponse parfaite !

0 votes

Pas de commentaires...? Que diriez-vous de la Console de gestion des stratégies de groupe, mon environnement est Server 2003, quelqu'un a de l'expertise avec ce logiciel. Aidez les gens!

15voto

Larry Smithmier Points 1573

Permettez-moi de commencer par http://support.microsoft.com/kb/323750 qui contient des exemples en Visual Basic et VBScript et http://www.anitkb.com/2010/03/how-to-implement-active-directory.html qui explique comment le paramètre OU maxPwdAge affecte les ordinateurs, pas les utilisateurs. Il contient également un commentaire pointant vers AloInfo.exe, un outil de MS qui peut être utilisé pour obtenir les âges des mots de passe.

Voici l'exemple:

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 = "Administrateur";
            passWord = "xxxmotdepassexxx";
            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("Vous devez changer votre mot de passe dans"+
                                      " {0} jours"
                                     , daysLeft));
            Console.ReadLine();
        }
    }
}

0 votes

Ah, en relisant, je remarque que votre environnement serveur est 2003, donc vous ne pouvez pas utiliser les politiques de mot de passe à grain fin décrites dans technet.microsoft.com/en-us/library/cc770394%28WS.10%29.aspx car cela nécessite 2008+. Je crois que l'article mentionné est une solution qui couvre tous les scénarios que vous rencontrez.

0 votes

Oui, je suis familier avec cet exemple pour lire la valeur maxPwdAge à travers le filtre. Mais ma question est..est-ce que la valeur est écrasée si un objet de stratégie de groupe qui régit les mots de passe existe pour un utilisateur ? Si cette valeur n'est pas écrasée par le fait qu'il y ait une gpo définie pour cet utilisateur spécifique, alors le code que vous avez fourni n'est pas bon. Je suis en train de vérifier cela maintenant.

0 votes

A pu revenir à la tâche. Comme je le soupçonnais, votre code ne suffira pas pour détecter l'expiration générale du mot de passe. La raison en est qu'un GPO peut remplacer la Stratégie de domaine par défaut à n'importe quel niveau. Ce qui semble devoir être utilisé est ceci : pinvoke.net/default.aspx/advapi32.lsaopenpolicy

11voto

Gerke Geurts Points 307

Le code suivant a fonctionné pour moi pour obtenir la date d'expiration du mot de passe à la fois sur les comptes d'utilisateurs de domaine et locaux :

public static DateTime GetPasswordExpirationDate(string userId, string domainOrMachineName)
{
    using (var userEntry = new DirectoryEntry("WinNT://" + domainOrMachineName + '/' + userId + ",user"))
    {
        return (DateTime)userEntry.InvokeGet("PasswordExpirationDate");
    }
}

1 votes

J'ai obtenu une erreur : Exception a été levée par la cible d'une invocation.

0 votes

@GerkeGeurts À quoi ressemble généralement userId? Est-ce la même chose que samAccountName?

0 votes

UserId est en effet le nom de compte SAM.

4voto

Mukesh Kumar Points 84

Utilisez la méthode suivante pour obtenir la date d'expiration du compte -

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

1 votes

MS recommande de ne pas utiliser DirectoryEntry.InvokeGet (voir msdn.microsoft.com/en-us/library/…). J'ai posté une solution alternative.

1voto

Tawab Wakil Points 355

Certaines des réponses précédentes reposent sur la méthode DirectoryEntry.InvokeGet, que MS déconseille d'utiliser. Donc voici une autre approche:

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

Vous devrez ajouter une référence à la bibliothèque ActiveDS COM généralement située à C:\Windows\System32\activeds.tlb.

0 votes

En fait, cette solution fait exactement la même chose que l'utilisation de DirectoryEntry.InvokeGet("PasswordExpirationDate"). Les deux appellent l'interface COM ActiveDS. Cependant, cela se fait d'une manière beaucoup plus compliquée!

0 votes

Je ne peux ni confirmer ni nier ce point. Mais le lien que j'ai fourni affirme de manière autoritaire que InvokeGet ne devrait pas être utilisé, alors que je n'ai pas pu trouver une déclaration aussi explicite concernant l'interface COM.

0 votes

L'utilisation de InvokeGet est découragée car elle contourne le cache des propriétés qui est efficace lors de l'utilisation de DirectoryEntry.Properties. Comme la propriété PasswordExpirationDate n'est pas stockée dans la collection DirectoryEntry.Properties, la méthode InvokeGet doit être utilisée pour y accéder.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X