2

I have a C# application that is being installed for all users.

Every user on the pc can use the program, and I need to store user-specific Data per user.

I started with Enviroment.SpecialFolder.ApplicationData giving me C:\Users\USER\AppData\Roaming. But when users choose run as admin and enter admin credentials, then this won't work, it will give me: C:\Users\ADMIN\AppData\Roaming

So I started using a WMI call:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();    

string username_with_domain = (string)collection.Cast<ManagementBaseObject> ().First().ToString();

and get the folder by the username.

But: this won't work in a Remote Desktop Session (RDP / MSTSC) - it returns "" so I have to fallback to Enviroment.UserName.

Summary

  • User starts .exe: Works. (ENVIROMENT.UserName)
  • User uses "run as Administrator" with "ADMIN" user: Works. (WMI Call)
  • User starts .exe in a RDP session: Works. (fallback to (ENVIROMENT.UserName))
  • User starts .exe in a RDP session with "run as Administrator" with "ADMIN" user: does not work

Question: How can I get the AppData folder or Username of the current logged in User? e.g. who owns the Desktop I see?

KYL3R
  • 3,877
  • 1
  • 12
  • 26
  • Why do they need to run as admin? – Tony Hopkinson Jun 04 '20 at 14:48
  • The installer has to run as admin (to install for all users) and opens the application after installation. Also, the application will become features requiring admin features (later). – KYL3R Jun 04 '20 at 14:51
  • 1
    Think I'd partition. only admin features available when running as admin and user features when not, then the appdata folder issue should be ameliorated. – Tony Hopkinson Jun 04 '20 at 15:26
  • When running an application as Admin, they are effectively running it as a different user. Part of the problem is the perceived need to run as an administrator. I would recommend putting any administrative functionality in a separate executable you can call from the main application. That allows you to increase privileges when you need to--and pass in any paths as arguments. – Berin Loritsch Jun 04 '20 at 16:33
  • @Berin, sounds quite reasonable. I wondered how games do this, but they simply store savegames in the directory. Multiple users see all savegames in the game I guess. Or it's installed per user and you don't have a problem. – KYL3R Jun 04 '20 at 17:05
  • Many games have a launcher that requires admin privileges, but the game itself is run as the logged in user. The launcher takes care of patching the game files when necessary. – Berin Loritsch Jun 05 '20 at 02:56

1 Answers1

1

While not directly related, a good discussion about your question appears here: Run a process from a windows service as the current user

The main problem you're facing is that there can be multiple users logged on to the same desktop (https://www.codeproject.com/Articles/13822/Get-Information-About-the-Currently-Logged-on-Us-2). If that's the case, which user do you pick (the "Inspect Event Log Data" section below provides a potentially helpful answer to this question)?

As the above SO link advises, you can take one of these approaches:

  1. Install a service with the application that captures the current user (rather than the "run-as user" in the background and stores that information in a repository that the launched application can access.
  2. Use the Windows API--the above link goes into details.

Add User Authentication To Your App

Of course, another way is for your app to require each user to identify him/herself at launch--this would work even if "run as" was used to impersonate another user. You could check this against valid users maintained by your application or through a repo such as active directory and then use that User's name to compose the user-path string you originally tried to detect.

Inspect Event Log Data:

With your feedback (in comments), I have a different take that might work for you. The Windows event log records successful desktop logon with Event ID 4624 under the Windows Logs -> Security event viewer branch. That event contains a timestamp value. It seems to me that if you filter these event log entries by Event ID 4624 and grab the latest one that indicates a Security ID of a user on the domain in question (you decide exactly how to filter this based on your needs), you should be able to determine the user ID of the user who "owns the desktop", as your post requested. I don't see how this approach could fail. I do understand that you might have access issues to the Event Log data, but I think that this might happen only for the non-Admin security context. In that case, System.Security.Principal.WindowsIdentity.GetCurrent().Name should give you the non-Admin user name every time; if that returns an Admin user name, then--and only then--would you need to delve into the Event Log in order to do your analysis. You can find posts (such as Read event viewer entries) that help you explore the Event Log from C#.

Jazimov
  • 12,626
  • 9
  • 52
  • 59
  • Sadly, this does not work. This is returned: `CMP_NAME\AdminUser`. When not using run-as it returns `CMP_NAME\NormalUser` – KYL3R Jun 04 '20 at 14:10
  • Apologies--I relied on Microsoft documentation that suggested my original answer would have worked. I have revised my answer. – Jazimov Jun 04 '20 at 14:35
  • hmm. Thanks. Option 1 is 346 lines of questionable code, hijacking the explorer token... Option 2 looks a bit scary too. am I overseeing something obvious? I can use the "CURRENT_USER" registry in all cases perfectly - but no current-user-folder ? – KYL3R Jun 04 '20 at 14:57
  • 1
    Yes, understood. I am unable to test all of your scenarios, but can you try issuing a WHOAMI command and capturing that output? See https://stackoverflow.com/questions/51167228/how-can-i-get-the-log-on-id-from-the-whoami-exe-result-in-c-sharp-code – Jazimov Jun 04 '20 at 15:11
  • in a remote session, logged in as "NormalUser", running cmd.exe and `whoami/user` gives `CMP_NAME\Normaluser`. Then running the cmd.exe as admin with `whoami/user` gives `CMP_NAME\AdminUser` again :/ – KYL3R Jun 04 '20 at 15:34
  • 1
    Please try my latest edit ("Inspect Event Log Data") above. I hope that helps. – Jazimov Jun 04 '20 at 16:47
  • Creative idea, might work, but there are many Logons visible including "ADMINISTRATOR" etc. so not sure if comparing timestamps works out. If it's this hard, I might just try going another way. I will see if I get it working as runned-by-user-only and start elevated process for Admin stuff. Should turn out cleaner than any of the above hacks. Thank you for your suggestions. Upvoted. – KYL3R Jun 05 '20 at 13:24
  • Thanks--they are hacks for sure, but without OS support for a "desktop owner" value, what to do? I added one last idea--one that seemed almost too obvious to mention. Good luck! – Jazimov Jun 05 '20 at 15:01
  • well the app allows users to log in to the Azure AD, and the login Token is saved (protected) per user. But during testing, 2 persons used the same pc with 2 accounts, but using the same (run-as) Admin account to install stuff - they noticed they were logged in as the "other" person, who logged in before - simply because both tokens were stored in "AdminUser/AppData". So that idea does not help sadly :P – KYL3R Jun 05 '20 at 20:39