Files
OSD-ScriptTemplate/Functions/Get-UserSessionList.ps1
2023-03-23 22:56:35 -04:00

538 lines
17 KiB
PowerShell

## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Get-UserSessionList
Function Get-UserSessionList
{
[CmdletBinding()]
Param
(
[ValidateNotNullOrEmpty()]
[String]$ComputerName = "$($Env:ComputerName)"
)
<#
.SYNOPSIS
Get session details for all local and RDP logged on users.
.DESCRIPTION
Get session details for all local and RDP logged on users using Win32 APIs. Get the following session details:
NTAccount, SID, UserName, DomainName, SessionId, SessionName, ConnectState, IsCurrentSession, IsConsoleSession, IsUserSession, IsActiveUserSession
IsRdpSession, IsLocalAdmin, LogonTime, IdleTime, DisconnectTime, ClientName, ClientProtocolType, ClientDirectory, ClientBuildNumber
.EXAMPLE
Get-LoggedOnUser
.NOTES
Description of ConnectState property:
Value Description
----- -----------
Active A user is logged on to the session.
ConnectQuery The session is in the process of connecting to a client.
Connected A client is connected to the session.
Disconnected The session is active, but the client has disconnected from it.
Down The session is down due to an error.
Idle The session is waiting for a client to connect.
Initializing The session is initializing.
Listening The session is listening for connections.
Reset The session is being reset.
Shadowing This session is shadowing another session.
Description of IsActiveUserSession property:
If a console user exists, then that will be the active user session.
If no console user exists but users are logged in, such as on terminal servers, then the first logged-in non-console user that is either 'Active' or 'Connected' is the active user.
Description of IsRdpSession property:
Gets a value indicating whether the user is associated with an RDP client session.
.LINK
http://psappdeploytoolkit.com
#>
$TypeDefinition =
@"
// Date Modified: 01-08-2016
// Version Number: 3.6.8
using System;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.DirectoryServices;
using System.Security.Principal;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
namespace PSADT
{
public class QueryUser
{
[DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr WTSOpenServer(string pServerName);
[DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern void WTSCloseServer(IntPtr hServer);
[DllImport("wtsapi32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr pBuffer, out int pBytesReturned);
[DllImport("wtsapi32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
public static extern int WTSEnumerateSessions(IntPtr hServer, int Reserved, int Version, out IntPtr pSessionInfo, out int pCount);
[DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern void WTSFreeMemory(IntPtr pMemory);
[DllImport("winsta.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int WinStationQueryInformation(IntPtr hServer, int sessionId, int information, ref WINSTATIONINFORMATIONW pBuffer, int bufferLength, ref int returnedLength);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int GetCurrentProcessId();
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern bool ProcessIdToSessionId(int processId, ref int pSessionId);
public class TerminalSessionData
{
public int SessionId;
public string ConnectionState;
public string SessionName;
public bool IsUserSession;
public TerminalSessionData(int sessionId, string connState, string sessionName, bool isUserSession)
{
SessionId = sessionId;
ConnectionState = connState;
SessionName = sessionName;
IsUserSession = isUserSession;
}
}
public class TerminalSessionInfo
{
public string NTAccount;
public string SID;
public string UserName;
public string DomainName;
public int SessionId;
public string SessionName;
public string ConnectState;
public bool IsCurrentSession;
public bool IsConsoleSession;
public bool IsActiveUserSession;
public bool IsUserSession;
public bool IsRdpSession;
public bool IsLocalAdmin;
public DateTime? LogonTime;
public TimeSpan? IdleTime;
public DateTime? DisconnectTime;
public string ClientName;
public string ClientProtocolType;
public string ClientDirectory;
public int ClientBuildNumber;
}
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionId;
[MarshalAs(UnmanagedType.LPStr)]
public string SessionName;
public WTS_CONNECTSTATE_CLASS State;
}
[StructLayout(LayoutKind.Sequential)]
public struct WINSTATIONINFORMATIONW
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 70)]
private byte[] Reserved1;
public int SessionId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
private byte[] Reserved2;
public FILETIME ConnectTime;
public FILETIME DisconnectTime;
public FILETIME LastInputTime;
public FILETIME LoginTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1096)]
private byte[] Reserved3;
public FILETIME CurrentTime;
}
public enum WINSTATIONINFOCLASS
{
WinStationInformation = 8
}
public enum WTS_CONNECTSTATE_CLASS
{
Active,
Connected,
ConnectQuery,
Shadow,
Disconnected,
Idle,
Listen,
Reset,
Down,
Init
}
public enum WTS_INFO_CLASS
{
SessionId=4,
UserName,
SessionName,
DomainName,
ConnectState,
ClientBuildNumber,
ClientName,
ClientDirectory,
ClientProtocolType=16
}
private static IntPtr OpenServer(string Name)
{
IntPtr server = WTSOpenServer(Name);
return server;
}
private static void CloseServer(IntPtr ServerHandle)
{
WTSCloseServer(ServerHandle);
}
private static IList<T> PtrToStructureList<T>(IntPtr ppList, int count) where T : struct
{
List<T> result = new List<T>();
long pointer = ppList.ToInt64();
int sizeOf = Marshal.SizeOf(typeof(T));
for (int index = 0; index < count; index++)
{
T item = (T) Marshal.PtrToStructure(new IntPtr(pointer), typeof(T));
result.Add(item);
pointer += sizeOf;
}
return result;
}
public static DateTime? FileTimeToDateTime(FILETIME ft)
{
if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0)
{
return null;
}
long hFT = (((long) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
return DateTime.FromFileTime(hFT);
}
public static WINSTATIONINFORMATIONW GetWinStationInformation(IntPtr server, int sessionId)
{
int retLen = 0;
WINSTATIONINFORMATIONW wsInfo = new WINSTATIONINFORMATIONW();
WinStationQueryInformation(server, sessionId, (int) WINSTATIONINFOCLASS.WinStationInformation, ref wsInfo, Marshal.SizeOf(typeof(WINSTATIONINFORMATIONW)), ref retLen);
return wsInfo;
}
public static TerminalSessionData[] ListSessions(string ServerName)
{
IntPtr server = IntPtr.Zero;
if (ServerName == "localhost" || ServerName == String.Empty)
{
ServerName = Environment.MachineName;
}
List<TerminalSessionData> results = new List<TerminalSessionData>();
try
{
server = OpenServer(ServerName);
IntPtr ppSessionInfo = IntPtr.Zero;
int count;
bool _isUserSession = false;
IList<WTS_SESSION_INFO> sessionsInfo;
if (WTSEnumerateSessions(server, 0, 1, out ppSessionInfo, out count) == 0)
{
throw new Win32Exception();
}
try
{
sessionsInfo = PtrToStructureList<WTS_SESSION_INFO>(ppSessionInfo, count);
}
finally
{
WTSFreeMemory(ppSessionInfo);
}
foreach (WTS_SESSION_INFO sessionInfo in sessionsInfo)
{
if (sessionInfo.SessionName != "Services" && sessionInfo.SessionName != "RDP-Tcp")
{
_isUserSession = true;
}
results.Add(new TerminalSessionData(sessionInfo.SessionId, sessionInfo.State.ToString(), sessionInfo.SessionName, _isUserSession));
_isUserSession = false;
}
}
finally
{
CloseServer(server);
}
TerminalSessionData[] returnData = results.ToArray();
return returnData;
}
public static TerminalSessionInfo GetSessionInfo(string ServerName, int SessionId)
{
IntPtr server = IntPtr.Zero;
IntPtr buffer = IntPtr.Zero;
int bytesReturned;
TerminalSessionInfo data = new TerminalSessionInfo();
bool _IsCurrentSessionId = false;
bool _IsConsoleSession = false;
bool _IsUserSession = false;
int currentSessionID = 0;
string _NTAccount = String.Empty;
if (ServerName == "localhost" || ServerName == String.Empty)
{
ServerName = Environment.MachineName;
}
if (ProcessIdToSessionId(GetCurrentProcessId(), ref currentSessionID) == false)
{
currentSessionID = -1;
}
// Get all members of the local administrators group
bool _IsLocalAdminCheckSuccess = false;
List<string> localAdminGroupSidsList = new List<string>();
try
{
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + ServerName + ",Computer");
string localAdminGroupName = new SecurityIdentifier("S-1-5-32-544").Translate(typeof(NTAccount)).Value.Split('\\')[1];
DirectoryEntry admGroup = localMachine.Children.Find(localAdminGroupName, "group");
object members = admGroup.Invoke("members", null);
foreach (object groupMember in (IEnumerable)members)
{
DirectoryEntry member = new DirectoryEntry(groupMember);
if (member.Name != String.Empty)
{
localAdminGroupSidsList.Add((new NTAccount(member.Name)).Translate(typeof(SecurityIdentifier)).Value);
}
}
_IsLocalAdminCheckSuccess = true;
}
catch { }
try
{
server = OpenServer(ServerName);
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientBuildNumber, out buffer, out bytesReturned) == false)
{
return data;
}
int lData = Marshal.ReadInt32(buffer);
data.ClientBuildNumber = lData;
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientDirectory, out buffer, out bytesReturned) == false)
{
return data;
}
string strData = Marshal.PtrToStringAnsi(buffer);
data.ClientDirectory = strData;
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientName, out buffer, out bytesReturned) == false)
{
return data;
}
strData = Marshal.PtrToStringAnsi(buffer);
data.ClientName = strData;
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientProtocolType, out buffer, out bytesReturned) == false)
{
return data;
}
Int16 intData = Marshal.ReadInt16(buffer);
if (intData == 2)
{
strData = "RDP";
data.IsRdpSession = true;
}
else
{
strData = "";
data.IsRdpSession = false;
}
data.ClientProtocolType = strData;
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ConnectState, out buffer, out bytesReturned) == false)
{
return data;
}
lData = Marshal.ReadInt32(buffer);
data.ConnectState = ((WTS_CONNECTSTATE_CLASS) lData).ToString();
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.SessionId, out buffer, out bytesReturned) == false)
{
return data;
}
lData = Marshal.ReadInt32(buffer);
data.SessionId = lData;
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.DomainName, out buffer, out bytesReturned) == false)
{
return data;
}
strData = Marshal.PtrToStringAnsi(buffer).ToUpper();
data.DomainName = strData;
if (strData != String.Empty)
{
_NTAccount = strData;
}
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.UserName, out buffer, out bytesReturned) == false)
{
return data;
}
strData = Marshal.PtrToStringAnsi(buffer);
data.UserName = strData;
if (strData != String.Empty)
{
data.NTAccount = _NTAccount + "\\" + strData;
string _Sid = (new NTAccount(_NTAccount + "\\" + strData)).Translate(typeof(SecurityIdentifier)).Value;
data.SID = _Sid;
if (_IsLocalAdminCheckSuccess == true)
{
foreach (string localAdminGroupSid in localAdminGroupSidsList)
{
if (localAdminGroupSid == _Sid)
{
data.IsLocalAdmin = true;
break;
}
else
{
data.IsLocalAdmin = false;
}
}
}
}
if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.SessionName, out buffer, out bytesReturned) == false)
{
return data;
}
strData = Marshal.PtrToStringAnsi(buffer);
data.SessionName = strData;
if (strData != "Services" && strData != "RDP-Tcp" && data.UserName != String.Empty)
{
_IsUserSession = true;
}
data.IsUserSession = _IsUserSession;
if (strData == "Console")
{
_IsConsoleSession = true;
}
data.IsConsoleSession = _IsConsoleSession;
WINSTATIONINFORMATIONW wsInfo = GetWinStationInformation(server, SessionId);
DateTime? _loginTime = FileTimeToDateTime(wsInfo.LoginTime);
DateTime? _lastInputTime = FileTimeToDateTime(wsInfo.LastInputTime);
DateTime? _disconnectTime = FileTimeToDateTime(wsInfo.DisconnectTime);
DateTime? _currentTime = FileTimeToDateTime(wsInfo.CurrentTime);
TimeSpan? _idleTime = (_currentTime != null && _lastInputTime != null) ? _currentTime.Value - _lastInputTime.Value : TimeSpan.Zero;
data.LogonTime = _loginTime;
data.IdleTime = _idleTime;
data.DisconnectTime = _disconnectTime;
if (currentSessionID == SessionId)
{
_IsCurrentSessionId = true;
}
data.IsCurrentSession = _IsCurrentSessionId;
}
finally
{
WTSFreeMemory(buffer);
buffer = IntPtr.Zero;
CloseServer(server);
}
return data;
}
public static TerminalSessionInfo[] GetUserSessionInfo(string ServerName)
{
if (ServerName == "localhost" || ServerName == String.Empty)
{
ServerName = Environment.MachineName;
}
// Find and get detailed information for all user sessions
// Also determine the active user session. If a console user exists, then that will be the active user session.
// If no console user exists but users are logged in, such as on terminal servers, then select the first logged-in non-console user that is either 'Active' or 'Connected' as the active user.
TerminalSessionData[] sessions = ListSessions(ServerName);
TerminalSessionInfo sessionInfo = new TerminalSessionInfo();
List<TerminalSessionInfo> userSessionsInfo = new List<TerminalSessionInfo>();
string firstActiveUserNTAccount = String.Empty;
bool IsActiveUserSessionSet = false;
foreach (TerminalSessionData session in sessions)
{
if (session.IsUserSession == true)
{
sessionInfo = GetSessionInfo(ServerName, session.SessionId);
if (sessionInfo.IsUserSession == true)
{
if ((firstActiveUserNTAccount == String.Empty) && (sessionInfo.ConnectState == "Active" || sessionInfo.ConnectState == "Connected"))
{
firstActiveUserNTAccount = sessionInfo.NTAccount;
}
if (sessionInfo.IsConsoleSession == true)
{
sessionInfo.IsActiveUserSession = true;
IsActiveUserSessionSet = true;
}
else
{
sessionInfo.IsActiveUserSession = false;
}
userSessionsInfo.Add(sessionInfo);
}
}
}
TerminalSessionInfo[] userSessions = userSessionsInfo.ToArray();
if (IsActiveUserSessionSet == false)
{
foreach (TerminalSessionInfo userSession in userSessions)
{
if (userSession.NTAccount == firstActiveUserNTAccount)
{
userSession.IsActiveUserSession = true;
break;
}
}
}
return userSessions;
}
}
}
"@
## Add the custom types required for the toolkit
If (-not ([Management.Automation.PSTypeName]'PSADT.UiAutomation').Type)
{
[string[]]$ReferencedAssemblies = 'System.Drawing', 'System.Windows.Forms', 'System.DirectoryServices'
Add-Type -TypeDefinition $TypeDefinition -ReferencedAssemblies $ReferencedAssemblies -IgnoreWarnings -ErrorAction 'Stop'
}
Try
{
Write-Output -InputObject ([PSADT.QueryUser]::GetUserSessionInfo("$($ComputerName)"))
}
Catch
{
Write-Warning -Message "Unable to communicate with `'$($ComputerName)`'"
}
}
#endregion