我正在编写一个Windows服务,需要知道当前是否有任何用户在机器上login。
到目前为止,我已经尝试过Win32_LogonSession
(WMI)和LsaEnumerateLogonSessions
/ LsaGetLogonSessionData
(secur32.dll)。
这两个工作,似乎都返回相同的数据,但它们太慢,无法更新时,用户注销:
- 系统启动时,返回“0个交互式用户”。 (好)
- 当我login时,他们返回“1交互式用户”。 (好)
- 但是,当我注销时,用户数保持为1.新login后,数为2,依此类推。
因此Win32_LogonSession和LsaEnumerateLogonSessions都不够好。 在最后一个交互式用户离开后的5分钟内,该服务需要知道。
SysInternals的LogonSessions.exe甚至没有提供最新的答案。
此外,答案不能是“监视login和注销事件,并有一个计数器variables”,因为服务可以在任何时候启动。
我结束了以下方法:计数至少有一个进程正在运行的交互式会话的数量。
1)获取每个交互式会话的登录会话ID。
- LsaEnumerateLogonSessions(secur32.dll)
- LsaGetLogonSessionData(secur32.dll)
- sessionData .LogonType = SECURITY_LOGON_TYPE.Interactive或sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
- sessionData.LoginID < – 将此值保存在LUID集中。
- LsaFreeReturnBuffer(secur32.dll)
2)获取每个正在运行的进程的登录会话ID。
[首先我们需要启用SeDebugPrivilege到当前的应用程序。]
- GetCurrentProcess(kernel32.dll)
- OpenProcessToken TOKEN_ADJUST_PRIVILEGES (advapi32.dll)
- LookupPrivilegeValue SE_DEBUG_NAME (advapi32.dll)
- AdjustTokenPrivileges(advapi32.dll)
- CloseHandle(kernel32.dll)
[然后检索我们想要的数据。]
- EnumProcesses(psapi.dll)
- OpenProcess PROCESS_QUERY_INFORMATION (kernel32.dll)
- OpenProcessToken TOKEN_QUERY (advapi32.dll)
- GetTokenInformation TOKEN_INFORMATION_CLASS.TokenStatistics (advapi32.dll)
- accessTokenStatistics .AuthenticationId < – 将此值保存在LUID集中。
- CloseHandle(kernel32.dll)
3)设置交叉点基数
interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |
Obs:sessionData.LoginID和accessTokenStatistics.AuthenticationId都是类型LUID 。