2008-09-25 56 views
23

这里是场景:如何在.NET中检索登录/连接用户列表?

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

请注意,这是而不是就像检索当前的交互式用户一样。

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

回答

25

这里是我就此问题:

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

    } 

    } 
} 
+11

我知道这是一个线索necomancy位,但如果任何人使用这有一个记忆韭菜。 add`WTSFreeMemory(userPtr); WTSFreeMemory(domainPtr);`在Console.Writeline`后修复它。 – 2010-04-20 21:49:22

5

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

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

0
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; 
    } 
    } 
} 
+0

这给你一些有用的信息,但不是用户名。 – James 2008-09-25 11:40:06

+0

我们怎么称呼它? – Si8 2017-04-04 15:30:18

19

另一种选择,如果你不想处理P /调用自己,会使用Cassia库:

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