Получить идентификатор пользователя из идентификатора входа (Windows XP и выше) - PullRequest
4 голосов
/ 28 апреля 2010

У меня есть служба Windows, которой требуется доступ к кустам реестра в HKEY_USERS, когда пользователи входят в систему, локально или через сервер терминалов. Я использую запрос WMI на win32_logonsession для получения событий, когда пользователи входят в систему, и одним из свойств, которые я получаю из этого запроса, является LogonId. Чтобы выяснить, к какому кусту реестра мне нужен доступ, теперь мне нужен SID пользователя, который используется в качестве имени раздела реестра под HKEY_USERS.

В большинстве случаев я могу получить это, выполнив RelatedObjectQuery следующим образом (в C #):

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

где "logonID" - идентификатор сеанса входа в систему из запроса сеанса. Выполнение RelatedObjectQuery обычно дает мне свойство SID, которое содержит именно то, что мне нужно.

У меня есть две проблемы с этим. Первое и самое главное, RelatedObjectQuery не будет возвращать никаких результатов для пользователя домена, который входит в систему с кэшированными учетными данными, отключенными от домена. Во-вторых, я не доволен производительностью этого RelatedObjectQuery - выполнение может занять до нескольких секунд.

Вот быстрая и грязная программа командной строки, которую я собрал, чтобы поэкспериментировать с запросами. Вместо того, чтобы настраивать получение событий, он просто перечисляет пользователей на локальном компьютере:

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

Итак ... есть ли способ быстро и надежно получить SID пользователя, учитывая информацию, которую я получаю из WMI, или я должен вместо этого использовать что-то вроде SENS?

Ответы [ 4 ]

2 голосов
/ 28 апреля 2010

Я задал очень похожий вопрос некоторое время назад и получил такой ответ: как получить SID из имени пользователя Windows .

Я планировал использовать SystemEvents, чтобы определить, когда пользователь входит в Windows, а затем просмотреть список зарегистрированных пользователей в тот момент, чтобы обнаружить всех зарегистрированных пользователей. ( Вот мой вопрос , обо всем этом, включая ссылки для обнаружения входов в систему и текущих пользователей.)

Если вы выберете подход, пожалуйста, опубликуйте обновление - мне было бы интересно услышать, что, по вашему мнению, работает хорошо.

1 голос
/ 02 июля 2012

Powershell проще.

Function GetSIDfromAcctName()
{
$myacct = Get-WmiObject Win32_UserAccount -filter "Name = '$env:USERNAME " 
write-host Name: $myacct.name
Write-Host SID : $myacct.sid
}
1 голос
/ 04 января 2011

Еще один простой способ: HKEY_LOCAL_MACHINE \ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ \ Microsoft \ Windows NT \ CurrentVersion \ ProfileList

0 голосов
/ 04 января 2011

Еще один рабочий ответ (код в 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
...