在检查用户是否是组成员时,如何克服“成员的SID无法解决”错误?

时间:2012-10-24 13:36:22

标签: c# active-directory

我们有一个流程需要检查特定用户是否是本地Administrators组的成员。

检查如下所示的代码:

using (PrincipalContext context = new PrincipalContext(ContextType.Machine, null))
{
    UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, sUserName);
    if (user != null)
    {
         SecurityIdentifier adminsGroupSID = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
         GroupPrincipal group = GroupPrincipal.FindByIdentity(context, IdentityType.Sid, adminsGroupSID.Value);
         if (group != null)
         {
             if (user.IsMemberOf(group))
                 return 0;
         }
    }
}

当该组具有已删除的帐户(例如域帐户)时,我们将收到PrincipalOperationException并显示消息“枚举组成员身份时发生错误(1332)。该成员的SID无法解析。”

有没有办法克服这个没有: a)从组中手动删除孤立的SID b)不要忽视它?

由于

5 个答案:

答案 0 :(得分:2)

这很大程度上取决于我在Michael {Seirer撰写的http://www.seirer.net/blog/2013/9/12/how-to-deal-with-localized-or-renamed-administrators-in-net中的发现。他试图获取本地Admin帐户的SID,而我们需要的只是该组中的名称。出错的原因"会员的SID无法解决。"是因为有些帐户在Active Directory中不再被识别 - 可能是指向已删除用户帐户的文件。您可以执行Microsoft所说的操作并删除它们,并希望您的应用程序永远不会崩溃(尽管它会在下次删除该管理员组中的帐户时),或者使用此代码永久解决它我稍微修改自麦克

using System.DirectoryServices;
using System.Collections;
using System.Runtime.InteropServices;

[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);

private static string GetTextualSID(DirectoryEntry objGroup)
{
    string sSID = string.Empty;
    byte[] SID = objGroup.Properties["objectSID"].Value as byte[];
    IntPtr sidPtr = Marshal.AllocHGlobal(SID.Length);
    sSID = "";
    System.Runtime.InteropServices.Marshal.Copy(SID, 0, sidPtr, SID.Length);
    ConvertSidToStringSid((IntPtr)sidPtr, out sSID);
    System.Runtime.InteropServices.Marshal.FreeHGlobal(sidPtr);
    return sSID; 
}


public static List<string> GetLocalAdministratorsNames()
{
    List<string> admins = new List<string>();
    DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
    string adminsSID = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).ToString();

    string localizedAdmin = new System.Security.Principal.SecurityIdentifier(adminsSID).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

    localizedAdmin = localizedAdmin.Replace(@"BUILTIN\", "");

    DirectoryEntry admGroup = localMachine.Children.Find(localizedAdmin, "group");
    object adminmembers = admGroup.Invoke("members", null);

    DirectoryEntry userGroup = localMachine.Children.Find("users", "group");
    object usermembers = userGroup.Invoke("members", null);

    //Retrieve each user name.
    foreach (object groupMember in (IEnumerable)adminmembers)
    {
        DirectoryEntry member = new DirectoryEntry(groupMember);

        string sidAsText = GetTextualSID(member);
        admins.Add(member.Name);            
    }
    return admins;
}

它将返回本地计算机上本地Administrators组的List<string>个成员。如果您不想使用本地计算机,您甚至可以将Environment.MachineName更改为您域中的任何计算机名称。

然后你可以迭代列表,看看它们是否在其中:

private static bool isAdmin(string user)
{
    //string user = @"DOMAIN\doej";
    user = user.Split(@'\')[1];

    List<string> admins = GetLocalAdministratorsNames();
    foreach (string s in admins)
    {
        if (s == user)
            return true; // admin found
    }
    return false;  // not an admin
}

答案 1 :(得分:0)

避免错误的一种方法是反过来。 不是检查用户是否是组的成员,而是先检索所有组并检查目标组的列表。一个缺点:比较慢......

var groups = UserPrincipal.Current.GetAuthorizationGroups();
var found = groups.FirstOrDefault(principal => principal.Name == "Administrators");
var isMemberOfAdminGroup = found != null;

感谢arus求助:)

答案 2 :(得分:0)

public static bool UserHasLocalAdminPrivledges(this UserPrincipal up)
{
   SecurityIdentifier id = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
   return up.GetAuthorizationGroups().Any(g => g.Sid == id)
}

答案 3 :(得分:0)

近十年后,即使在 .NET 4.x 和 5.x 中,这仍然是一个问题。解决此错误的另一种方法是基本上解构 npm install @material-ui/data-grid 语句背后的代码并制作您自己的搜索列表。您需要获取 Enumerator,然后在 Try/Catch 中调用 MoveNext。我最初担心如果它抛出异常它不会移动到下一个,但它确实如此,所以这是有效的。它并不漂亮,但我已经对其进行了测试并且对我有用。

foreach

答案 4 :(得分:-1)

有三种可能的解决方案(所有未经测试的解决方案,使用最后一个自己用于所有类型的域组):
1)加载组并自己枚举成员
2)加载组的基础对象并使用属性[“Members”],这是一个SID列表 3)使用用户的GetAuthorizationGroups()(也将使用您的非直接组,Service-Account必须是“Windows授权组”和“PreWindows 2000 Comaptible ....”的成员)并使用组列表查找您的管理员组。