I want to be able to create a powershell script that will tell me, for all RDP sessions currently active on a machine, who the user is, and what their clientname (machine name) is.
I can use a combination of win32_loggedonnuser and win32_logonsession to get the username information, but I can't find the client name in these objects (enumerations?).
PS C:\> $logons = gwmi win32_loggedonuser; $lstring = ""; foreach($l in $logons) { $lstring +=$l;} $lstring -match "cephalopod";
False
PS C:\> $sessions = gwmi win32_logonsession; $sstring = ""; foreach($s in $sessions) { $sstring +=$s;} $sstring -match "cephalopod";
False
(cephalopod is my machine name, the machine that's logged into the server box)
.
I can see that HKCU:\Volatile Environment
does have the client name, and the temp
key has the user name within it, but I can't establish from the keys alone if the session is currently active.
Am I missing an API call that will get me all this information in one place?
Basic requirement: grep out the Task Manager > Users listing for user and client name, where status is active.
There is no WMI interface for this that I know of.
Yep. You can get the data from the Win32 API. From wtsapi32.dll, to be specific. You can write a C program, or you can P/Invoke it from C# or even Powershell.
Since you probably want Powershell, I wrote this for you this morning:
Copy all of that into a file named QuerySessionInformation.ps1. Now launch the 32 bit version of Powershell in C:\Windows\SysWOW64\WindowsPowershell\v1.0. The code above uses pointers that will not work in a native 64 bit environment.
Now run the script. If you've never run the 32 bit version of Powershell on that server before, you will need to modify the script execution policy with Set-ExecutionPolicy, as 32 bit and 64 bit Powershell have separate execution policies. Note that there should be no output from the script itself, as all it is doing is compiling the .NET code and adding it to the current environment. Also note that once a type is added with Add-Type, you can not unload it without exiting that Powershell session... AFAIK. It makes debugging this sort of stuff really annoying as you have to restart Powershell every time you modify the code.
Now that the code is loaded, type this:
If there are any active user sessions on REMOTESERVER, the output will look like this:
This will work on remote computers as well as the local computer, but beware that if the user running this does not have sufficient permissions to the remote computer, it will fail silently (no output.)
Edit: There are other bits of info in WTS_INFO_CLASS that may be of interest to you, such as WTSConnectState and WTSClientAddress. All you have to do is query for them.
Edit: I have also converted this solution to native code (C) for use on the command line:
http://www.myotherpcisacloud.com/post/2013/01/16/Usersexe-v1003.aspx
Would PS Terminal Services (for Powershell) do the trick? I use this all the time on our 10 Terminal Servers.
PS > Import-Module PSTerminalServices
PS > Get-tssession -computername {name}
This is a wonderful utility.
Execute quser /server:[the servers name] >[the path to the text file].txt
It lists all of the info, pipes it to a space delimited text file so it can easily be imported & dissected. Works great and avoids any complexities of calling native APIs that are 32 or 64 bit dependent. Can be done all in managed code if it's a .Net focused app.
Many thanks for the script.
I found one limitation ; Because of "Console.WriteLine", it's not possible to pipe the result (in a Select-String for example). I've modified your class to be able to do so. The method Listuser returns a List
Once the Class is loaded then just call [RDPInfo]::NEW().listusers("myserver") And then you can pipe the result.
http://weblogs.asp.net/owscott/archive/2003/12/30/Managing-Terminal-Services-Sessions-Remotely.aspx
might be more useful to you :)