C# 从登录ID(Windows XP及更高版本)获取用户SID
我有一个Windows服务,当用户本地或通过终端服务器登录时,需要访问HKEY_用户下的注册表配置单元。我在win32_logonsession上使用WMI查询来接收用户登录时的事件,我从该查询中获得的属性之一是LogonId。为了弄清楚我需要访问哪个注册表配置单元,现在,我需要用户的SID,它用作HKEY_users下面的注册表项名称 在大多数情况下,我可以通过执行类似这样的RelatedObjectQuery(在C中)来实现这一点: 其中“logonID”是会话查询中的登录会话ID。运行RelatedObjectQuery通常会给我一个SID属性,该属性正好包含我需要的内容 我对此有两个问题。首先也是最重要的一点,RelatedObjectQuery不会为使用缓存凭据登录并与域断开连接的域用户返回任何结果。其次,我对这个RelatedObjectQuery的性能不满意——执行它可能需要几秒钟的时间 这里有一个快速而肮脏的命令行程序,我把它放在一起进行查询实验。这只是枚举本地计算机上的用户,而不是设置为接收事件:C# 从登录ID(Windows XP及更高版本)获取用户SID,c#,.net,windows,wmi,sid,C#,.net,Windows,Wmi,Sid,我有一个Windows服务,当用户本地或通过终端服务器登录时,需要访问HKEY_用户下的注册表配置单元。我在win32_logonsession上使用WMI查询来接收用户登录时的事件,我从该查询中获得的属性之一是LogonId。为了弄清楚我需要访问哪个注册表配置单元,现在,我需要用户的SID,它用作HKEY_users下面的注册表项名称 在大多数情况下,我可以通过执行类似这样的RelatedObjectQuery(在C中)来实现这一点: 其中“logonID”是会话查询中的登录会话ID。运行Re
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之类的工具?我问了一会儿,得到了以下答案:
我计划使用SystemEvents来检测用户何时登录到windows,然后在登录用户列表中循环检测所有登录用户。(,关于所有这些,包括检测登录和当前用户的参考。)
如果您决定采用哪种方法,请发布最新消息-我很想听听您的意见。另一种简单的方法:
HKEY\U LOCAL\U MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList另一个工作答案(VB.Net中的代码)
Powershell更简单
Function GetSIDfromAcctName()
{
$myacct = Get-WmiObject Win32_UserAccount -filter "Name = '$env:USERNAME "
write-host Name: $myacct.name
Write-Host SID : $myacct.sid
}
这只适用于用户存在本地配置文件的情况。考虑域中的服务器:可能有许多用户进行认证,但只有少数管理员会有配置文件。目前我认为在POWER SUBLE中编写Windows服务的可能副本是一种选择。不过,如果在脚本编写环境中有这种需要,我肯定会记住这一点。
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
Function GetSIDfromAcctName()
{
$myacct = Get-WmiObject Win32_UserAccount -filter "Name = '$env:USERNAME "
write-host Name: $myacct.name
Write-Host SID : $myacct.sid
}