Introduction
When you're in an environment that has multiple virtual machines with each machine having RDP account connection limitation (e.g., only x maximum concurrent terminal service users) or will be too slow for more than one user, and you would like to quickly know which machines have extra connection available or if a machine is free, it is a waste of time to connect to each one.
On average, an RDP connection attempt takes 30 seconds and, on top of that, checking if another user(s) is connected will take around 3 minutes. Using Terminal Services Manager can cut this time down but still you'll have to spend 10 to 15 seconds checking each known machine...but what if you want to scan including the newly added machines that you're not aware of?
What if you want to have a bird's eye-view of the network domain and its current users and also be able to print (print screen for now) this view? What if you need the Full Name of each connected user (disconnected/timed-out users are not displayed) instead of their usually unintelligible login names?
What if you want to know if a user is unreasonably using a lot of machines?
Background
Note that this solution is not limitless as it can only scan virtual machines that are exposed to the current machine's network domain where you will run this tool. I know some guys especially network administrators can have a better explanation about this so let's leave it to them.
Also note that this project took 1.5 hours to create on a staggered basis covering three days (I have a day job and a personal life like everyone else) so for a moment please brush aside the "this project needs refactoring!" thought running in your mind. Consider this as a very quick 1-hour project if done continuously
Using the Code
My approach is to briefly give you an explanation of the source code and how it is mainly structured. Feel free to look at the project source code for the rest of the functionalities not mentioned here.
- Note the following references:
using System.Windows.Forms;
using ListNetworkComputers;
using System.Security.Principal;
using Cassia;
using System.DirectoryServices;
We reference the ListNetworkComputers project only (quickest approach) just to get access to the NetworkBrowser
class. The ListNetworkComputers project was created by Sacha Barber with the link at the end of this post.
The Cassia .Net library is "for accessing the native Windows Terminal Services API (now the Remote Desktop Services API)" and is from Google Code with link at the end of this post.
- The main functionality is presented below, which is where I integrated all the pre-existing functionalities for my purpose:
try
{
NetworkBrowser nb = new NetworkBrowser();
ArrayList al = nb.getNetworkComputers();
ITerminalServicesManager manager = new TerminalServicesManager();
for (int x = 0; x < al.Count; x++)
{
...
panel1.Controls.Add(lblComputer);
try
{
using (ITerminalServer server = manager.GetRemoteServer(al[x] as string))
{
server.Open();
int locationCounter = 0;
foreach (ITerminalServicesSession session in server.GetSessions())
{
NTAccount account = session.UserAccount;
if (account != null)
{
Label lblUser = new Label();
string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))",
"person", session.UserName);
DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + session.DomainName,
null, null, AuthenticationTypes.Secure);
DirectorySearcher searcher = new DirectorySearcher(adRoot);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.PropertiesToLoad.AddRange(new string[] { "fullname" });
searcher.Filter = filter;
SearchResult result = searcher.FindOne();
DirectoryEntry directoryEntry = result.GetDirectoryEntry();
if (directoryEntry != null)
{
lblUser.Text = directoryEntry.Properties["displayName"][0].ToString();
}
else
{
lblUser.Text = account.Value;
}
...
}
}
}
}
...
}
}
...
Points of Interest
Please do note that I am in no way attempting plagiarism or claiming something that is not mine. The list below are the exact sources/references of the source codes as applicable...what I only did is to create a (very quick) structure of functionality that will merge all of the useful parts of these codes for my intended purpose. There are tons of improvements (modularity, interactivity, efficiency, late-binding, etc. etc.) to be done here so feel free to improvise. Please refer to the following links to get details on the specific libraries and classes that I used.
Licenses: The third-party components/libraries/codes used in this project may have respective copyrights/licenses of their own. Refer to the third-party sites and observe their copyrights/licenses. Codes that I have created in this project are under CPOL License.
Ritchie Grijaldo is a Microsoft Certified Professional Developer for Enterprise, Web, and Windows Applications. More than 10 years of experience in migrating, designing, and developing n-tier applications. Designed and developed a WCF service impervious to hacking exploits, is robust, scalable, extensible, architecturally secure, a high-performing and efficient solution for validating and converting PDF documents into the standard PDF/A archiving format. Senior Developer for ASP.Net 3.5 custom workflow application hosted within a SharePoint 2010 site. Delivered solutions using Windows Azure.
Technical Skills:
- C# 5.0/6.0, C#.Net Best Practices, .Net Design Patterns, WCF
- SharePoint Development, XSLT, ASP.Net, SQL Database Design
- JQuery, AJAX, KnockoutJS, HTML5, ECMAScript 6, CSS3
- MVC, MVVM, MVP
- SQL Scripting, PowerShell Scripting
- ETL, SOA, TDD, SDLC Concepts
- Secure Software Design, High Performance Computing (Multithreading, Multiprocessing, C#.Net Code Performance Optimizations), Application Analysis & Detailed Design
- Old Projects: J2EE, SNMP, CIMD2, PHP, ColdFusion, Classic ASP, Oracle Identity & Access Management, Microsoft Azure Development