2008-09-25 3 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

Я знаю, что это небольшая ниточка, но если кто-то использует это, есть лук-порей памяти. добавить 'WTSFreeMemory (userPtr); WTSFreeMemory (domainPtr); 'после' Console.Writeline', чтобы исправить это. –

+1

Привет, Магнус, я попробовал ваш код, но он просто вернул зарегистрированного пользователя в текущую клиентскую систему в локальной локальной сети. Есть ли способ получить все зарегистрированные пользователи с именем системного клиента в локальной локальной сети с указанным выше кодом? –

+0

@M_Mogharrabi, извините, ваш вопрос для меня не имеет смысла. Этот код предназначен для запуска на сервере, я не знаю, что вы подразумеваете под «текущей клиентской системой». Вы можете перефразировать? –

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

+0

Как мы это называем? – Si8

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

Это выглядит очень прост в использовании. Спасибо, что добавил. – James

+0

Cassia замечательный, за исключением того, что вы не можете получить исходную сеть. Адрес только IP-адрес клиента, который будет их внутренним сетевым адресом, если они находятся за маршрутизатором. – DaddioNTS

Смежные вопросы