C# 如何克服;成员';“无法解析s SID”;检查用户是否为组成员时出错?
我们有一个流程,需要检查特定用户是否是本地Administrators组的成员 检查的代码如下所示:C# 如何克服;成员';“无法解析s SID”;检查用户是否为组成员时出错?,c#,active-directory,C#,Active Directory,我们有一个流程,需要检查特定用户是否是本地Administrators组的成员 检查的代码如下所示: using (PrincipalContext context = new PrincipalContext(ContextType.Machine, null)) { UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, sUserName); if (us
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) 不忽视它
谢谢有三种可能的解决方案(均未经测试,将最后一种方案用于所有类型的域组):
1) 加载组并自己枚举成员
2) 加载组的基础对象并使用属性[“Members”],这是一个SID列表。
3) 使用用户的GetAuthorizationGroups()(也将使用您的非直接组,服务帐户最终必须是“Windows授权组”和“PreWindows 2000 Comaptable…”的成员)并使用组列表查找您的管理组。避免错误的一种方法是使用其他方法。 首先检索所有组并检查目标组的列表,而不是检查用户是否是组的成员。一个缺点是:速度较慢
var groups = UserPrincipal.Current.GetAuthorizationGroups();
var found = groups.FirstOrDefault(principal => principal.Name == "Administrators");
var isMemberOfAdminGroup = found != null;
谢谢你的帮助:)这主要是基于我在迈克尔·塞勒(Michael Seier)的著作中的发现。他试图获取本地管理员帐户的SID,而我们只需要该组中的名称。“无法解析成员的SID”错误的原因是,Active Directory中有一些帐户已无法识别,很可能是指向已删除用户帐户的遗迹。你可以按照微软的说法删除它们,希望你的应用不会再次崩溃(尽管下次删除管理员组中的帐户时会崩溃),也可以使用Mike略微修改的代码永久解决问题
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;
}
谢谢你的回复。我会检查能做什么。另外,您可能会推荐一些类似的解决方案来将用户添加到组中?在执行group.Members.Add(user)时也会遇到同样的问题。好吧,底层对象将始终工作,但不如AccountManagement命名空间那么舒适。但是AccountManagement名称空间似乎有一些缺陷,需要解决。你也可以为这些组编写一个修复函数…@TGlatzer:我如何枚举?我在循环时出错了。1.无法列举。正如Rajesh所展示的,它给出了一个例外——微软甚至不在乎修复它,因为他们说解决办法是删除死掉的帐户。2. <加载
DirectoryEntry de=(DirectoryEntry)groupPrincipal.GetUnderlyingObject()时,code>GetUnderlyingObject()未提供任何值。3. GetAuthorizationGroups()
不利于AD,而不是本地计算机或其他远程计算机。它是以广告为中心的,与本地组无关。如果要检查计算机上的本地Administrators组,这将没有帮助。这将在AD中查询Administrators组-这样我们就清楚了。GetAuthorizationGroups()
不符合AD,而不是本地计算机或其他远程计算机。它以广告为中心,与当地团体无关。也就是说,使用内置组的SID查看该组是否在AD管理员组中有点奇怪,但可能会起作用。我没有测试这个,但这有点像是先在谷仓里转一圈,而不是直接进门。
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
}
public static bool UserHasLocalAdminPrivledges(this UserPrincipal up)
{
SecurityIdentifier id = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
return up.GetAuthorizationGroups().Any(g => g.Sid == id)
}