使用c#枚举远程系统上的Windows用户组成员
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Enumerate Windows user group members on remote system using c#
提问by quux
Within c#, I need to be able to
在 c# 中,我需要能够
- Connect to a remote system, specifying username/password as appropriate
- List the members of a localgroup on that system
- Fetch the results back to the executing computer
- 连接到远程系统,根据需要指定用户名/密码
- 列出该系统上本地组的成员
- 将结果取回执行计算机
So for example I would connect to \SOMESYSTEM with appropriate creds, and fetch back a list of local administrators including SOMESYSTEM\Administrator, SOMESYSTEM\Bob, DOMAIN\AlanH, "DOMAIN\Domain Administrators".
例如,我会使用适当的凭据连接到 \SOMESYSTEM,并取回本地管理员列表,包括 SOMESYSTEM\Administrator、SOMESYSTEM\Bob、DOMAIN\AlanH、“DOMAIN\Domain Administrators”。
I've tried this with system.directoryservices.accountmanagement but am running into problems with authentication. Sometimes I get:
我已经用 system.directoryservices.accountmanagement 尝试过这个,但遇到了身份验证问题。有时我得到:
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again. (Exception from HRESULT: 0x800704C3)
不允许同一用户使用多个用户名多次连接到服务器或共享资源。断开与服务器或共享资源的所有先前连接,然后重试。(来自 HRESULT 的异常:0x800704C3)
The above is trying because there will be situations where I simply cannot unmap existing drives or UNC connections.
以上是尝试,因为在某些情况下,我根本无法取消映射现有驱动器或 UNC 连接。
Other times my program gets UNKNOWN ERROR and the security log on the remote system reports an error 675, code 0x19 which is KDC_ERR_PREAUTH_REQUIRED.
其他时候,我的程序出现未知错误,远程系统上的安全日志报告错误 675,代码 0x19,即 KDC_ERR_PREAUTH_REQUIRED。
I need a simpler and less error prone way to do this!
我需要一种更简单且不易出错的方法来做到这一点!
采纳答案by dguaraglia
This should be easy to do using WMI. Here you have a pointer to some docs:
使用 WMI 应该很容易做到这一点。这里有一个指向一些文档的指针:
WMI Documentation for Win32_UserAccount
Even if you have no previous experience with WMI, it should be quite easy to turn that VB Script code at the bottom of the page into some .NET code.
即使您以前没有使用 WMI 的经验,也应该很容易将页面底部的 VB 脚本代码转换为一些 .NET 代码。
Hope this helped!
希望这有帮助!
回答by Eric Z Beard
You should be able to do this with System.DirectoryServices.DirectoryEntry. If you are having trouble running it remotely, maybe you could install something on the remote machines to give you your data via some sort of RPC, like remoting or a web service. But I think what you're trying should be possible remotely without getting too fancy.
您应该可以使用 System.DirectoryServices.DirectoryEntry 来做到这一点。如果您在远程运行它时遇到问题,也许您可以在远程机器上安装一些东西,以通过某种 RPC(例如远程处理或 Web 服务)为您提供数据。但我认为你正在尝试的东西应该可以远程实现,而不会太花哨。
回答by Nick
If Windows won't let you connect through it's login mechanism, I think your only option is to run something on the remote machine with an open port (either directly or through remoting or a web service, as mentioned).
如果 Windows 不允许您通过其登录机制进行连接,我认为您唯一的选择是在具有开放端口的远程计算机上运行某些内容(直接或通过远程处理或 Web 服务,如上所述)。
回答by Scott Wisniewski
I would recommend using the Win32 API function NetLocalGroupGetMembers. It is much more straight forward than trying to figure out the crazy LDAP syntax, which is necessary for some of the other solutions recommended here. As long as you impersonate the user you want to run the check as by calling "LoginUser", you should not run into any security issues.
我建议使用 Win32 API 函数NetLocalGroupGetMembers。它比试图找出疯狂的 LDAP 语法要直接得多,这对于这里推荐的其他一些解决方案是必要的。只要您通过调用“LoginUser”模拟要运行检查的用户,就不会遇到任何安全问题。
You can find sample code for doing the impersonation here.
您可以在此处找到进行模拟的示例代码。
If you need help figuring out how to call "NetLocalGroupGetMembers" from C#, I reccomend that you checkout Jared Parson's PInvoke assistant, which you can downloadfrom codeplex.
如果您需要帮助弄清楚如何从 C# 调用“NetLocalGroupGetMembers”,我建议您查看 Jared Parson 的 PInvoke 助手,您可以从 codeplex下载。
If you are running the code in an ASP.NET app running in IIS, and want to impersonate the user accessing the website in order to make the call, then you may need to grant "Trusted for Delegation" permission to the production web server.
如果您在 IIS 中运行的 ASP.NET 应用程序中运行代码,并且想要模拟访问网站的用户以进行调用,则您可能需要向生产 Web 服务器授予“受信任的委派”权限。
If you are running on the desktop, then using the active user's security credentials should not be a problem.
如果您在桌面上运行,那么使用活动用户的安全凭证应该不是问题。
It is possible that you network admin could have revoked access to the "Securable Object" for the particular machine you are trying to access. Unfortunately that access is necessary for all of the network management apifunctions to work. If that is the case, then you will need to grant access to the "Securable Object" for whatever users you want to execute as. With the default windows security settings all authenticated users should have access, however.
您的网络管理员可能已经撤销了您尝试访问的特定机器对“安全对象”的访问权限。不幸的是,所有网络管理 api功能都需要访问权限才能工作。如果是这种情况,那么您将需要为您想要执行的任何用户授予对“安全对象”的访问权限。但是,使用默认的 Windows 安全设置,所有经过身份验证的用户都应该具有访问权限。
I hope this helps.
我希望这有帮助。
-Scott
-斯科特
回答by quux
davidg was on the right track, and I am crediting him with the answer.
davidg 走在正确的轨道上,我相信他的答案。
But the WMI query necessary was a little less than straightfoward, since I needed not just a list of users for the whole machine, but the subset of users and groups, whether local or domain, that were members of the local Administrators group. For the record, that WMI query was:
但是所需的 WMI 查询并不简单,因为我不仅需要整个机器的用户列表,还需要属于本地管理员组成员的用户和组的子集,无论是本地还是域。作为记录,该 WMI 查询是:
SELECT PartComponent FROM Win32_GroupUser WHERE GroupComponent = "Win32_Group.Domain='thehostname',Name='thegroupname'"
Here's the full code snippet:
这是完整的代码片段:
public string GroupMembers(string targethost, string groupname, string targetusername, string targetpassword)
{
StringBuilder result = new StringBuilder();
try
{
ConnectionOptions Conn = new ConnectionOptions();
if (targethost != Environment.MachineName) //WMI errors if creds given for localhost
{
Conn.Username = targetusername; //can be null
Conn.Password = targetpassword; //can be null
}
Conn.Timeout = TimeSpan.FromSeconds(2);
ManagementScope scope = new ManagementScope("\\" + targethost + "\root\cimv2", Conn);
scope.Connect();
StringBuilder qs = new StringBuilder();
qs.Append("SELECT PartComponent FROM Win32_GroupUser WHERE GroupComponent = \"Win32_Group.Domain='");
qs.Append(targethost);
qs.Append("',Name='");
qs.Append(groupname);
qs.AppendLine("'\"");
ObjectQuery query = new ObjectQuery(qs.ToString());
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
ManagementPath path = new ManagementPath(m["PartComponent"].ToString());
{
String[] names = path.RelativePath.Split(',');
result.Append(names[0].Substring(names[0].IndexOf("=") + 1).Replace("\"", " ").Trim() + "\");
result.AppendLine(names[1].Substring(names[1].IndexOf("=") + 1).Replace("\"", " ").Trim());
}
}
return result.ToString();
}
catch (Exception e)
{
Console.WriteLine("Error. Message: " + e.Message);
return "fail";
}
}
So, if I invoke Groupmembers("Server1", "Administrators", "myusername", "mypassword"); I get a single string returned with:
所以,如果我调用 Groupmembers("Server1", "Administrators", "myusername", "mypassword"); 我得到一个返回的字符串:
SERVER1\Administrator
MYDOMAIN\Domain Admins
SERVER1\Administrator
MYDOMAIN\Domain Admins
The actual WMI return is more like this:
实际的 WMI 返回更像这样:
\\SERVER1\root\cimv2:Win32_UserAccount.Domain="SERVER1",Name="Administrator"
\\SERVER1\root\cimv2:Win32_UserAccount.Domain="SERVER1",Name="管理员"
... so as you can see, I had to do a little string manipulation to pretty it up.
...正如你所看到的,我不得不做一些字符串操作来美化它。