-3

My program depends on information that changes depending on which user is logged in. An example would be the location of AppData. My program also needs Administrative privileges. If I run the program as Administrator, the program thinks the Administrator is the currently logged in user.

My "solution": Create a second program to run as console. It runs as a standard user, putting information into variables to correctly identify the current user. It then save the main program, from Resources, to disk, starts it, then passes these variables via Arguments.

The problem: I have to Build the program twice before I can test it. This is very annoying.

Although my solution works, I'm tired of it. Is there any other way I can get the currently (active) logged in user? I've tried SystemInformation.UserName.ToString and My.User.Name.ToString. Both give the wrong user.

Edit: System.Security.Principal.WindowsIdentity.GetCurrent().Name does not work.

Proposed Solution: Instead of having a program run before my main program to gather information, I will try to have that program run at the same time my main program does. My main program will wait until the information has been sent back, and then resume. This way, I don't have to double build all the time.

Tyler Montney
  • 1,402
  • 1
  • 17
  • 25
  • http://stackoverflow.com/a/1240379/327083 – J... May 15 '14 at 08:48
  • 1
    possible duplicate of [How do I get the current username in .NET using C#?](http://stackoverflow.com/questions/1240373/how-do-i-get-the-current-username-in-net-using-c) – J... May 15 '14 at 08:48
  • I know the dupe is C#, but the answer and problem are, for all intents and purposes, identical. – J... May 15 '14 at 08:49
  • It is not a duplicate. That solution does not work. – Tyler Montney May 15 '14 at 09:05
  • From app manifest, I have it require Administrator ( – Tyler Montney May 15 '14 at 09:20
  • I tried running an example app as admin (with ``). UAC kicks in, `new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)` returns `True`, but `WindowsIdentity.GetCurrent().Name` returns the correct username. – sloth May 15 '14 at 09:42
  • @TylerMontney Read all the answers - `Environment.UserName` is what you want. – J... May 15 '14 at 09:59
  • @sloth Do you have your Administrator account enabled? Does your account have Standard or Administrative privileges? – Tyler Montney May 15 '14 at 10:22
  • @TylerMontney Local administrator is enabled. The account I tested is in the admin group (but it's not in the same domain). – sloth May 15 '14 at 11:20
  • what are you doing that the program needs Administrative privileges all the time? – Ňɏssa Pøngjǣrdenlarp May 15 '14 at 12:36

4 Answers4

1

This answer will probably be controversial, because it isn't strictly answering the question in the title. But it is nevertheless the correct answer to the question. The question explicitly asked is what is known as an XY problem. You have encountered a problem, figured out a possible solution in your head, and then run into trouble implementing that solution, so you've asked for help. The issue is that the solution you've figured out in your head is not the correct one.

My program depends on information that changes depending on which user is logged in. An example would be the location of AppData.

This is normal. You do not, however, solve it by detecting which user is logged in. That won't do you any good anyway. Say you know the name of the user: how are you now going to use that to figure out the AppData folder? I suppose you're going to try and compose a path manually, based on your knowledge of the folder's location in a default installation of Windows: C:\Users\<the user name>\AppData\. But you've just blundered. What happens if the user has mapped their profile directory someplace else? What if the user name doesn't match the name of the directory in the Users directory (e.g. if the Administrator account has been renamed)?

The real solution to this problem is altogether simpler. You simply ask Windows for the path of the AppData folder. Let the operating system do its job keeping track of the logged in user.

Normally, in Windows, you would call the SHGetKnownFolderPath function, or its moral equivalent. In the .NET Framework, that functionality is wrapped by the Environment.GetFolderPath method. Simple, and guaranteed to be correct.

You will want to specify either SpecialFolder.CommonApplicationData (the AppData folder for all users), SpecialFolder.ApplicationData (the roaming AppData folder for the current user), or SpecialFolder.LocalApplicationData (the non-roaming AppData folder for the current user).

My program also needs Administrative privileges. If I run the program as Administrator, the program thinks the Administrator is the currently logged in user.

Because it is. If you're running the program as Administrator, then for all intents and purposes, the program will be run as Administrator. That means returning Administrator as the name of the current user, returning the Administrator's AppData folder, and so on and so forth. This is quite logical, it is what enables the program to do Administrator-specific things.

But beyond that, it is bad practice (in all but the most unusual of cases) to have an entire application that requires Administrative privileges. Generally, there are only one or two actions taken by an application that truly require Administrative privileges. For example, I have a little utility that I wrote. None of its basic functions require Administrative privileges, but it has a feature to install itself so that it is launched on startup for all users. Clearly that requires Administrative privileges, but that's only a one-time speciality feature. You don't want the entire app to require Administrative privileges just for that specialized function. What if the current user can't get Administrative privileges? They should still be able to use the software, just with the Administrator-specific functionality disabled or otherwise inaccessible.

And this fits with Windows's model for process elevation. There is no way to temporarily elevate the current process. You have to start a new elevated process, do whatever it is that requires Administrative privileges, and then quit that process. I have written detailed instructions here on how to do that. Of course, they are in C#, but trivially translated to VB.NET.

Is there any other way I can get the currently (active) logged in user? I've tried SystemInformation.UserName.ToString and My.User.Name.ToString. Both give the wrong user.

Like I said above, the information is not "wrong". You said it yourself: they are returning the "currently (active)" user: Administrator. The one you requested the app to be run as.

With the solution I proposed above, your app, running normally, would not be run as Administrator. That would increase security, and it would ensure that you get information applicable to the currently logged in user. When you need to perform actions that require Administrator privileges, you spin off a second elevated process, do the work, and then exit that process. The elevated process acts as Administrator, for all intents and purposes, which is almost always what you want.

For what it's worth, I frequently see questions like yours from people who are trying to write an installer (don't do that, just use one of the many excellent installers already available). Their installer requires Administrative privileges, obviously, so they set it to request elevation on startup. So far, so good. Except that they want to write data to a specific user's AppData folder during the installation. Now they have a problem, because (1) they can't get that path, and (2) there might not even be another logged in user. The solution, and the one officially recommended by the Windows Logo guidelines, is to do this type of initialization on first-run. In other words, the first time that the installed application is run by a normal user. Then you get the AppData folder you expect.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Got to say, can't argue with that logic and I think that is an excellent (and entirely correct, in every sense) answer. But I fear the OP may not see it that way. – Steve Pettifer May 15 '14 at 09:46
  • *That means returning Administrator as the name of the current user, returning the Administrator's AppData folder, and so on and so forth.* Is that true if you elevate a process with UAC? My experience say otherwise. Also, when you run an application as administrator, e.g. the task manager still shows the logged-in user as owner. – sloth May 15 '14 at 09:55
  • @sloth Yeah, I guess the situation is a bit more complicated than I make it sound. I thought about testing the various scenarios for myself, but I'm sitting here on a MacBook Pro without any kind of Windows environment installed. My dev box is at least one room away, and I'm super lazy. Also, I should be sleeping. :-) – Cody Gray - on strike May 15 '14 at 09:59
  • What you've said is correct, but doesn't apply to what I'm asking. True, I would run individual operations as Administrator and have the rest of the program run standard. Pretty much ALL of my program needs Administrative privileges. As I am typing this, I discovered a possible solution. Rather than having each and every checkbox apply changes immediately, I should have them "stack up" waiting for an "OK" button to be pressed. Otherwise, I would've had a UAC prompt for every checkbox. – Tyler Montney May 15 '14 at 10:06
  • The AppData folder was merely an example. My program does lots of registry entries, and Windows Service manipulation. Obviously, Administrative privilege is implied. A user doesn't have Administrative privileges? That's OK by me. My program assumes you have Administrator privilege, whether it be elevation or direct Administrative rights. Since some of my registry entries are in CURRENT USER, that changes if the program is run as a different user. So if I run the program as Administrator, to get rights, it will makes changes for the wrong user (Administrator). – Tyler Montney May 15 '14 at 10:09
  • And I never meant to imply that "the information I received is wrong", such as SystemInformation.UserName.ToString and My.User.Name.ToString. Obviously it's doing its job, just not what I thought it would do. It's wrong information for the job I want to do. @sloth if you have the Administrator account disabled, it will still show the correct user (because you're the only available Administrator), assuming your main account is an Administrator itself. – Tyler Montney May 15 '14 at 10:10
0

I believe Environment.UserName gets the currently logged in user (not the 'run as' user). Can also query WMI as follows:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();
string username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];

This was from this SO question.

Community
  • 1
  • 1
Steve Pettifer
  • 1,975
  • 1
  • 19
  • 34
0

solutions found here Detect Current Logged on User with VB.Net and getting username in vb.net

I also needed to write application to go directly to a local path which I already have the url. c:\users\username\appdata\packages and "environment.username" works for me. I just declared a variable to hold it

Sam Hanley
  • 4,707
  • 7
  • 35
  • 63
boluvi
  • 1
  • Rather than just linking to answers elsewhere (which may break or be removed), it's much more useful to summarize the helpful information in your answer itself. – Sam Hanley Feb 24 '15 at 19:01
0

Having popped up on my feed as a frequently viewed question, I'd like to take a shot at "answering" my own question.

Backstory is I was trying to create a registry tweak utility (partially as a way to teach myself VB). I was very new to programming at the time. I'd check a box and have it immediately apply. Some of the tweaks were HKEY_CURRENT_USER. At least for Windows 10 if you're in the local Administrators group and you elevate, it still has you as the running user. Perhaps UAC performed differently with Windows 7, perhaps I was running two accounts (User and Administrator). I believe I was trying to account for a fringe case.

Either way, if the user elevates (or runas) a different user, obviously it'll list the process as that user. Here are some ways you might be able to detect the interactive user:

  • Event Log: Event IDs 4624 (Logon_Type 2) and 4648 both will list the user trying to elevate. It won't list the actual program, probably svchost.exe. If you have process creation enabled (GPO), you may be able to correlate Event ID 4688 for new processes spawned.
  • Executing Path: If it's in the user's folder (aka C:\Users\myuser), it might be a good indicator that's the user trying to elevate (especially if you enumerate local Administrators and find the user is a regular user).
  • Least Privilege: I believe I suggested this eventually. Run the program as the interactive user. Elevate only when necessary. If you have control over redirection, you can pass the username.
  • Registry: If it's user-specific, hitting HKEY_USER may be applicable (to avoid redirection).
  • Check explorer/logonui processes: If a user is logged in interactively, an explorer process should be running. If they're locked, there should also be a logonui process.
  • query /user: This command isn't easily parseable. However, it isn't affected by elevation (it always knows the interactive user).
  • interactive user: Based on https://serverfault.com/questions/188115/what-is-windows-interactive-user, users are assigned special identities automatically. I haven't figured it out, but perhaps there's a way to enumerate those to determine if a user is interactive.

All of the above aren't necessarily bulletproof nor are they one size fits all. You may need to use more than one together to ensure you get it right, especially if your needs are mission critical. The above also assumes you have the knowledge to implement each individual one. (e.g. How do I read from Event Log using C#.) There's more than enough guides and threads, especially on SO, that will explain it. I don't think it's necessary to rehash that, especially considering my question was more sysadmin related than anything.

Tyler Montney
  • 1,402
  • 1
  • 17
  • 25