2012-10-24 42 views
4

我們有一個過程,需要檢查特定用戶是否是本地管理員組的成員。如何在檢查用戶是否是組的成員時克服「成員的SID無法解決」錯誤?

,檢查看起來像以下代碼:

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

有三個不可能性的解決方案(所有未經測試,使用最後自己所有類型的域組):
1)加載組和自己
2枚舉成員)加載底層對象並使用屬性[「成員」],這是一個SID列表。
3)使用用戶的GetAuthorizationGroups()(它也將使用您的非直接組,Service-Account最終必須是「Windows授權組」和「PreWindows 2000 Comaptible ....」的成員),並使用組列表查找您的管理員組。

+0

謝謝你的答覆。我會檢查可以做些什麼。另外,可能你會推薦一些類似的解決方案來將用戶添加到組中?當我們做group.Members.Add(用戶)時,會出現同樣的問題。 –

+0

那麼,底層對象將始終有效,但並不像AccountManagement-Namespace那麼舒服。但似乎AccountManagement-Namespace有一些缺陷,需要解決方法。你也可以編寫修復功能...... – TGlatzer

+1

@TGlatzer:我如何枚舉?循環播放時出現錯誤。 HTTP://計算器。com/questions/35913995/while-trying-to-resolve-a-cross-store-reference-the-sid-of-the-target-principal –

1

避免錯誤的一種方法是採取其他方式。 而不是檢查用戶是否爲組的成員,請首先檢索所有組,然後檢查目標組的列表。一個缺點:速度慢....

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

感謝arus您的幫助:)

+0

如果您想檢查計算機上的本地管理員組,這將無濟於事。這會查詢AD中的管理員組 - 我們很清楚。 – vapcguy

1

這是在http://www.seirer.net/blog/2013/9/12/how-to-deal-with-localized-or-renamed-administrators-in-net邁克爾Seirer書面很大程度上依賴於我的發現。他試圖獲取本地Admin帳戶的SID,而我們所需要的只是該組中的名稱。錯誤原因「會員的SID無法解決」。是因爲有些帳戶在Active Directory中不再被識別 - 可能是指向已刪除用戶帳戶的遺蹟。你可以做任何微軟說的,只是刪除它們,並希望你的應用永遠不會再次崩潰(雖然它會,下一次,一個帳戶被刪除,坐在該管理員組),或永久解決這個代碼,我稍微修改麥克風。

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; 
} 

它將在本地計算機上返回本地管理員組成員的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 
} 
相關問題