C# Application (All-Users Installtion) should use %appdata% per User (even runAs Admin and/or in RDP Session)

Viewed 285

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?

1 Answers

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#.

Related