查找无法更改密码的用户

查找无法更改密码的用户

问题描述:

我正在尝试准备一份无法在AD中更改其密码的用户的报告.AD已安装在Window Server 2012上.

I am trying to prepare report of users who cannot change their password in AD. AD is installed on Window Server 2012.

这是我认为可以但不起作用的方法-

Here is the method, which I thought to work but isn't working -

    /// <summary>
    /// Check whether password of user cannot be changed.
    /// </summary>
    /// <param name="user">The DirectoryEntry object of user.</param>
    /// <returns>Return true if password cannot be changed else false.</returns>
    public static bool IsPasswordCannotBeChanged(DirectoryEntry user)
    {
        if (user.Properties.Contains("userAccountControl") &&
            user.Properties["userAccountControl"].Value != null)
        {
            var userFlags = (UserFlags)user.Properties["userAccountControl"].Value;
            return userFlags.Contains(UserFlags.PasswordCannotChange);
        }
        return false;
    }

这是枚举 UserFlags -

[Flags]
public enum UserFlags
{
    // Reference - Chapter 10 (from The .NET Developer's Guide to Directory Services Programming)

    Script = 1,                                     // 0x1
    AccountDisabled = 2,                            // 0x2
    HomeDirectoryRequired = 8,                      // 0x8
    AccountLockedOut = 16,                          // 0x10
    PasswordNotRequired = 32,                       // 0x20
    PasswordCannotChange = 64,                      // 0x40
    EncryptedTextPasswordAllowed = 128,             // 0x80
    TempDuplicateAccount = 256,                     // 0x100
    NormalAccount = 512,                            // 0x200
    InterDomainTrustAccount = 2048,                 // 0x800
    WorkstationTrustAccount = 4096,                 // 0x1000
    ServerTrustAccount = 8192,                      // 0x2000
    PasswordDoesNotExpire = 65536,                  // 0x10000 (Also 66048 )
    MnsLogonAccount = 131072,                       // 0x20000
    SmartCardRequired = 262144,                     // 0x40000
    TrustedForDelegation = 524288,                  // 0x80000
    AccountNotDelegated = 1048576,                  // 0x100000
    UseDesKeyOnly = 2097152,                        // 0x200000
    DontRequirePreauth = 4194304,                   // 0x400000
    PasswordExpired = 8388608,                      // 0x800000 (Applicable only in Window 2000 and Window Server 2003)
    TrustedToAuthenticateForDelegation = 16777216,  // 0x1000000
    NoAuthDataRequired = 33554432                   // 0x2000000
}

您能否分享为什么密码无法更改的用户未返回 64 (密码无法更改)的原因?

Can you share why 64 (for password cannot change), is not returned for user whose password cannot be changed?

或者您有更好的方法来解决这个问题?

Or you have a much better approach to make this work out?

EDIT-

EDIT-

UserFlagExtension 代码可让事情变得快速-

UserFlagExtension code for making things bit fast -

public static class UserFlagExtensions
{
    /// <summary>
    /// Check if flags contains the specific user flag.
    /// </summary>
    /// <param name="haystack">The bunch of flags</param>
    /// <param name="needle">The flag to look for.</param>
    /// <returns>Return true if flag found in flags.</returns>
    public static bool Contains(this UserFlags haystack, UserFlags needle)
    {
        return (haystack & needle) == needle;
    }
}

搜索了很多并奋力工作了几个小时之后,我便能够制定出有效的解决方案.

After searching lot and struggling for hours, I was able to formulate working solution.

请继续链接 AD .NET-用户无法更改密码属性(获取/设置)

您需要添加对 ActiveDS 的引用才能使其正常工作.尽管我没有时间进行测试.但是应该在许多地方都可以正常工作.所以...

You will need to add reference to ActiveDS for making it to work. Although I hadn't get time to test it. But a lot of places it is supposed to be working. So...

上一篇文章的代码段- (如果文章被删除)

public bool GetCantChangePassword(string userid)
 {
        bool cantChange = false;
        try
        {
            DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0},{1}", "OU=Standard Users,OU=Domain", "DC=domain,DC=org"));
            entry.AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.ServerBind;
            DirectorySearcher search = new DirectorySearcher(entry);
            search.Filter = string.Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))", userid);
            search.SearchScope = SearchScope.Subtree;
            SearchResult results = search.FindOne();
            if (results != null)
            {
                try
                {
                    DirectoryEntry user = results.GetDirectoryEntry();
                    ActiveDirectorySecurity userSecurity = user.ObjectSecurity;
                    SecurityDescriptor sd = (SecurityDescriptor)user.Properties["ntSecurityDescriptor"].Value;
                    AccessControlList oACL = (AccessControlList)sd.DiscretionaryAcl;

                    bool everyoneCantChange = false;
                    bool selfCantChange = false;

                    foreach (ActiveDs.AccessControlEntry ace in oACL)
                    {
                        try
                        {
                            if (ace.ObjectType.ToUpper().Equals("{AB721A53-1E2F-11D0-9819-00AA0040529B}".ToUpper()))
                            {
                                if (ace.Trustee.Equals("Everyone") && (ace.AceType == (int)ADS_ACETYPE_ENUM.ADS_ACETYPE_ACCESS_DENIED_OBJECT))
                                {
                                    everyoneCantChange = true;
                                }
                                if (ace.Trustee.Equals(@"NT AUTHORITY\SELF") && (ace.AceType == (int)ADS_ACETYPE_ENUM.ADS_ACETYPE_ACCESS_DENIED_OBJECT))
                                {
                                    selfCantChange = true;
                                }
                            }
                        }
                        catch (NullReferenceException ex)
                        {
                            //Logger.append(ex.Message);
                        }
                        catch (Exception ex)
                        {
                            Logger.append(ex);
                        }
                    }


                    if (everyoneCantChange || selfCantChange)
                    {
                        cantChange = true;
                    }
                    else
                    {
                        cantChange = false;
                    }

                    user.Close();
                }
                catch (Exception ex)
                {
                    // Log your errors!
                }
            }
            entry.Close();
        }
        catch (Exception ex)
        {
            // Log your errors!
        }
        return cantChange;
    }

.Net 4.0方式

这就是我能够确定的方式.而且很容易修复.但是,我需要使用 我使用的代码段-

Code snippet I used-

    /// <summary>
    /// Check whether password of user cannot be changed.
    /// </summary>
    /// <param name="user">The DirectoryEntry object of user.</param>
    /// <returns>Return true if password cannot be changed else false.</returns>
    public static bool IsPasswordCannotBeChanged(DirectoryEntry user)
    {
        var isUserCantChangePass = false;

        try
        {
            // 1. Get SamAccountName
            var samAccountName = Convert.ToString(user.Properties["sAMAccountName"].Value);
            if (!string.IsNullOrEmpty(samAccountName))
            {
                // 2. Prepare domain context
                using (var domainContext = new PrincipalContext(ContextType.Domain, _domain, _domainUser, _domainPass))
                {
                    // 3. Find user
                    var userPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, samAccountName);

                    // 4. Check if user cannot change password
                    using (userPrincipal)
                        if (userPrincipal != null) isUserCantChangePass = userPrincipal.UserCannotChangePassword;
                }
            }

        }
        catch (Exception exc)
        {
            Logger.Write(exc);
        }

        return isUserCantChangePass;
    }