Énumérer les membres du groupe d'utilisateurs Windows sur le système distant à l'aide de C#

StackOverflow https://stackoverflow.com/questions/21514

Question

En C#, je dois pouvoir

  • Connectez-vous à un système distant, en spécifiant le nom d'utilisateur/mot de passe approprié
  • Répertorier les membres d'un groupe local sur ce système
  • Récupérer les résultats sur l'ordinateur d'exécution

Ainsi, par exemple, je me connecterais à \SOMESYSTEM avec les informations d'identification appropriées et récupérerais une liste d'administrateurs locaux, notamment SOMESYSTEM\Administrator, SOMESYSTEM\Bob, DOMAIN\AlanH, "DOMAIN\Domain Administrators".

J'ai essayé cela avec system.directoryservices.accountmanagement mais je rencontre des problèmes d'authentification.Parfois j'obtiens :

Les connexions multiples à un serveur ou à une ressource partagée par le même utilisateur, utilisant plusieurs noms d'utilisateur, ne sont pas autorisées.Déconnectez toutes les connexions précédentes au serveur ou à la ressource partagée et réessayez.(Exception de HRESULT :0x800704C3)

Ce qui précède est un essai car il y aura des situations dans lesquelles je ne pourrai tout simplement pas démapper les lecteurs existants ou les connexions UNC.

D'autres fois, mon programme obtient une ERREUR INCONNUE et le journal de sécurité sur le système distant signale une erreur 675, code 0x19 qui est KDC_ERR_PREAUTH_REQUIRED.

J'ai besoin d'un moyen plus simple et moins sujet aux erreurs de procéder !

Était-ce utile?

La solution

Cela devrait être facile à faire avec WMI.Ici vous avez un pointeur vers quelques documents :

Documentation WMI pour Win32_UserAccount

Même si vous n'avez aucune expérience avec WMI, il devrait être assez facile de transformer ce code VB Script au bas de la page en code .NET.

J'espère que cela a aidé !

Autres conseils

Davidg était sur la bonne voie et je lui attribue la réponse.

Mais la requête WMI nécessaire était un peu moins simple, car j'avais besoin non seulement d'une liste d'utilisateurs pour l'ensemble de la machine, mais aussi du sous-ensemble d'utilisateurs. et groupes, qu'ils soient locaux ou de domaine, qui étaient membres du groupe Administrateurs local.Pour mémoire, cette requête WMI était :

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

Voici l'extrait de code complet :

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

Donc, si j'invoque Groupmembers("Server1", "Administrators", "myusername", "mypassword");Je reçois une seule chaîne renvoyée avec :

SERVEUR1\Administrateur
MON DOMAINE\Administrateurs de domaine

Le retour WMI réel ressemble davantage à ceci :

\\SERVER1 oot\cimv2:Win32_UserAccount.Domain="SERVER1",Name="Administrateur"

...donc comme vous pouvez le voir, j'ai dû faire une petite manipulation de cordes pour l'embellir.

Je recommanderais d'utiliser la fonction API Win32 NetLocalGroupGetMembers.C'est beaucoup plus simple que d'essayer de comprendre la syntaxe LDAP folle, qui est nécessaire pour certaines des autres solutions recommandées ici.Tant que vous usurpez l'identité de l'utilisateur avec lequel vous souhaitez exécuter la vérification en appelant "LoginUser", vous ne devriez rencontrer aucun problème de sécurité.

Vous pouvez trouver un exemple de code pour effectuer l'usurpation d'identité ici.

Si vous avez besoin d'aide pour savoir comment appeler "NetLocalGroupGetMembers" à partir de C#, je vous recommande de consulter l'assistant PInvoke de Jared Parson, que vous pouvez télécharger du codeplex.

Si vous exécutez le code dans une application ASP.NET exécutée dans IIS et que vous souhaitez usurper l'identité de l'utilisateur accédant au site Web afin de passer l'appel, vous devrez peut-être accorder l'autorisation « Approuvé pour la délégation » au serveur Web de production.

Si vous utilisez le bureau, l'utilisation des informations d'identification de sécurité de l'utilisateur actif ne devrait pas poser de problème.

Il est possible que votre administrateur réseau ait révoqué l'accès à « l'objet sécurisable » pour la machine particulière à laquelle vous essayez d'accéder.Malheureusement, cet accès est nécessaire pour tous les API de gestion de réseau fonctions pour fonctionner.Si tel est le cas, vous devrez alors accorder l'accès à « l'objet sécurisable » aux utilisateurs sous lesquels vous souhaitez exécuter.Avec les paramètres de sécurité Windows par défaut, tous les utilisateurs authentifiés devraient cependant y avoir accès.

J'espère que ça aide.

-Scott

Vous devriez pouvoir le faire avec System.DirectoryServices.DirectoryEntry.Si vous rencontrez des difficultés pour l'exécuter à distance, vous pourriez peut-être installer quelque chose sur les machines distantes pour vous fournir vos données via une sorte de RPC, comme la connexion à distance ou un service Web.Mais je pense que ce que vous essayez devrait être possible à distance sans trop de fantaisie.

Si Windows ne vous permet pas de vous connecter via son mécanisme de connexion, je pense que votre seule option est d'exécuter quelque chose sur la machine distante avec un port ouvert (soit directement, soit via un service distant ou un service Web, comme mentionné).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top