Hi guys,
I am looking for a script that will allow my users to find remote desktops that aren’t in an active session, or to list the active session on a set of computers – similar to what PSLogged in does. For us, PSLoggedin doesn’t work anymore – instead of listing active sessions, it lists EVERY user who has ever logged into the machine, making it useless. Any help you guys could provide would be greatly appreciated. Thanks.
You can use PowerShell if you have version 4.0 there are RDP cmdlets:
RemoteDesktop Module | Microsoft Learn
Or I had found a C# based script that will grab some information, then I added a piece of PowerShell script to ask you what Terminal Server you wanted to check
Here it is if you’re interested:
# QuerySessionInformation.ps1
# Written by Ryan Ries, Jan. 2013, with help from MSDN and Stackoverflow.
# http://serverfault.com/questions/342533/wmi-object-to-get-current-sessions-with-client-name
$Code = @'
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
public class RDPInfo
[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
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);
IntPtr SessionInfoPtr = IntPtr.Zero;
IntPtr userPtr = IntPtr.Zero;
IntPtr domainPtr = IntPtr.Zero;
IntPtr clientNamePtr = IntPtr.Zero;
Int32 sessionCount = 0;
Int32 retVal = WTSEnumerateSessions(serverHandle, 0, 1, ref SessionInfoPtr, ref sessionCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
Int32 currentSession = (int)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);
WTSQuerySessionInformation(serverHandle, si.SessionID, WTS_INFO_CLASS.WTSClientName, out clientNamePtr, out bytes);
if(Marshal.PtrToStringAnsi(domainPtr).Length > 0 && Marshal.PtrToStringAnsi(userPtr).Length > 0)
if(Marshal.PtrToStringAnsi(clientNamePtr).Length < 1)
Console.WriteLine(Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr) + "\tSessionID: " + si.SessionID + "\tClientName: n/a");
Console.WriteLine(Marshal.PtrToStringAnsi(domainPtr) + "\\" + Marshal.PtrToStringAnsi(userPtr) + "\tSessionID: " + si.SessionID + "\tClientName: " + Marshal.PtrToStringAnsi(clientNamePtr));
WTSFreeMemory(clientNamePtr);
WTSFreeMemory(userPtr);
WTSFreeMemory(domainPtr);
WTSFreeMemory(SessionInfoPtr);
catch(Exception ex)
Console.WriteLine("Exception: " + ex.Message);
finally
CloseServer(serverHandle);
# This section was added by Matt Bergeron (Chamele0n on Spiceworks community) on Mar. 2013
# Asks for user input of servers hostname to be queried
[console]::ForegroundColor = "green"
[console]::BackgroundColor= "black"
$Server = Read-Host 'Please enter the HostName of the server you want to query. (e.g. TerminalServer1) Leave blank for localhost'
if ($Server -eq $null){
$Server = (Get-Childitem env:computername)
[console]::ResetColor()
Add-Type $Code
[console]::ForegroundColor = "yellow"
[console]::BackgroundColor= "black"
[RDPInfo]::ListUsers($Server)
[console]::ResetColor()
I’m not sure if this would work for you, but I just look for the owner of the explorer.exe process to see who’s logged on:
(Get-WmiObject Win32_Process -ComputerName computer | ?{ $_.ProcessName -match "explorer" }).getowner() | Select-object "User"
This might be helpful also:
learn.microsoft.com