I'm trying to retrieve all the users that have ever logged into a pc and populate them in a combobox, but after searching, I'm not finding any good answers.
I was going to look at the:
DirectoryInfo(Environment.GetEnvironmentVariable("USERPROFILE")).Parent.GetDirectories();
But I feel that is way to unreliable.
Next I was going to look at the registry, but after reading, that list will not update if a user account name has ever been changed. I know there has to be a record of all the user profiles on a machine, because I have used Microsoft systernals tools to manage them. but I just cannot figure out how to do it programatically with c#.
Ok, well, i figured this out, actually with WMI after all, here is my code.
using System.Security.Principal;
using System.Management;
private void GetLocalUserAccounts()
{
SelectQuery query = new SelectQuery("Win32_UserProfile");
ManagementObjectsSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject sid in searcher.Get())
{
MessageBox.Show(new SecurityIdentifier(sid["SID"].ToString()).Translate(typeof(NTAccount)).ToString());
}
}
This also returns the system accounts IE: NT_Authority NT_System, but those can be filtered easily. Thanks for all the help.
I would suggest to take a look at WMI. It allows you to run sql-like queries on a machine to get loads of system informations.
Some inspiration in VBScript : http://social.technet.microsoft.com/Forums/en-US/ITCG/thread/2b99b836-ed8f-4146-89e4-947b79bf4862/
If the user is created on the local machine, it should have a user folder, as Joshua said.
Also, you could try running CMD's "net user" command and capturing the return value using something like this.
Edit: per the comments below, check this out and see if it helps: https://stackoverflow.com/a/8455654/1046689
You could iterate the %windir%\Users directory ommitting default folder names (public/admin etc) and parse out the usernames from the filenames
Related
I have created an agent to read windows event using WMI. I ma using the agent from last 3 years to collect events. It is used in a SEIM product. The query looks like
SELECT * FROM Win32_NTLogEvent where LogFile = 'System' or logFile='Active Directory Web Services'
I am able to get the events properly. But Now I want to read apploacker events 'Microsoft-Windows-AppLocker/EXE and DLL' (Application and Security Logs -> Microsoft -> Windows -> AppLocker -> Exe And DLL).
I tried the below query but it returns zero record though I have 40+ records in it. I can see the record in event viewer.
SELECT * FROM Win32_NTLogEvent where LogFile = 'Microsoft-Windows-AppLocker/EXE and DLL'
I have tried with "wbemtest" but no record with no error.
I am not sure if this can be achieved by any other way using WMI. I know Powershell has a cmdlet and through which I am able to read 'Microsoft-Windows-AppLocker/EXE and DLL' events. But I want to read it using WMI.
Any pointers will be highly appreciated.
Thanks in advance to all viewers.
It seems that the WMI Query parses the registry location HKLM\SYSTEM\CurrentControlSet\Services\EventLog for available event logs (see MSDN Forum post).
Check the list you find there with the result of the query Select * FROM Win32_NTEventLogFile.
To add a logfile for WMI operations, add a new key under the above registry location with the name of the log ('Microsoft-Windows-AppLocker/EXE and DLL' in your case). Now it should return that log with your WMI query.
Depending on the PowerShell version, you could use the "Get-WinEvent" command to simplify what you're doing.
https://msdn.microsoft.com/en-us/powershell/reference/5.0/microsoft.powershell.diagnostics/get-winevent
Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL"
I am currently writing a C# service to basically make sure a group of exes are running and if they aren't then relaunch them.
The service starts up automatically so I run in to the problem that it attempts to launch the exe when no one is logged in. I have a solution that works for non-VM systems as shown below:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();
string loggedIn = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];
I then check this against null or whitespace and then just don't check the process list if no user is logged in.
However, while running on a VM this section of code returns null when a user is logged in. So I need a way of checking for a logged in user on both a standard machine and VM. I also need it to work for XP and windows 7, and both 32bit and 64bit. I am using .Net 4.
Official documentation to list sessions prescribes to use LsaLogOnSessions to enumerate them, refer to MSDN or to this CodeProject article for more examples.
That said if you just need to be sure there is at least one logged in user then you can simply check for default shell process. Default shell will always be loaded for each session:
bool loggedInUserExist = Process.GetProcessesByName("explorer").Any();
In this example I hard-coded value but you must read it from string value Shell in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\, in case default shell has been overridden (or for Server Core installation when GUI isn't present).
If you don't need anything else then you're done. If you have to filter specific users then you have to get process' owner. It's not such easy in C# unless you use WMI to query Win32_Process, search for explorer in Name property and then call GetOwner() method of the ManagementObject (see this post here on SO). Note that you may use same query both to determine if there is any logged in user and who he is. As alternative you may P/Invoke for Windows API functions as described in this post (but in this case I'd go back to LsaLogOnSessions).
In add or remove programs you can view list of updates/patches for MS office Outlook. Is there a way to get this information using c# code. We tried WMI code
const string query = "SELECT HotFixID FROM Win32_QuickFixEngineering";
var search = new ManagementObjectSearcher(query);
var collection = search.Get();
foreach (ManagementObject quickFix in collection)
Console.WriteLine(quickFix["HotFixID"].ToString());
This only lists windows updates. Is there a way to list updates for office components?(for windows XP)
I believe you will have to use the registry to get these. The following registry keys should help:
#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
You will have to loop though both the values for the HKLM and HKCU hives in order to be sure you have everything. Then you can filter on DisplayName and Publisher for each entry in order to get only the MS office patches.
Note you could also try to query the Win32_Product class to get products installed by the Windows installer. Although I have often found that it does not list everything you need (however it might be sufficient for your current problem - but I am not in a position to check right now).
I am trying to find a way to get a list of Windows sessions? I need the same information as the one displayed in the Task Manager on the User tab. I need to know if the user is active or not and if s/he is logged on in the Remote Desktop session.
Any idea on how to do that with C# / Windows XP Pro?
As a starting point you can get a list of users logged on by running the command
qwinsta
From the command prompt.
This will give output like
C:\WINDOWS\system32>qwinsta
SESSIONNAME USERNAME ID STATE TYPE DEVICE
>console me 0 Active wdcon
rdp-tcp 65536 Listen rdpwd
and will list any remote sessions.
Use LsaEnumerateLogonSessions via P/Invoke. You'll also need LsaFreeReturnBuffer to cleanup after enumerating.
I believe you'll need to use P/Invoke to retrieve this information.
The relevant APIs are documented in this MSDN page.
Another way is to use the Logonsessions utility from Sysinternals:
http://technet.microsoft.com/en-us/sysinternals/bb896769.aspx
You do not need to use Pinvoke. WMI does it, and well: "select Name, SessionId from Win32_Process" in the root\cimv2 namespace. And, it can be called from a remote machine. Simpler. Add in a where clause in the select to fine tune what you get back.
My code needs to determine how long a particular process has been running. But it continues to fail with an access denied error message on the Process.StartTime request. This is a process running with a User's credentials (ie, not a high-privilege process). There's clearly a security setting or a policy setting, or something that I need to twiddle with to fix this, as I can't believe the StartTime property is in the Framework just so that it can fail 100% of the time.
A Google search indicated that I could resolve this by adding the user whose credentials the querying code is running under to the "Performance Log Users" group. However, no such user group exists on this machine.
I've read something similar to what you said in the past, Lars. Unfortunately, I'm somewhat restricted with what I can do with the machine in question (in other words, I can't go creating user groups willy-nilly: it's a server, not just some random PC).
Thanks for the answers, Will and Lars. Unfortunately, they didn't solve my problem.
Ultimate solution to this is to use WMI:
using System.Management;
String queryString = "select CreationDate from Win32_Process where ProcessId='" + ProcessId + "'";
SelectQuery query = new SelectQuery(queryString);
ManagementScope scope = new System.Management.ManagementScope(#"\\.\root\CIMV2");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection processes = searcher.Get();
//... snip ... logic to figure out which of the processes in the collection is the right one goes here
DateTime startTime = ManagementDateTimeConverter.ToDateTime(processes[0]["CreationDate"].ToString());
TimeSpan uptime = DateTime.Now.Subtract(startTime);
Parts of this were scraped from Code Project:
http://www.codeproject.com/KB/system/win32processusingwmi.aspx
And "Hey, Scripting Guy!":
http://www.microsoft.com/technet/scriptcenter/resources/qanda/jul05/hey0720.mspx
Process of .Net 1.1 uses the Performance Counters to get the information. Either they are disabled or the user does not have administrative rights. Making sure the Performance Counters are enabled and the user is an administrator should make your code work.
Actually the "Performance Counter Users Group" should enough. The group doesn't exist by default. So you should create it yourself.
Process of .Net 2.0 is not depended on the Performance Counters.
See http://weblogs.asp.net/nunitaddin/archive/2004/11/21/267559.aspx
The underlying code needs to be able to call OpenProcess, for which you may require SeDebugPrivilege.
Is the process you're doing the StartTime request on running as a different user to your own process?
OK, sorry that didn't work... I am no expert on ASP.NET impersonation, I tend to use app pools which I don't think you can do on W2K Have you tried writing a tiny little test app which does the same query, and then running that as various users?
I am reluctant to post a chunk of MS framework code here, but you could use either Reflector or this: http://www.codeplex.com/NetMassDownloader to get the source code for the relevant bits of the framework so that you could try implementing various bits to see where it fails.
Can you get any other info about the process without getting Access Denied?
I can enumerate the process (ie, the GetProcessById function works), and we have other code that gets the EXE name and other bits of information.
I will give the test app a try. I'm also going to attempt to use WMI to get this information if I can't get the C# implementation working properly in short order (this is not critical functionality, so I can't spend days on it).