【问题标题】:Active Directory Acquiring Locked/Unlocked status in a Windows ServiceActive Directory 在 Windows 服务中获取锁定/解锁状态
【发布时间】:2015-06-29 19:39:33
【问题描述】:

我正在制作一个 Windows 服务,它可以获取本地域 TRY.local 中所有 Active Directory 帐户的锁定/解锁状态。 即使名为 user1 的帐户被锁定,它也会为 IsAccountLocked() 提供 false 值。

using (var context = new PrincipalContext(ContextType.Domain, "TRY.local"))
{
    using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
    {
        foreach (var result in searcher.FindAll())
        {
            DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
            Library.WriteErrorLog("First Name: " + de.Properties["givenName"].Value);
            try{
                string name = (string)de.Properties["samaccountname"].Value;
                PrincipalContext ctx = new PrincipalContext(ContextType.Domain,"TRY.local","CN="+name+",OU=Users,DC=TRY,DC=local","administrator","password");
                UserPrincipal usr = UserPrincipal.FindByIdentity(ctx, name);
                if(usr!=null){
                    Library.WriteErrorLog("IsAccountLockedOut\t"+usr.IsAccountLockedOut());
                }
                usr.Dispose();
                ctx.Dispose();
            }
        catch(Exception e){                                         
            Library.WriteErrorLog(e);
        }
    }
}

我也试过

using (var context = new PrincipalContext(ContextType.Domain, "TRY.local"))
{
    using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
    {
        foreach (var result in searcher.FindAll())
        {
            DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
            Library.WriteErrorLog("SAM Account Name : " + de.Properties["samaccountname"].Value);
            int uc = Convert.ToInt32(de.Properties["userAccountControl"][0]);
            const int ADS_LOCKOUT = 0x00000010;
            bool account_LockedOut = (uc & ADS_LOCKOUT)==ADS_LOCKOUT;
            Library.WriteErrorLog("IsAccountLockedOut : "+account_LockedOut);                                       
        }
    }
}

WriteErrorLog(string abc) 将 abc 写入文本文件

由于我是 Active Directory 的新手,如果能获得有关此问题的指导,我将不胜感激。 提前致谢!

【问题讨论】:

  • 最简单的方法是使用微软制作的LOCKOUT.EXE。 microsoft.com/en-gb/download/details.aspx?id=15201 或者您的问题还有其他我不明白的地方吗?
  • 我必须检查所有用户帐户,而不仅仅是一个。其次,我的程序是一个服务,所以我对 LOCKOUT.EXE 有点怀疑。我的主要要求是获取域上每个用户的锁定状态并不断更新它(目前,我每 50 秒更新一次)。
  • 现在请原谅我非常偏爱 Powershell 但blogs.technet.com/b/heyscriptingguy/archive/2011/08/31/… 解释了如何获取锁定状态,这样您就可以让它每 50 秒轮询一次并作为后台作业运行,现在为了便于阅读,我建议也做一个 HTML 输出。
  • 服务是否在域控制器上运行? (它与您在 GUI 中查看的域控制器是否相同?)服务配置为在什么安全上下文中运行?
  • 我不认为这会给它足够的访问权限。尝试网络服务或本地系统。

标签: c# active-directory windows-services windows-server-2012-r2


【解决方案1】:

您必须拥有有效的网络凭据才能查询 Active Directory。

当服务作为本地服务运行时,它没有网络凭据 - 它只能在本地系统上运行。如果您需要网络凭据,请将服务配置为作为网络服务运行。 (如果您需要本地计算机上的管理员访问权限,请使用本地系统;这具有网络凭据和本地管理员访问权限。)

作为网络服务或本地系统运行的服务在访问网络时使用计算机的 Active Directory 帐户,即,如果计算机名为 PLUGH,则用于访问网络的用户名是 PLUGH$

【讨论】:

    【解决方案2】:

    我发现当 UserPrincipal 对象用于获取帐户的锁定状态时,整个 LDAP 路径直到用户所在的组织单位(OU)是否存在应作为参数提供给 PrincipalContext 以及管理员登录名和密码。

    例如:

    using (var context = new PrincipalContext(ContextType.Domain, "TRY.local"))
    {
        using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
        {
            foreach (var result in searcher.FindAll())
            {
                DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
                string path = de.Path;
                var offset = path.IndexOf('/');
                offset = path.IndexOf('/', offset+1);
                offset = path.IndexOf('/', offset+1);
                path = path.Substring(offset+1);
                string user_id = Convert.ToString(de.Properties["samaccountname"].Value); 
    
                PrincipalContext ctx = new PrincipalContext(ContextType.Domain,
                                           "TRY.local",
                                           path,
                                           "administrator",
                                           "password");
    

    要使用 UserPrincipal,我们现在将 ctx 和 user_id 作为参数传递给 UserPrincipal.FindByIdentity(PrincipalContext, string) 方法。

    字符串路径最终会包含:"CN=User,OU=USERS,OU=DEPARTMENT,DC=SERVER,DC=COM"

    UserPrincipal user_locked = UserPrincipal.FindByIdentity(ctx, username);
    if (user_locked != null) {
        if (user_locked.IsAccountLockedOut()){
           user_locked.UnlockAccount();                                         
        }
        user_locked.Dispose();
        Console.WriteLine("Unlocked");
    }
    ctx.Dispose();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 2016-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多