我需要测试哪些Windows用户具有管理员权限。
好的,现在仔细阅读:不是当前用户。我查询所有本地用户帐户,然后测试其中哪一个具有管理员权限。假设我以 Joe 身份登录,我的应用程序在 Joe 用户的上下文中运行,但这台电脑上有一个用户 Timmy,他当前未登录。我需要测试提米在这台电脑上是否有管理员。因此,这个问题绝对不是关于当前用户权限;)因此,这绝对不是有关确定当前用户权限的类似问题的重复。这个是不同的;)
这是我的代码:
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
。阿法克不能。WindowsIdentity
的用户需要登录(如果没有,则抛出SecurityException),我查询所有本地用户,而不仅仅是当前用户。
好吧,我发现了,但它仍然很奇怪...
更新的代码:(我将匹配组名称更改为匹配组 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 毫秒,而不是 2300 毫秒IsMemberOf()
。
作为奖励,我将与我的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();
}
}