我们有一个流程需要检查特定用户是否是本地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)不要忽视它?
由于
答案 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 ....”的成员)并使用组列表查找您的管理员组。