如何检索在.NET中login/连接的用户列表?

这是一个场景:

您有一个用户可以通过RDP远程连接的Windows服务器。 您希望您的程序(作为服务运行)知道当前连接的人员。 这可能包括也可能不包括交互式控制台会话。

请注意,这与检索当前的交互式用户并不相同。

我猜测,有terminal服务的某种API访问来获取此信息?

这是我对这个问题的看法:

using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace EnumerateRDUsers { class Program { [DllImport("wtsapi32.dll")] static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName); [DllImport("wtsapi32.dll")] static extern void WTSCloseServer(IntPtr hServer); [DllImport("wtsapi32.dll")] static extern Int32 WTSEnumerateSessions( IntPtr hServer, [MarshalAs(UnmanagedType.U4)] Int32 Reserved, [MarshalAs(UnmanagedType.U4)] Int32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref Int32 pCount); [DllImport("wtsapi32.dll")] static extern void WTSFreeMemory(IntPtr pMemory); [DllImport("Wtsapi32.dll")] static extern bool WTSQuerySessionInformation( System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned); [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO { public Int32 SessionID; [MarshalAs(UnmanagedType.LPStr)] public String pWinStationName; public WTS_CONNECTSTATE_CLASS State; } public enum WTS_INFO_CLASS { WTSInitialProgram, WTSApplicationName, WTSWorkingDirectory, WTSOEMId, WTSSessionId, WTSUserName, WTSWinStationName, WTSDomainName, WTSConnectState, WTSClientBuildNumber, WTSClientName, WTSClientDirectory, WTSClientProductId, WTSClientHardwareId, WTSClientAddress, WTSClientDisplay, WTSClientProtocolType } public enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } static void Main(string[] args) { ListUsers("<INSERT SERVERNAME HERE>"); } public static IntPtr OpenServer(String Name) { IntPtr server = WTSOpenServer(Name); return server; } public static void CloseServer(IntPtr ServerHandle) { WTSCloseServer(ServerHandle); } public static void ListUsers(String ServerName) { IntPtr serverHandle = IntPtr.Zero; List<String> resultList = new List<string>(); serverHandle = OpenServer(ServerName); try { IntPtr SessionInfoPtr = IntPtr.Zero; IntPtr userPtr = IntPtr.Zero; IntPtr domainPtr = IntPtr.Zero; Int32 sessionCount = 0; Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount); Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); IntPtr currentSession = SessionInfoPtr; uint bytes = 0; if (retVal != 0) { for (int i = 0; i < sessionCount; i++) { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO)); currentSession += dataSize; WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes); WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes); Console.WriteLine("Domain and User: " + Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr)); WTSFreeMemory(userPtr); WTSFreeMemory(domainPtr); } WTSFreeMemory(SessionInfoPtr); } } finally { CloseServer(serverHandle); } } } } 

另一种select,如果你不想处理P / Invokes自己,将是使用决明库:

 using System; using System.Security.Principal; using Cassia; namespace CassiaSample { public static class Program { public static void Main(string[] args) { ITerminalServicesManager manager = new TerminalServicesManager(); using (ITerminalServer server = manager.GetRemoteServer("your-server-name")) { server.Open(); foreach (ITerminalServicesSession session in server.GetSessions()) { NTAccount account = session.UserAccount; if (account != null) { Console.WriteLine(account); } } } } } } 

好吧,我自己的问题的一个解决scheme。

您可以使用WMI来检索正在运行的进程的列表。 你也可以看看这些进程的所有者。 如果你看看“explorer.exe”的所有者(并删除重复项),你应该最终得到一个login用户列表。

 using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace TerminalServices { class TSManager { [DllImport("wtsapi32.dll")] static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName); [DllImport("wtsapi32.dll")] static extern void WTSCloseServer(IntPtr hServer); [DllImport("wtsapi32.dll")] static extern Int32 WTSEnumerateSessions( IntPtr hServer, [MarshalAs(UnmanagedType.U4)] Int32 Reserved, [MarshalAs(UnmanagedType.U4)] Int32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref Int32 pCount); [DllImport("wtsapi32.dll")] static extern void WTSFreeMemory(IntPtr pMemory); [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO { public Int32 SessionID; [MarshalAs(UnmanagedType.LPStr)] public String pWinStationName; public WTS_CONNECTSTATE_CLASS State; } public enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } public static IntPtr OpenServer(String Name) { IntPtr server = WTSOpenServer(Name); return server; } public static void CloseServer(IntPtr ServerHandle) { WTSCloseServer(ServerHandle); } public static List<String> ListSessions(String ServerName) { IntPtr server = IntPtr.Zero; List<String> ret = new List<string>(); server = OpenServer(ServerName); try { IntPtr ppSessionInfo = IntPtr.Zero; Int32 count = 0; Int32 retval = WTSEnumerateSessions(server, 0, 1, ref ppSessionInfo, ref count); Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); Int32 current = (int)ppSessionInfo; if (retval != 0) { for (int i = 0; i < count; i++) { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO)); current += dataSize; ret.Add(si.SessionID + " " + si.State + " " + si.pWinStationName); } WTSFreeMemory(ppSessionInfo); } } finally { CloseServer(server); } return ret; } } }