Is there a way to limit the number of users who can open my application if they install it on a terminal server?
I have a new site that solely uses terminal server, they claim only 3 users will need to use the application, but all 3 use terminal services and from my knowledge, any application installed onto the terminal server will be accessible by anyone on that server, unless the system admin blocks it - but that is not me policing it.
Anyway, this site has something like 20 or 30 people using the terminal server, so licensing it for 3 when potentially anything up to 30 will be using it is a significant loss in revenue for me, so I need to ensure that only 3 people will be able to use it (preferably a set 3 and not any 3).
any ideas? I guess I would need to check the system OS so that the systems will identify that it is coming from the same system - just thinking aloud.
Currently I utilize a SQL 2012 database, so could I limit it in there somehow?
thanks in advance.
First of all I found this C# script that would at least identify whether the RDS is installed, any idea if this can be used/adapted for SS?
static void Main(string args)
// 14 is the identifier of the Remote Desktop Services role.
static bool HasServerFeatureById(UInt32 roleId)
ManagementClass serviceClass = new ManagementClass("Win32_ServerFeature");
foreach (ManagementObject feature in serviceClass.GetInstances())
if ((UInt32)feature["ID"] == roleId)
// The most likely cause of this is that this is being called from an
// operating system that is not a server operating system.
If it's a central database you could add a user table and keep track of who's logged in that way. You can get the logged in user name from the USERNAME environment variable (so you don't have to prompt them for it) and deny access to any user name you don't find in the table or if they are already logged in. You could even count the number of logged in users.
One problem you may run into with this approach is that users logged in states in the table may get out of sync with the real world due to a crash or stray cosmic ray and you'll need a way to reset a users status. It's a bit of pain but it's manageable.
QUOTE: from northcode;55062
I have seen other applications with this approach and they have a "monitoring" app that the end user can use to kick users that are supposedly still connected.
I will need to investigate and plan this thoroughly.
I am trying to lock down the usage based on the number of licenses purchased no matter if the same user logs on across multiple devices or different users log into the same device.
What I have thought so far is to save in the SQL database the total number of licenses purchased and then in a table record a system and username to license them, when the number of systems recorded reaches the number of licenses, then they will not be able to run it on any other system, unless I log in and delicense a system, or they purchase additional licenses. With the identification of Remote Desktop Services, this will allow me to license by user login and for systems not running RDS (like Windows desktops) I will be able to license by workstation name. This should also allow me to stop using the expiry component from Swf Studio and just rely on the data in the database. I will need to write an admin module for me to manage the licenses, but that is no biggie. I intend to encrypt the data for the licensing so that no one can look at the data and change it. And I am trying to determine the best way to create a static GUID that I can use to "fingerprint" the system as well.
Does that sound like a workable solution?
I have found and tweaked a jscript file to determine if Remote Desktop Services is installed on a system...
var wbemFlagReturnImmediately = 0x10;
var wbemFlagForwardOnly = 0x20;
var objWMIService = GetObject("winmgmts:\\\\.\\root\\CIMV2");
var colItems = objWMIService.ExecQuery("SELECT * FROM Win32_ServerFeature WHERE ID=18", "WQL", wbemFlagReturnImmediately | wbemFlagForwardOnly);
var enumItems = new Enumerator(colItems);
var s = "";
for (; !enumItems.atEnd(); enumItems.moveNext())
var objItem = enumItems.item();
s = objItem.Name;
I also found out that the role is 18 not 14 as my previous post mentioned.
Now I can determine if it is a terminal server, so now I can make sure that certain location calls are related to the user and not a global location.
If you combine the idea of a central license manager with a USB drive as the "fingerprint" then you may have a solution. Every USB drive has a unique id that you can use to uniquely identify your users. You can give them an unlimited number of USB "keys" and still limit them to N at a time using the license manager on the back end.
QUOTE: from northcode;55065
Okay I think this is looking more promising - so how do I get the UUID from a USB drive?
so the UUID from Win32_ComputerSystemProduct under WMI - is that not a unique fingerprint code on each computer?
or the registry key...
Do either of these change?
How do I ascertain which MAC address a system has for their network connection, if the device has multiple network cards?
i.e. if the system has a bluetooth, wireless and LAN connection, and the LAN connection is the one being used, how is it best to identify that and only that MAC address?
The Win32_ComputerSystemProduct UUID and the MAC address of the primary network adapter both come from hardware and should not change unless the motherboard or the network adapter are changed. Avoid using anything from the registry for a unique id, it's way too easy to change.spoof.
If you're using the hardware ids and someone installs your software on a VM, activates your software and then clones the VM they can run as many copies of your software as they want (unless you're managing licenses as well).
With a dongle you can eliminate the possibility of cloning and avoid tying your software to a specific machine.
The primary network adapter SHOULD be the first one in the list. It works that way on all the machines I've tried it on but I can't guarantee it always works that way.
So I would say that there's no way to get this (reliably) from SWF Studio right now and I'm not sure that there is a definitive way. The primary adapter (for me) is whatever one I'm using. It could be the one attached to the ethernet port (when I'm at home) or the wi-fi adapter (when I'm on the road).
BTW, I now have this working as I intended.
Where the jscript identifies the system as a Terminal Server, I save (and check) the UUID of the device, the username of the device and the PC Name of the device and store that in a table in my SQL database. Where the system is not a Terminal Server, it only saves and checks the UUID and the PC Name. This information is encrypted ssCore.Crypto so no prying eyes can see it :).
I store the total number of licenses (also encrypted) that they have and then when the application starts it checks the items mentioned above within the database against active licenses as well as whether the number of active licenses exceeds the total number available. So if the client has only purchased 3 licenses, it is either 3 terminal users, or 3 workstations, or a combination of the two, but it will not run a 4th application as there are insufficient licenses. I have also created an admin component where I can delicense and relicense systems where they may do a PC shuffle and want to transfer the license to another device, or add more licenses if they purchase them.
Now that is working I was able to split my application into two and I can license for either component or both components, and the licensing will determine what buttons are visible to the end user - yippee, I finally have done it and locked it down (as best I can and more than my clients will understand) - this will inevitably catch out those who have found a way around the current system, especially the terminal server users :).