我需要测试哪些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),并查询所有本地用户,而不仅仅是当前用户。
答案 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();
}
}