c# - 从登录 ID 获取用户 SID(Windows XP 及更高版本)

标签 c# .net windows wmi sid

我有一个 Windows 服务需要在用户登录时访问 HKEY_USERS 下的注册表配置单元,无论是在本地还是通过终端服务器。我在 win32_logonsession 上使用 WMI 查询来接收用户登录时的事件,我从该查询中获得的属性之一是 LogonId。为了弄清楚我需要访问哪个注册表配置单元,现在,我需要用户的 SID,它用作 HKEY_USERS 下的注册表项名称。

在大多数情况下,我可以通过像这样(在 C# 中)执行 RelatedObjectQuery 来获得它:

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

其中“logonID”是来自 session 查询的登录 session ID。运行 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 );
            }
        }
    }
}

那么...根据我从 WMI 检索到的信息,有没有办法快速可靠地获取用户 SID,或者我应该考虑改用 SENS 之类的东西?

最佳答案

我问了a very similar question不久前得到了这个答案:how to get a SID from a windows username .

我计划使用 SystemEvents 来检测用户何时登录到 Windows,然后循环遍历此时已登录的用户列表以检测所有已登录的用户。 ( Here's my question ,关于所有这些,包括用于检测登录和当前用户的引用。)

如果您决定采用一种方法,请发布更新 - 我很想听听您发现哪种方法效果好。

关于c# - 从登录 ID 获取用户 SID(Windows XP 及更高版本),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2727393/

相关文章:

c# - 您如何确定 C# Visual Studio 项目生成的可执行文件和 DLL?

c# - 是整数吗?线程安全?

.net - 以编程方式替换 Word 文档中文本的最快方法

C# 异步文件传输 - 在继续循环之前等待

windows - 驱动程序安装过程中 Windows 安全对话框中的信息从何而来?

c# - 无法将类型 'System.Collections.Generic.List<>' 隐式转换为 'System.Threading.Tasks.Task<>>

c# - asp.net response.write 与 bootbox.alert

c# - .NET 框架 : Argument type 'uint' is not CLS-compliant on P/Invoke

windows - Windows 7 上的 Cygwin 死于等待 dll 加载

node.js - 在 Windows Node.js 中使用 unix 文件行为