2010-04-28 115 views
4

我有一個Windows服務,需要在用戶登錄時訪問HKEY_USERS下的註冊表配置單元,無論是本地還是通過終端服務器。我在win32_logonsession上使用WMI查詢來接收用戶登錄時的事件,並且從該查詢中獲得的其中一個屬性是LogonId。爲了找出我需要訪問哪個註冊表配置單元,現在我需要用戶的SID,它用作HKEY_USERS下的註冊表項名稱。從登錄ID(Windows XP和更高版本)獲取用戶SID

在大多數情況下,我可以做一個RelatedObjectQuery像這樣(在C#)得到這樣的:

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

其中「LogonID的」是從會話查詢登錄會話ID。運行RelatedObjectQuery通常會給我一個SID屬性,其中包含我所需要的。

我對此有兩個問題。首先也是最重要的一點,相關對象查詢不會爲使用與域斷開連接的緩存憑證登錄的域用戶返回任何結果。其次,我對這個相關對象查詢的性能不滿意 - 它可能需要幾秒鐘才能執行。

這裏是一個快速而骯髒的命令行程序,我扔在一起實驗查詢。而不是設置爲接收事件,這只是列舉了在本地計算機上的用戶:

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

所以...有沒有辦法快速,可靠地獲取給定的,我從WMI檢索信息的用戶的SID,還是應該我正在尋找使用像SENS而不是?

+0

可能重複的[轉換用戶名到C#中的SID串/。NET](http://stackoverflow.com/questions/1040623/convert-a-username-to-a-sid-string- in-c-net) – Richard 2011-01-04 10:33:08

回答

2

我問a very similar question一會兒回來,得到了這個答案:how to get a SID from a windows username

我打算使用SystemEvents來檢測用戶何時登錄到窗口,然後循環登錄用戶列表以檢測所有登錄的用戶。 (Here's my question,關於所有這些包括檢測登錄和當前用戶的參考信息)。

如果您決定使用某種方法,請發佈更新 - 我很樂意聽到您發現的效果。

1

另一種簡單的方法: HKEY_LOCAL_MACHINE \ SOFTWARE \微軟\的Windows NT \ CURRENTVERSION \ ProfileList文件

+0

這隻適用於存在本地配置文件的用戶。考慮域中的服務器:可能有許多用戶進行身份驗證,但只有少數管理員擁有配置文件。 – Richard 2011-01-04 10:31:46

+0

從問題:「需要訪問HKEY_USERS下的註冊表配置單元」.. – hB0 2011-01-04 10:42:11

0

另一個工作答案(代碼在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是更容易。的

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

我不認爲在Powershell中編寫Windows服務是一個選項,目前。但是,如果我在腳本編寫的情況下有這種需求,我一定會牢記這一點。 – 2012-07-03 16:25:17