How to get process owner name in 64 bit OS in C# - c#

How do I determine the owner of a process in C#?
public string GetProcessOwner(int processId)
{
string query = "Select * From Win32_Process Where ProcessID = " + processId;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
string[] argList = new string[] { string.Empty, string.Empty };
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
{
// return DOMAIN\user
return argList[1] + "\\" + argList[0];
}
}
return "NO OWNER";
}
I detailed studied and implemented the code as given above. This code works fine but only gets the owner names of those processes which are 32 bits. The method return "no owner" for 64 bits processes.
Please help me, how I can get the processes owner names for both 32 bit processes and 64 bit processes.

No, that code works "fine". It also works when your code is 32bit but the target process is 64bit, so no issue here as well.
Possible reasons why you could get "NO OWNER":
You are trying to get the owner for which you have no permission (e.g. you are running as non-privileged user, but trying to get the owner of a privileged one).
You are trying to get the owner of a pseudo process (e.g. "System", with PID 4, or "System Idle Process" with PID 0).
BTW, also services have owners (regarding #weismat comment).

Related

C# get windows drive hardware caption via registry

I need to retrieve the name of drive where Windows is installed.
Best way I found to do it is via registry, since WMI is very slow for this specific query.
string diskdrive = Registry.GetValue(#"HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0", "Identifier", null);
Which returns : INTEL SSDSCKKF512H6 LBF
While this works perfect form my system, "Target Id" seems to have different digit identifier for other system. how would I go about to detect the specific target ID (maybe detect it by using part of the registry subkey string, somehow).
Not even sure this will do the job for other type of disks (Nvme or IDE).
If there is a better way to do this without WMi query.
Thanks in advance
Found something from CMD:
REG QUERY "HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0" /v Identifier /s
This searches for the registry key named Identifier within Target Id 0
Okay, then try:
This optimized version executes in ~65 ms on my system. That should be good enough.
//ManagementObject sys = new ManagementObject("Win32_OperatingSystem=#");
//string systemDrive = sys["SystemDrive"].ToString();
//Console.WriteLine("System Drive is {0}", systemDrive);
string strQuery = "ASSOCIATORS OF {Win32_LogicalDisk.DeviceID=\""
+ System.IO.Path.GetPathRoot(Environment.SystemDirectory).Replace("\\", "")
+ "\"} WHERE AssocClass = Win32_LogicalDiskToPartition";
RelatedObjectQuery relquery = new RelatedObjectQuery(strQuery);
ManagementObjectSearcher search = new ManagementObjectSearcher(relquery);
UInt32 ndx = 0;
foreach (var diskPartition in search.Get())
{
ndx = (uint)diskPartition["DiskIndex"];
Console.WriteLine("Disk Index of System Drive is {0}, Disk Partition is {1}", ndx, diskPartition["DeviceID"]);
}
SelectQuery diskQuery = new SelectQuery(string.Format("SELECT * FROM Win32_DiskDrive WHERE Index={0}", ndx));
ManagementObjectSearcher diskSearch = new ManagementObjectSearcher(diskQuery);
foreach (var disk in diskSearch.Get())
{
Console.WriteLine("Caption is {0}", disk["Caption"]);
Console.WriteLine("Serial Number is {0}", disk["SerialNumber"]);
Console.WriteLine("Model is {0}", disk["Model"]);
Console.WriteLine("InterfaceType is {0}", disk["InterfaceType"]);
}

Unable to format a drive (Unknown Error)

I'm using the WMI Volume ManagementObject to format a drive (Docs). If I try to do this from a non-elevated application, I get a result code of 3 (Access denied) which makes sense. Running the application as an administrator means I get a return code of 18 (Unknown Error).
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
String.Format("select * from Win32_Volume WHERE DriveLetter = \"{0}\"", Drive));
foreach (ManagementObject vi in searcher.Get()) {
FormatResult result = (FormatResult)(int)(uint)vi.InvokeMethod("Format", new object[] { FileSystem, QuickFormat, ClusterSize, Label, EnableCompression });
if (result != FormatResult.Success) {
throw new FormatFailedException(String.Format("{0} (Error code {1})", result.ToString(), (int)result));
}
}
Parameters:
FileSystem: "NTFS"
Quick: false
ClusterSize: 4096
Label: "Test"
EnableCompression: false
I can format the drive with the above parameters through Explorer without any problems. How can I diagnose the issue and find out what's going on?
Since there seems to be some confusion, FormatResult is just an enum to simplify handling return codes...
enum FormatResult {
Success = 0,
UnsupportedFileSystem = 1,
IncompatibleMediaInDrive = 2,
AccessDenied = 3,
CallCanceled = 4,
...
UnknownError = 18
}
To give an idea of what I'm doing:
Since the docs mention that this method is usually called asynchronously, I've tried switching to an Async call with the same result (code available upon request). I've also tried various combinations of FileSystem (NTFS/FAT32), ClusterSize (including 0 to let the system pick a default), and Quick/Full formats. All give the same result of 18.
What am I missing?

Getting CPU ID on virtual machine

I am trying to use this code:
public string GetCPUId()
{
string cpuInfo = String.Empty;
string temp = String.Empty;
ManagementClass mc = new ManagementClass("Win32_Processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (cpuInfo == String.Empty)
{
cpuInfo = mo.Properties["ProcessorId"].Value.ToString();
}
}
return cpuInfo;
}
To get a hw uid on a XP virtual machine (virtualbox), but I am only getting a messagebox that says:
Object reference not set to an instance of an object.
Is it because it's a virtual machine or what?
Yes, it is because you are running a virtual machine. mo.Properties["ProcessorId"] will return null. See the answers here.
I've just found a faster solution here :
http://www.dotnetspark.com/kb/24-get-processor-id-using-c-sharp.aspx
it works faster than yours.and IT WORKS IN MY VIRTUAL WINDOWS(using VMware Workstation 7.0.0 with WINDOWS XP installed virtually) as both codes use the same library yours should work as well! try including dll file in project output it MIGHT Help.
UPDATE (2022): Since the linked page is not working any more I am pasting the code :
public static string GetProcessorID()
{
string sProcessorID = "";
string sQuery = "SELECT ProcessorId FROM Win32_Processor";
ManagementObjectSearcher oManagementObjectSearcher = new ManagementObjectSearcher(sQuery);
ManagementObjectCollection oCollection = oManagementObjectSearcher.Get();
foreach (ManagementObject oManagementObject in oCollection)
{
sProcessorID = (string)oManagementObject["ProcessorId"];
}
return (sProcessorID);
}
That should work just fine on a VM. The CPU ID presented by the virtual CPU may or may not match the physical CPU, though.

C# List currently open files and programs

Is there a way I can get a list of all open applications and a list of all open files? For the files I only need the files that I opened (documents etc) not OS's open system files. The same for the applications (only browsers, document processors etc).
I already tried various functions from the Windows API like EnumWindows but I couldn't get what I wanted.
An example of what my ultimate goal would be, is to have lists like this:
Applications
Microsoft Word,
Notepad,
Mozilla Firefox
Files
foo.txt,
foo.mp3,
foo.doc
What I need is just the names, I don't need handles etc (even though I'm sure I'll have to use them to get what I want)
You can get a list of running processes with their information
public static string ListAllProcesses()
{
StringBuilder sb = new StringBuilder();
// list out all processes and write them into a stringbuilder
ManagementClass MgmtClass = new ManagementClass("Win32_Process");
foreach (ManagementObject mo in MgmtClass.GetInstances())
{
sb.Append("Name:\t" + mo["Name"] + Environment.NewLine);
sb.Append("ID:\t" + mo["ProcessId"] + Environment.NewLine);
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
The only method (That I know) to see if the process is opened by user or system is to check it's owner. If it's system, then it's not run by user:
//You will need to reference System.Management.Dll and use System.Management namespace
public string GetProcessOwner(string processName)
{
string query = "Select * from Win32_Process Where Name = \"" + processName + "\"";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
string[] argList = new string[] { string.Empty, string.Empty };
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
{
// return DOMAIN\user
string owner = argList[1] + "\\" + argList[0];
return owner;
}
}
return "NO OWNER";
}
For the list of opened files, It is possible to do using Managed Code which is somehow hard. Here is an example on codeproject demonstrating the same matter
You can have a list of running processes with Process.GetProcesses(): http://msdn.microsoft.com/en-us/library/1f3ys1f9.aspx
But you can have the file they have open if they exposes some automation interface you know.

How to kill specific process running under specific user account

How to kill specific process running under specific user account. using C#?
Thanks,
var processes = from p in Process.GetProcessesByName(nameOfTheProcess)
where p.StartInfo.UserName == nameOfTheUser
select p;
foreach(Process p in processes) p.Kill();
EDIT: as Fredrik pointed out, the UserName property is not set for processes obtained by GetProcesses. Here's a modified version that uses WMI to get the username (GetProcessOwner method found here) :
static void KillProcessByNameAndUserName(string processName, string userName)
{
var processes = from p in Process.GetProcessesByName(processName)
where GetProcessOwner(p.Id) == userName
select p;
foreach(Process p in processes) p.Kill();
}
static string GetProcessOwner(int processId)
{
string query = “Select * From Win32_Process Where ProcessID = “ + processId;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
string[] argList = new string[] { string.Empty };
int returnVal = Convert.ToInt32(obj.InvokeMethod(“GetOwner”, argList));
if (returnVal == 0)
return argList[0];
}
return “NO OWNER”;
}
In order to get the username, you have to grab the security context of the process from the Win32 API.
Call the OpenProcessToken() function via P/Invoke using the process handle found in the .Net Process class from the code you already have above. You will obtain a structure that contains a SID for the owner of the process. Be prepared for errors such as Access Denied, since you may not have access rights to obtain this information for all processes, such as those that are not yours. From there, you have to convert the SID to a name. There are a few ways to do this, but LookupAccountSid() function (again, via P/Invoke) will get the username for you.
In framework 2.0, a bunch of stuff was added to help with dealing with security descriptors (System.Security.AccessControl namespace), however, I don't see anything that will help you in dealing with the P/Invoke complexities there.
See pinvoke.net for information on using the Win32 API from C#.

Categories