2008-09-25 10 views
23

Hier ist das Szenario:Wie rufen Sie eine Liste der angemeldeten/verbundenen Benutzer in .NET ab?

Sie haben einen Windows-Server, über den Benutzer remote mit RDP verbinden. Sie möchten, dass Ihr Programm (das als Dienst ausgeführt wird) weiß, wer gerade verbunden ist. Dies kann eine interaktive Konsolensitzung beinhalten oder nicht.

Bitte beachten Sie, dass dies die nicht das gleiche wie nur das Abrufen des aktuellen interaktiven Benutzers ist.

Ich vermute, dass es eine Art von API-Zugriff auf Terminaldienste gibt, um diese Informationen zu erhalten?

Antwort

25

Hier ist mein nehmen auf die Frage:

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

Ich weiß, das ist ein bisschen Thread necomancy, aber wenn jemand dies verwendet, gibt es einen Speicher Lauch. hinzufügen 'WTSFreeMemory (userPtr); WTSFreeMemory (domainPtr); 'nach der' Console.Writeline', um es zu beheben. –

+1

Hallo Magnus, ich habe versucht, Ihren Code, aber es zurückgegeben nur den angemeldeten Benutzer auf dem aktuellen Client-System in meinem lokalen LAN.Ist es eine Möglichkeit, alle angemeldeten Benutzer mit System-Client-Namen in einem lokalen LAN mit dem obigen Code zu bekommen? –

+0

@M_Mogharrabi, tut mir leid, deine Frage ergibt keinen Sinn für mich. Dieser Code soll auf einem Server laufen, ich weiß nicht, was du unter "aktuelles Client-System" meinst Kannst du das bitte umformulieren? –

5

Ok, eine Lösung für meine eigene Frage.

Mit WMI können Sie eine Liste laufender Prozesse abrufen. Sie können sich auch die Eigentümer dieser Prozesse ansehen. Wenn Sie sich die Besitzer von "explorer.exe" ansehen (und die Duplikate entfernen), sollten Sie eine Liste der angemeldeten Benutzer erhalten.

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

Dies gibt Ihnen einige nützliche Informationen, aber nicht die Benutzernamen. – James

+0

Wie nennen wir es? – Si8

19

Eine weitere Option, wenn Sie wollen nicht mit dem P beschäftigen/selbst aufruft, wäre die Cassia Bibliothek verwenden:

+1

Das sieht wirklich einfach zu bedienen aus. Danke, dass du das hinzugefügt hast. – James

+0

Cassia ist großartig, außer Sie können nicht die Quell-Netzwerkadresse nur die Client-IP-Adresse erhalten, die ihre interne Netzwerkadresse sein wird, wenn sie sich hinter einem Router befindet. – DaddioNTS

Verwandte Themen