2010-04-28 7 views
4

J'ai un service Windows qui doit accéder aux ruches de registre sous HKEY_USERS lorsque les utilisateurs se connectent, soit localement, soit via Terminal Server. J'utilise une requête WMI sur win32_logonsession pour recevoir des événements lorsque les utilisateurs se connectent, et l'une des propriétés que je reçois de cette requête est un LogonId. Pour déterminer quelle ruche de registre j'ai besoin d'accéder, maintenant, j'ai besoin du SID des utilisateurs, qui est utilisé comme un nom de clé de registre sous HKEY_USERS.Obtenir le SID utilisateur à partir de l'ID de connexion (Windows XP et versions ultérieures)

Dans la plupart des cas, je peux obtenir cela en faisant un RelatedObjectQuery comme si (en C#):

RelatedObjectQuery relatedQuery = new RelatedObjectQuery("associators of {Win32_LogonSession.LogonId='" + logonID + "'} WHERE AssocClass=Win32_LoggedOnUser Role=Dependent"); 

où "LogonID" est la session d'ouverture de session ID de la requête de session. L'exécution de RelatedObjectQuery me donne généralement une propriété SID qui contient exactement ce dont j'ai besoin.

J'ai deux problèmes avec cela. Tout d'abord, LinkedObjectQuery ne renvoie aucun résultat pour un utilisateur de domaine qui se connecte avec des informations d'identification mises en cache, déconnecté du domaine. Deuxièmement, je ne suis pas satisfait de la performance de cette RelatedObjectQuery --- cela peut prendre plusieurs secondes à exécuter.

Voici un programme de ligne de commande rapide et corrompu que j'ai lancé ensemble pour expérimenter les requêtes. Plutôt que de mettre en place pour recevoir les événements, ce que les utilisateurs énumère sur la machine locale:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Management; 

namespace EnumUsersTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ManagementScope scope = new ManagementScope("\\\\.\\root\\cimv2"); 

      string queryString = "select * from win32_logonsession";       // for all sessions 
      //string queryString = "select * from win32_logonsession where logontype = 2";  // for local interactive sessions only 

      ManagementObjectSearcher sessionQuery = new ManagementObjectSearcher(scope, new SelectQuery(queryString)); 
      ManagementObjectCollection logonSessions = sessionQuery.Get(); 
      foreach (ManagementObject logonSession in logonSessions) 
      { 
       string logonID = logonSession["LogonId"].ToString(); 
       Console.WriteLine("=== {0}, type {1} ===", logonID, logonSession["LogonType"].ToString()); 
       RelatedObjectQuery relatedQuery = new RelatedObjectQuery("associators of {Win32_LogonSession.LogonId='" + logonID + "'} WHERE AssocClass=Win32_LoggedOnUser Role=Dependent"); 
       ManagementObjectSearcher userQuery = new ManagementObjectSearcher(scope, relatedQuery); 
       ManagementObjectCollection users = userQuery.Get(); 
       foreach (ManagementObject user in users) 
       { 
        PrintProperties(user.Properties); 
       } 
      } 

      Console.WriteLine("\nDone! Press a key to exit..."); 
      Console.ReadKey(true); 
     } 


     private static void PrintProperty(PropertyData pd) 
     { 
      string value = "null"; 
      string valueType = "n/a"; 
      if (pd.Value != null) 
      { 
       value = pd.Value.ToString(); 
       valueType = pd.Value.GetType().ToString(); 
      } 

      Console.WriteLine(" \"{0}\" = ({1}) \"{2}\"", pd.Name, valueType, value); 
     } 


     private static void PrintProperties(PropertyDataCollection properties) 
     { 
      foreach (PropertyData pd in properties) 
      { 
       PrintProperty(pd); 
      } 
     } 
    } 
} 

Alors ... est-il moyen d'obtenir rapidement et de manière fiable le SID utilisateur donné les informations que je récupère de WMI, ou devrais Je cherche à utiliser quelque chose comme SENS à la place?

+0

double possible de [Convertir un nom d'utilisateur pour une chaîne SID en C# /. NET] (http://stackoverflow.com/questions/1040623/convert-a-username-to-a-sid-string- in-c-net) – Richard

Répondre

2

J'ai demandé a very similar question un certain temps et j'ai obtenu cette réponse: how to get a SID from a windows username. Je prévoyais d'utiliser SystemEvents pour détecter quand un utilisateur se connecte à Windows, puis de boucler la liste des utilisateurs connectés à ce moment-là pour détecter tous les utilisateurs connectés. (Here's my question, à propos de tout cela, y compris les références pour détecter les connexions et les utilisateurs actuels.)

Si vous décidez d'une approche s'il vous plaît poster une mise à jour - Je serais intéressé d'entendre ce que vous trouvez fonctionne bien.

1

Une autre façon simple: HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ ProfileList

+0

Cela ne fonctionne que lorsqu'un profil local existe pour l'utilisateur. Considérez le serveur dans le domaine: il se peut que de nombreux utilisateurs s'authentifient, mais seuls quelques administrateurs auront des profils. – Richard

+0

De la question: "doit accéder aux ruches de registre sous HKEY_USERS" .. – hB0

0

Une autre réponse de travail (code VB.Net)

Public Function GetSIDfromAccName(ByVal strAccName As String) As String 
     Debug.WriteLine("***WMI-GetSIDfromAccName***") 
     Dim strSID As String = "" 
     Try 
      Dim wmiClass As System.Management.SelectQuery = New System.Management.SelectQuery(("Select * from Win32_UserAccount where Name='" _ 
       + (strAccName + "'"))) 
      Dim wmiSearcher As System.Management.ManagementObjectSearcher = New System.Management.ManagementObjectSearcher(wmiClass) 
      For Each val As System.Management.ManagementBaseObject In wmiSearcher.Get 
       strSID = val("SID").ToString 
      Next 
     Catch e As Exception 
      Debug.WriteLine(e.ToString) 
     End Try 
     Return strSID 
    End Function 
1

Powershell est plus facile.

Function GetSIDfromAcctName() 
{ 
$myacct = Get-WmiObject Win32_UserAccount -filter "Name = '$env:USERNAME " 
write-host Name: $myacct.name 
Write-Host SID : $myacct.sid 
} 
+0

Je ne pense pas que l'écriture d'un service Windows dans Powershell est une option, à l'heure actuelle. Je vais certainement garder cela à l'esprit si j'ai jamais eu ce besoin dans une situation de script, cependant. –

Questions connexes