更快速的方法来测试用户是否是管理员

时间:2017-01-27 11:03:13

标签: c# windows windows-security

我需要测试哪些Windows用户具有管理员权限。

好的,现在仔细阅读: NOT CURRENT USER 。我查询所有本地用户帐户,然后测试其中哪一个具有管理员权限。假设我已经记录为Joe,我的应用程序在Joe用户的上下文中运行,但是在这台PC上有一个用户Timmy,他当前没有登录。我需要测试Timmy是否在这台PC上有管理员。所以,这个问题绝对不是当前的用户权限;)因此,这绝对不是关于确定当前用户权限的类似问题的重复。这个是不同的;)

这是我的代码:

public static dynamic[] Users => WMI.Query("SELECT * FROM Win32_UserAccount WHERE Disabled = 0").Select<dynamic, dynamic>(d => {
    var machineContext = new PrincipalContext(ContextType.Machine);
    Principal principal = Principal.FindByIdentity(machineContext, d.SID);
    d.IsAdmin = principal.IsMemberOf(machineContext, IdentityType.Name, "Administrators");
    principal.Dispose();
    machineContext.Dispose();
    return d;
}).ToArray();

这有效,但执行IsMemberOf()需要超过2秒。 有更快的方法吗? 为什么这么慢?

如果你想知道WMI.Query在这里做了什么,它只是查询WMI并将结果作为托管dynamic对象的数组而不是IDisposable类型返回。在返回结果之前处置IDisposable类型。但问题与此无关。

为了澄清,我使用System.DirectoryServices.AccountManagement从SID获取实际的用户帐户。我不知道是否可以从SID创建WindowsIdentity。 AFAIK它不能。 WindowsIdentity的用户需要登录(如果没有,则抛出SecurityException),并查询所有本地用户,而不仅仅是当前用户。

1 个答案:

答案 0 :(得分:1)

好吧,我发现了它,但它仍然很奇怪......

更新了代码:(我将匹配的组名更改为匹配的组SID)。

public static dynamic[] Users => WMI.Query("SELECT * FROM Win32_UserAccount WHERE Disabled = 0").Select<dynamic, dynamic>(d => {
    using (var machineContext = new PrincipalContext(ContextType.Machine))
    using (Principal principal = Principal.FindByIdentity(machineContext, d.SID))
    d.IsAdmin = principal.GetGroups().Any(i => i.Sid.IsWellKnown(System.Security.Principal.WellKnownSidType.BuiltinAdministratorsSid));
    return d;
}).ToArray();

结果GetGroups()IsMemberOf()更快。

更新:实际上大约快了135倍。 GetGroups() Any()花费了17毫秒而非IsMemberOf()花了2300毫秒。

作为奖励,我将与我的WMI.Query分享;)

/// <summary>
/// Safe, managed WMI queries support.
/// </summary>
static class WMI {

/// <summary>
/// Queries WMI and returns results as an array of dynamic objects.
/// </summary>
/// <param name="q"></param>
/// <returns></returns>
public static dynamic[] Query(string q) {
    using (var s = new ManagementObjectSearcher(q))
        return
            s
            .Get()
            .OfType<ManagementObject>()
            .Select(i => {
                var x = new ExpandoObject();
                using (i) foreach (var p in i.Properties) (x as IDictionary<string, object>).Add(p.Name, p.Value);
                return x;
            })
            .ToArray();
    }
}