在远程系统上使用c#枚举Windows用户组成员

在C#中,我需要能够

  • 连接到远程系统,根据需要指定用户名/密码
  • 列出该系统上本地组的成员
  • 将结果取回到正在执行的计算机上

因此,例如,我将连接到\ SOMESYSTEM与适当creds,并取回本地pipe理员列表,包括SOMESYSTEM \pipe理员,SOMESYSTEM \鲍勃,DOMAIN \ AlanH,“域\域pipe理员”。

我已经试过这与system.directoryservices.accountmanagement但我遇到了身份validation的问题。 有时我会得到:

不允许同一用户使用多个用户名连接到服务器或共享资源。 断开与服务器或共享资源的所有连接,然后重试。 (来自HRESULT的exception:0x800704C3)

以上是尝试,因为会有情况下,我根本无法取消映射现有的驱动器或UNC连接。

其他时候,我的程序得到UNKNOWN ERROR,远程系统上的安全日志报告错误675,代码0x19是KDC_ERR_PREAUTH_REQUIRED。

我需要一个更简单,更不容易出错的方式来做到这一点!

Solutions Collecting From Web of "在远程系统上使用c#枚举Windows用户组成员"

这应该很容易做到使用WMI。 这里有一个指向一些文档的指针:

Win32_UserAccount的WMI文档

即使您之前没有使用WMI的经验,也应该很容易将页面底部的VB脚本代码转换为一些.NET代码。

希望这有助于!

大卫正走在正确的轨道上,我把他的答案归功于他。

但是,WMI查询所需的时间稍晚一点,因为我不仅需要整个机器的用户列表,而且还需要属于本地管理员组的用户和组的子集(无论是本地还是域)。 为了记录,该WMI查询是:

SELECT PartComponent FROM Win32_GroupUser WHERE GroupComponent = "Win32_Group.Domain='thehostname',Name='thegroupname'" 

以下是完整的代码片段:

 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"; } } 

所以,如果我调用Groupmembers(“server1”,“管理员”,“myusername”,“mypassword”); 我得到一个单一的字符串返回:

SERVER1 \管理员
MYDOMAIN \域管理员

实际的WMI回报更像这样:

\\ SERVER1 \ ROOT \ CIMV2:Win32_UserAccount.Domain = “SERVER 1”,名称= “管理员”

…所以,你可以看到,我不得不做一些小小的字符串操作。

我会建议使用Win32 API函数NetLocalGroupGetMembers 。 比试图找出疯狂的LDAP语法要简单得多,这对于这里推荐的其他一些解决方案是必需的。 只要你模仿用户你想通过调用“LoginUser”来运行检查,你不应该遇到任何安全问题。

你可以在这里找到用于模仿的示例代码。

如果您需要帮助了解如何从C#中调用“NetLocalGroupGetMembers”,我建议您签出Jared Parson的PInvoke助手,您可以从codeplex 下载该助手。

如果您正在IIS中运行的ASP.NET应用程序中运行代码,并且要模拟访问该网站的用户进行呼叫,则可能需要为生产Web服务器授予“可信委派”权限。

如果您正在桌面上运行,那么使用活动用户的安全证书应该不成问题。

网络管理员可能已经取消了您试图访问的特定机器的“安全对象”的访问权限。 不幸的是,所有的网络管理API功能都需要访问。 如果是这种情况,那么您将需要授予对“安全对象”的访问权限,无论您想要执行什么用户。 但是,使用默认的Windows安全设置,所有经过身份验证的用户都应具有访问权

我希望这有帮助。

斯科特

你应该可以通过System.DirectoryServices.DirectoryEntry来做到这一点。 如果您在远程运行时遇到问题,也许可以在远程计算机上安装某些东西,以便通过某种RPC(例如远程或Web服务)为您提供数据。 但是我认为你应该可以做到远程控制而不要太花哨。

如果Windows不允许通过它的登录机制进行连接,我认为你唯一的选择是使用开放端口(直接或通过远程或Web服务,如上所述)在远程机器上运行一些东西。