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

时间:2008-08-22 00:29:06

标签: c# windows user-management usergroups

在c#中,我需要能够

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

例如,我将使用适当的信用连接到\ SOMESYSTEM,并获取本地管理员列表,包括SOMESYSTEM \ Administrator,SOMESYSTEM \ Bob,DOMAIN \ AlanH,“DOMAIN \ Domain Administrators”。

我用system.directoryservices.accountmanagement尝试了这个,但遇到了身份验证问题。有时我得到:

不允许同一用户使用多个用户名与服务器或共享资源建立多个连接。断开与服务器或共享资源的所有先前连接,然后重试。 (HRESULT异常:0x800704C3)

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

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

我需要一种更简单且不易出错的方法来做到这一点!

5 个答案:

答案 0 :(得分:2)

davidg走在正确的轨道上,我正在给他答案。

但是必要的WMI查询比直接更少,因为我不仅需要整个机器的用户列表,而且需要用户和组的子集,无论是本地还是域,是本地Administrators组的成员。为了记录,该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”,“Administrators”,“myusername”,“mypassword”);我得到一个返回的字符串:

SERVER1 \管理员
MYDOMAIN \ Domain Admins

实际的WMI回报更像是这样:

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

...所以你可以看到,我不得不做一些小的字符串操作来完善它。

答案 1 :(得分:1)

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

WMI Documentation for Win32_UserAccount

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

希望这有帮助!

答案 2 :(得分:1)

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

您可以找到进行模拟的示例代码here

如果你需要帮助搞清楚如何从C#调用“NetLocalGroupGetMembers”,我建议你查看Jared Parson的PInvoke助手,你可以从codeplex download

如果您在IIS中运行的ASP.NET应用程序中运行代码,并且想要模拟访问网站以进行调用的用户,那么您可能需要向生产授予“Trusted for Delegation”权限网络服务器。

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

网络管理员可能已撤消对您尝试访问的特定计算机的“安全对象”的访问权限。不幸的是,所有network management api函数都需要访问才能工作。如果是这种情况,那么您将需要为要执行的任何用户授予对“安全对象”的访问权限。但是,使用默认的Windows安全设置,所有经过身份验证的用户都应具有访问权限。

我希望这会有所帮助。

-Scott

答案 3 :(得分:0)

您应该可以使用System.DirectoryServices.DirectoryEntry执行此操作。如果您无法远程运行它,也许您可​​以在远程计算机上安装一些东西,通过某种RPC(如远程处理或Web服务)为您提供数据。但我认为你所尝试的应该可以远程进行而不会过于花哨。

答案 4 :(得分:0)

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