WTSEnumerateSessions (wtsapi32)
Last changed: -62.209.223.226

.
Summary
This Terminal Services API call lists all local and remote sessions for a given server, including their state (e.g. connected, disconnected) and type (local, RDP). It is the basis for the output of qwinsta.exe.

C# Signature:

[DllImport("wtsapi32.dll", SetLastError=true)]
static extern int WTSEnumerateSessions(
                System.IntPtr hServer,
                int Reserved,
                int Version,
                ref System.IntPtr ppSessionInfo,
                ref int pCount);

[DllImport("wtsapi32.dll", SetLastError=true)]
static extern void WTSEnumerateSessions(
                System.IntPtr hServer,
                ref System.IntPtr ppSessionInfo,
                ref int pCount)
{
    WTSEnumerateSessions(hServer,0,1,ppSessionInfo,pCount);
}

Powershell Signature:

$wtsenumsig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern int WTSEnumerateSessions(
        System.IntPtr hServer,
        int Reserved,
        int Version,
        ref System.IntPtr ppSessionInfo,
        ref int pCount);
'@

C# Example

// Note the VB example will give you the first entry of the array n times where n is the size of the array
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace TerminalServices
{
    class TSManager
    {
    [DllImport("wtsapi32.dll", SetLastError=true)]
    static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

    [DllImport("wtsapi32.dll")]
    static extern void WTSCloseServer(IntPtr hServer);

    [DllImport("wtsapi32.dll", SetLastError=true)]
    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));

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

Powershell Example

$server = "vmtermsrv"
$messageTitle = "FooBar"
$message = "This is a test...  This is only a test"
$timeout = 60;

$wtssig = @'
namespace mystruct {
using System;
using System.Runtime.InteropServices;
     [StructLayout(LayoutKind.Sequential)]
     public 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
     }
     }
'@


add-type  $wtssig

$wtsenumsig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern int WTSEnumerateSessions(
         System.IntPtr hServer,
         int Reserved,
         int Version,
         ref System.IntPtr ppSessionInfo,
         ref int pCount);
'@

$wtsopensig = @'
[DllImport("wtsapi32.dll", SetLastError=true)]
public static extern IntPtr WTSOpenServer(string pServerName);
'@

$wtsSendMessagesig = @'
[DllImport("wtsapi32.dll", SetLastError = true)]
     public static extern bool WTSSendMessage(
     IntPtr hServer,
     [MarshalAs(UnmanagedType.I4)] int SessionId,
     String pTitle,
     [MarshalAs(UnmanagedType.U4)] int TitleLength,
     String pMessage,
     [MarshalAs(UnmanagedType.U4)] int MessageLength,
     [MarshalAs(UnmanagedType.U4)] int Style,
     [MarshalAs(UnmanagedType.U4)] int Timeout,
     [MarshalAs(UnmanagedType.U4)] out int pResponse,
     bool bWait);
'@

$wtsenum = add-type -MemberDefinition $wtsenumsig -Name PSWTSEnumerateSessions -Namespace GetLoggedOnUsers -PassThru
$wtsOpen = add-type -MemberDefinition $wtsopensig -name PSWTSOpenServer -Namespace GetLoggedOnUsers -PassThru
$wtsmessage = Add-Type -MemberDefinition $wtsSendMessagesig -name PSWTSSendMessage -Namespace GetLoggedOnUsers -PassThru



[long]$count = 0
[long]$ppSessionInfo = 0

$server = $wtsOpen::WTSOpenServer($server)
[long]$retval = $wtsenum::WTSEnumerateSessions($server,0,1,[ref]$ppSessionInfo,[ref]$count)
$datasize = [system.runtime.interopservices.marshal]::SizeOf([System.Type][mystruct.WTS_SESSION_INFO])
$Responses = @()
if ($retval -ne 0){
     for ($i = 0; $i -lt $count; $i++){
     $element =  [system.runtime.interopservices.marshal]::PtrToStructure($ppSessionInfo + ($datasize * $i),[System.type][mystruct.WTS_SESSION_INFO])
     $element
     $resp = ""
     $wtsmessage::WTSSendMessage($server, $element.SessionID,$messageTitle,$messageTitle.Length,$message,$message.Length,0,$timeout,[ref]$resp,$true)
     $responses += $resp;
     }

}
$responses

VB Signature:

    <DllImport("wtsapi32.dll", _
    bestfitmapping:=True, _
    CallingConvention:=CallingConvention.StdCall, _
    CharSet:=CharSet.Auto, _
    EntryPoint:="WTSEnumerateSessions", _
    setlasterror:=True, _
    ThrowOnUnmappableChar:=True)> _
    Private Shared Function WTSEnumerateSessions( _
    ByVal hServer As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Reserved As Int32, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Version As Int32, _
    ByRef ppSessionInfo As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByRef pCount As Int32) As Int32
    End Function

User-Defined Types:

    Private Enum WTS_CONNECTSTATE_CLASS
    WTSActive
    WTSConnected
    WTSConnectQuery
    WTSShadow
    WTSDisconnected
    WTSIdle
    WTSListen
    WTSReset
    WTSDown
    WTSInit
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Private Structure WTS_SESSION_INFO
    Dim SessionID As Int32 'DWORD integer
    Dim pWinStationName As String ' integer LPTSTR - Pointer to a null-terminated string containing the name of the WinStation for this session
    Dim State As WTS_CONNECTSTATE_CLASS
    End Structure

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices

Public Class ManagedWTSAPI

    Private Enum WTS_CONNECTSTATE_CLASS
    WTSActive
    WTSConnected
    WTSConnectQuery
    WTSShadow
    WTSDisconnected
    WTSIdle
    WTSListen
    WTSReset
    WTSDown
    WTSInit
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Private Structure WTS_SESSION_INFO
    Dim SessionID As Int32 'DWORD integer
    Dim pWinStationName As String ' integer LPTSTR - Pointer to a null-terminated string containing the name of the WinStation for this session
    Dim State As WTS_CONNECTSTATE_CLASS
    End Structure

    Friend Structure strSessionsInfo
    Dim SessionID As Integer
    Dim StationName As String
    Dim ConnectionState As String
    End Structure

    <DllImport("wtsapi32.dll", _
    bestfitmapping:=True, _
    CallingConvention:=CallingConvention.StdCall, _
    CharSet:=CharSet.Auto, _
    EntryPoint:="WTSEnumerateSessions", _
    setlasterror:=True, _
    ThrowOnUnmappableChar:=True)> _
    Private Shared Function WTSEnumerateSessions( _
    ByVal hServer As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Reserved As Int32, _
    <MarshalAs(UnmanagedType.U4)> _
    ByVal Vesrion As Int32, _
    ByRef ppSessionInfo As IntPtr, _
    <MarshalAs(UnmanagedType.U4)> _
    ByRef pCount As Int32) As Int32
    End Function

    <DllImport("wtsapi32.dll")> _
    Private Shared Sub WTSFreeMemory(ByVal pMemory As IntPtr)
    End Sub

    <DllImport("wtsapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
     Private Shared Function WTSOpenServer(ByVal pServerName As String) As IntPtr
    End Function

    <DllImport("wtsapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
     Private Shared Sub WTSCloseServer(ByVal hServer As IntPtr)
    End Sub

    Friend Function GetSessions(ByVal ServerName As String) As strSessionsInfo()
    Dim ptrOpenedServer As IntPtr
    Dim RetVal As strSessionsInfo()
    Try
        ptrOpenedServer = WTSOpenServer(ServerName)
        Dim FRetVal As Int32
        Dim ppSessionInfo As IntPtr = IntPtr.Zero
        Dim Count As Int32 = 0
        Try
        FRetVal = WTSEnumerateSessions(ptrOpenedServer, 0, 1, ppSessionInfo, Count)
        If FRetVal <> 0 Then
            Dim sessionInfo() As WTS_SESSION_INFO = New WTS_SESSION_INFO(Count) {}
            Dim i As Integer
            Dim DataSize = Marshal.SizeOf(New WTS_SESSION_INFO)
            Dim current As Int64
            current = ppSessionInfo.ToInt64
            For i = 0 To Count - 1 ' Step i + 1
            sessionInfo(i) = CType(Marshal.PtrToStructure(New IntPtr(current), GetType(WTS_SESSION_INFO)), WTS_SESSION_INFO)
            current = current + DataSize
            Next
            WTSFreeMemory(ppSessionInfo)
            Dim tmpArr(sessionInfo.GetUpperBound(0)) As strSessionsInfo
            For i = 0 To tmpArr.GetUpperBound(0)
            tmpArr(i).SessionID = sessionInfo(i).SessionID
            tmpArr(i).StationName = sessionInfo(i).pWinStationName
            tmpArr(i).ConnectionState = GetConnectionState(sessionInfo(i).State)
            Next
            ReDim sessionInfo(-1)
            RetVal = tmpArr
        Else
            Throw New ApplicationException("No data retruned")
        End If
        Catch ex As Exception
        Throw New Exception(ex.Message & vbCrLf & System.Runtime.InteropServices.Marshal.GetLastWin32Error)
        End Try
    Catch ex As Exception
        Throw New Exception(ex.Message)
        Exit Function
    Finally
        WTSCloseServer(ptrOpenedServer)
    End Try

    Return RetVal
    End Function

    Private Function GetConnectionState(ByVal State As WTS_CONNECTSTATE_CLASS) As String
    Dim RetVal As String
    Select Case State
        Case WTS_CONNECTSTATE_CLASS.WTSActive
        RetVal = "Active"
        Case WTS_CONNECTSTATE_CLASS.WTSConnected
        RetVal = "Connected"
        Case WTS_CONNECTSTATE_CLASS.WTSConnectQuery
        RetVal = "Query"
        Case WTS_CONNECTSTATE_CLASS.WTSDisconnected
        RetVal = "Disconnected"
        Case WTS_CONNECTSTATE_CLASS.WTSDown
        RetVal = "Down"
        Case WTS_CONNECTSTATE_CLASS.WTSIdle
        RetVal = "Idle"
        Case WTS_CONNECTSTATE_CLASS.WTSInit
        RetVal = "Initializing."
        Case WTS_CONNECTSTATE_CLASS.WTSListen
        RetVal = "Listen"
        Case WTS_CONNECTSTATE_CLASS.WTSReset
        RetVal = "reset"
        Case WTS_CONNECTSTATE_CLASS.WTSShadow
        RetVal = "Shadowing"
        Case Else
        RetVal = "Unknown connect state"
    End Select
    Return RetVal
    End Function

End Class

Alternative Managed API:

Cassia on google code: https://code.google.com/p/cassia/

Documentation