测试(非当前)用户是否为管理员的更快方法
Faster method to test if (not current) user is an administrator
我需要测试哪些 Windows 用户拥有管理员权限。
好的,现在仔细阅读:不是当前用户。我查询所有本地用户帐户,然后测试其中一个具有管理员权限。假设我以 Joe 身份登录,我的应用程序在 Joe 用户的上下文中运行,但是这台 PC 上有一个用户 Timmy,他当前未登录。我需要测试 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 和 returns 结果作为托管 dynamic
对象而不是 IDisposable
类型的数组。 IDisposable
类型在返回结果之前被释放。不过与问题无关。
为了澄清,我使用 System.DirectoryServices.AccountManagement
从 SID 获取实际用户帐户。我不知道 WindowsIdentity
是否可以从 SID 创建。 AFAIK 它不能。 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();
}
}
我需要测试哪些 Windows 用户拥有管理员权限。
好的,现在仔细阅读:不是当前用户。我查询所有本地用户帐户,然后测试其中一个具有管理员权限。假设我以 Joe 身份登录,我的应用程序在 Joe 用户的上下文中运行,但是这台 PC 上有一个用户 Timmy,他当前未登录。我需要测试 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 和 returns 结果作为托管 dynamic
对象而不是 IDisposable
类型的数组。 IDisposable
类型在返回结果之前被释放。不过与问题无关。
为了澄清,我使用 System.DirectoryServices.AccountManagement
从 SID 获取实际用户帐户。我不知道 WindowsIdentity
是否可以从 SID 创建。 AFAIK 它不能。 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();
}
}