非域环境下如何快速找到交互式用户组SID并添加至Event Log Readers组?
非域环境下如何快速找到交互式用户组SID并添加至Event Log Readers组?
首先得跟你说个关键点:你其实已经拿到交互式用户的SID了!WellKnownSidType.InteractiveSid就是它的正确标识,之所以用PrincipalSearcher搜不到,是因为交互式用户(Interactive)不是一个常规的本地组,它是Windows内置的特殊安全主体,不会出现在常规的组列表里,所以遍历本地组自然找不到它~
之前的代码慢,主要是因为GroupPrincipal和Principal这些封装类在非域环境下会做一些额外的系统查询,拖慢了速度。咱们可以换用更底层的DirectoryEntry来操作,直接对接Windows的ADSI接口,速度会快很多,而且逻辑也不复杂。
下面是优化后的代码,我给你加了详细注释,你直接用就行:
using System.DirectoryServices; using System.Security.Principal; // 1. 直接获取两个内置SID,这一步你原来的写法完全正确 var eventLogReadersSid = new SecurityIdentifier(WellKnownSidType.WinBuiltinEventLogReadersGroup, null); var interactiveUsersSid = new SecurityIdentifier(WellKnownSidType.InteractiveSid, null); // 2. 用DirectoryEntry直接打开本地机器的组容器 using (var localMachine = new DirectoryEntry("WinNT://./computer,computer")) { // 3. 找到Event Log Readers组(先把SID转成NT账户名再查找) using (var eventLogReadersGroup = localMachine.Children.Find( eventLogReadersSid.Translate(typeof(NTAccount)).Value, "group")) { // 4. 把交互式用户的SID转换成可添加的账户格式 var interactiveAccount = new NTAccount(interactiveUsersSid.Translate(typeof(NTAccount)).Value); var interactiveSidString = interactiveUsersSid.ToString(); // 5. 检查组内是否已存在该成员,避免重复添加 bool isAlreadyMember = false; foreach (object member in eventLogReadersGroup.Invoke("Members", null)) { using (var memberEntry = new DirectoryEntry(member)) { var memberSid = new SecurityIdentifier((byte[])memberEntry.Properties["objectSid"].Value, 0); if (memberSid.ToString() == interactiveSidString) { isAlreadyMember = true; break; } } } // 6. 如果不存在就添加并保存更改 if (!isAlreadyMember) { eventLogReadersGroup.Invoke("Add", new object[] { interactiveAccount.ToString() }); eventLogReadersGroup.CommitChanges(); DebugLog($"用户({interactiveAccount.Value})已添加至Event Log Readers组"); } } }
为什么这个方法更快?
- 跳过了
PrincipalContext和GroupPrincipal这些封装层,直接和Windows本地目录服务交互,减少了不必要的中间查询步骤 - 用
DirectoryEntry.Invoke直接调用ADSI原生方法,比Principal类的成员检查逻辑更高效
另外提醒你:运行这段代码需要管理员权限,不然会没有修改组的权限哦~
备注:内容来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

