Pregunta

Dentro de C#, necesito poder

  • Conéctese a un sistema remoto, especificando nombre de usuario/contraseña según corresponda
  • Enumerar los miembros de un grupo local en ese sistema
  • Recuperar los resultados en la computadora en ejecución

Entonces, por ejemplo, me conectaría a \SOMESYSTEM con los créditos apropiados y recuperaría una lista de administradores locales, incluidos SOMESYSTEM\Administrator, SOMESYSTEM\Bob, DOMAIN\AlanH, "DOMAIN\Domain Administrators".

Probé esto con system.directoryservices.accountmanagement pero tengo problemas con la autenticación.A veces obtengo:

No se permiten múltiples conexiones a un servidor o recurso compartido por parte del mismo usuario, utilizando más de un nombre de usuario.Desconecte todas las conexiones anteriores al servidor o recurso compartido y vuelva a intentarlo.(Excepción de HRESULT:0x800704C3)

Lo anterior es una prueba porque habrá situaciones en las que simplemente no puedo desasignar unidades existentes o conexiones UNC.

Otras veces mi programa recibe un ERROR DESCONOCIDO y el registro de seguridad en el sistema remoto informa un error 675, código 0x19 que es KDC_ERR_PREAUTH_REQUIRED.

¡Necesito una forma más sencilla y menos propensa a errores de hacer esto!

¿Fue útil?

Solución

Esto debería ser fácil de hacer usando WMI.Aquí tienes un puntero a algunos documentos:

Documentación de WMI para Win32_UserAccount

Incluso si no tiene experiencia previa con WMI, debería ser bastante fácil convertir ese código VB Script en la parte inferior de la página en algún código .NET.

¡Espero que esto haya ayudado!

Otros consejos

Davidg estaba en el camino correcto y le doy el crédito por la respuesta.

Pero la consulta WMI necesaria fue un poco menos sencilla, ya que no solo necesitaba una lista de usuarios para toda la máquina, sino también el subconjunto de usuarios. y grupos, ya sean locales o de dominio, que fueran miembros del grupo de Administradores local.Para que conste, esa consulta WMI fue:

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

Aquí está el fragmento de código completo:

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

Entonces, si invoco Groupmembers("Server1", "Administrators", "myusername", "mypassword");Recibo una sola cadena devuelta con:

SERVIDOR1\Administrador
MIDOMINIO\Administradores de dominio

El retorno real de WMI es más parecido a esto:

\\SERVIDOR1 oot\cimv2:Win32_UserAccount.Domain="SERVIDOR1",Nombre="Administrador"

...Como puedes ver, tuve que manipular un poco las cuerdas para embellecerlo.

Recomendaría usar la función API de Win32. NetLocalGroupGetMembers.Es mucho más sencillo que intentar descifrar la loca sintaxis LDAP, que es necesaria para algunas de las otras soluciones recomendadas aquí.Siempre que se haga pasar por el usuario que desea ejecutar la verificación llamando a "LoginUser", no debería encontrarse con ningún problema de seguridad.

Puede encontrar un código de muestra para realizar la suplantación. aquí.

Si necesita ayuda para descubrir cómo llamar a "NetLocalGroupGetMembers" desde C#, le recomiendo que consulte el asistente PInvoke de Jared Parson, que puede descargar de codeplex.

Si está ejecutando el código en una aplicación ASP.NET que se ejecuta en IIS y desea hacerse pasar por el usuario que accede al sitio web para realizar la llamada, es posible que deba otorgar el permiso "Confiable para delegación" al servidor web de producción.

Si está ejecutando en el escritorio, usar las credenciales de seguridad del usuario activo no debería ser un problema.

Es posible que su administrador de red haya revocado el acceso al "Objeto Protegible" para la máquina en particular a la que está intentando acceder.Lamentablemente ese acceso es necesario para todos los API de gestión de red funciones para trabajar.Si ese es el caso, deberá otorgar acceso al "Objeto seguro" a los usuarios con los que desee ejecutar.Sin embargo, con la configuración de seguridad predeterminada de Windows, todos los usuarios autenticados deberían tener acceso.

Espero que esto ayude.

-Scott

Debería poder hacer esto con System.DirectoryServices.DirectoryEntry.Si tiene problemas para ejecutarlo de forma remota, tal vez pueda instalar algo en las máquinas remotas para brindarle sus datos a través de algún tipo de RPC, como comunicación remota o un servicio web.Pero creo que lo que estás intentando debería ser posible de forma remota sin ser demasiado sofisticado.

Si Windows no le permite conectarse a través de su mecanismo de inicio de sesión, creo que su única opción es ejecutar algo en la máquina remota con un puerto abierto (ya sea directamente o mediante comunicación remota o un servicio web, como se mencionó).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top