c# ManagementObjectSearcher used for finding process (and its description) with PID - c#

Im working on a program which should list me processes and when i click on certain process it should give me its description.
My idea(Actually i modified something similar what i found on web) was to use ManagementObjectSearcher with sql statement ("Select * From Win32_Process WHERE ProcessID="+a); where "a" is string variable which contains process ID.For some processes its working(chrome,calculator for example) and for some it doesnt(svchost,tiltweelmouse and so on).
private void Lista_procesa_prikaz_MouseClick(object sender, MouseEventArgs e)
{
string a = Lista_procesa_prikaz.Items[Lista_procesa_prikaz.FocusedItem.Index].SubItems[1].Text;
var searcher = new ManagementObjectSearcher("Select * From Win32_Process WHERE ProcessID="+a);
var proces = searcher.Get();
foreach (var process in proces)
{
var processName = process["Name"];
var processPath = process["ExecutablePath"];
if (processPath != null)
{
var fileVersionInfo = FileVersionInfo.GetVersionInfo(processPath.ToString());
var processDescription = fileVersionInfo.FileDescription;
Description_textbox.Text = processDescription.ToString();
}
}
}
IF someone could spot mistake here i would be really happy,
Any help is appreciated
Thank you
EDIT: Partially solved problem,if anyone even cares,platform need to be set to x64(in my case).Go to Project,yourProjectName properties,build,platform target:x64

I don't know if it must be from ManagementObjectSearcher but may I suggest a managed class that gets the same data.
var procs = System.Diagnostics.Process.GetProcesses()
.Where(x => x.Id == 3116);
foreach(var p in procs)
Console.WriteLine(p.ProcessName + p.Id);
Attempting to read the path to the using both approaches will throw if you don't have elevated privileges. As for getting those privileges, consider using a manifest for that.

Related

How can I find the users which a shared folder, shared to programmatically? [duplicate]

Is there a way through the .net framework to determine if a folder is shared or not?
Neither Diretory, DirectoryInfo or FileAttributes seem to have any corresponding field.
One thing I forgot to mention was that I want to be checking for network shares. But I'll investigate the WMI stuff.
You can get a list of all the shared folders using the WMI Win32_Share and see if the folder you're looking for is between them. Here's a snippet that might help you with this:
public static List<string> GetSharedFolders()
{
List<string> sharedFolders = new List<string>();
// Object to query the WMI Win32_Share API for shared files...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from win32_share");
ManagementBaseObject outParams;
ManagementClass mc = new ManagementClass("Win32_Share"); //for local shares
foreach (ManagementObject share in searcher.Get()){
string type = share["Type"].ToString();
if (type == "0") // 0 = DiskDrive (1 = Print Queue, 2 = Device, 3 = IPH)
{
string name = share["Name"].ToString(); //getting share name
string path = share["Path"].ToString(); //getting share path
string caption = share["Caption"].ToString(); //getting share description
sharedFolders.Add(path);
}
}
return sharedFolders;
}
Please note that I brutally copy-pasted from this link on bytes
You can use WMI Win32_Share.
Take a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id=408923
Shows a sample for querying, creating and deleting shared folders.
One more way to skin this cat is to use powershell (if you have it installed) to invoke the wmi call, include a reference to System.Management.Automation, it will most likley be in \program files\reference assemblies\microsoft\windowspowershell
private void button1_Click(object sender, EventArgs e)
{
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline pl = rs.CreatePipeline();
pl.Commands.AddScript("get-wmiobject win32_share");
StringBuilder sb = new StringBuilder();
Collection<PSObject> list = pl.Invoke();
rs.Close();
foreach (PSObject obj in list)
{
string name = obj.Properties["Name"].Value as string;
string path = obj.Properties["Path"].Value as string;
string desc = obj.Properties["Description"].Value as string;
sb.AppendLine(string.Format("{0}{1}{2}",name, path, desc));
}
// do something with the results...
}
Try using WMI and doing a SELECT * FROM Win32_ShareToDirectory query.

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

How do you get the UserName of the owner of a process?

I'm trying to get a list of processes currently owned by the current user (Environment.UserName). Unfortunately, the Process class doesn't have any way of getting the UserName of the user owning a process.
How do you get the UserName of the user which is the owner of a process using the Process class so I can compare it to Environment.UserName?
If your solution requires a pinvoke, please provide a code example.
Thanks, your answers put me on the proper path. For those who needs a code sample:
public class App
{
public static void Main(string[] Args)
{
Management.ManagementObjectSearcher Processes = new Management.ManagementObjectSearcher("SELECT * FROM Win32_Process");
foreach (Management.ManagementObject Process in Processes.Get()) {
if (Process["ExecutablePath"] != null) {
string ExecutablePath = Process["ExecutablePath"].ToString();
string[] OwnerInfo = new string[2];
Process.InvokeMethod("GetOwner", (object[]) OwnerInfo);
Console.WriteLine(string.Format("{0}: {1}", IO.Path.GetFileName(ExecutablePath), OwnerInfo[0]));
}
}
Console.ReadLine();
}
}
The CodeProject article How To Get Process Owner ID and Current User SID by Warlib describes how to do this using both WMI and using the Win32 API via PInvoke.
The WMI code is much simpler but is slower to execute. Your question doesn't indicate which would be more appropriate for your scenario.
You will have a hard time getting the username without being an administrator on the computer.
None of the methods with WMI, through the OpenProcess or using the WTSEnumerateProcesses will give you the username unless you are an administrator. Trying to enable SeDebugPrivilege etc does not work either. I have still to see a code that works without being the admin.
If anyone know how to get this WITHOUT being an admin on the machine it is being run, please write how to do it, as I have not found out how to enable that level of access to a service user.
You might look at using System.Management (WMI). With that you can query the Win32_Process tree.
here is the MS link labelled "GetOwner Method of the Win32_Process Class"
Props to Andrew Moore for his answer, I'm merely formatting it because it didn't compile in C# 3.5.
private string GetUserName(string procName)
{
string query = "SELECT * FROM Win32_Process WHERE Name = \'" + procName + "\'";
var procs = new System.Management.ManagementObjectSearcher(query);
foreach (System.Management.ManagementObject p in procs.Get())
{
var path = p["ExecutablePath"];
if (path != null)
{
string executablePath = path.ToString();
string[] ownerInfo = new string[2];
p.InvokeMethod("GetOwner", (object[])ownerInfo);
return ownerInfo[0];
}
}
return null;
}
You'll need to add a reference to System.Management.dll for this to work.
Here's what I ended up using. It works in .NET 3.5:
using System.Linq;
using System.Management;
class Program
{
/// <summary>
/// Adapted from https://www.codeproject.com/Articles/14828/How-To-Get-Process-Owner-ID-and-Current-User-SID
/// </summary>
public static void GetProcessOwnerByProcessId(int processId, out string user, out string domain)
{
user = "???";
domain = "???";
var sq = new ObjectQuery("Select * from Win32_Process Where ProcessID = '" + processId + "'");
var searcher = new ManagementObjectSearcher(sq);
if (searcher.Get().Count != 1)
{
return;
}
var process = searcher.Get().Cast<ManagementObject>().First();
var ownerInfo = new string[2];
process.InvokeMethod("GetOwner", ownerInfo);
if (user != null)
{
user = ownerInfo[0];
}
if (domain != null)
{
domain = ownerInfo[1];
}
}
public static void Main()
{
var processId = System.Diagnostics.Process.GetCurrentProcess().Id;
string user;
string domain;
GetProcessOwnerByProcessId(processId, out user, out domain);
System.Console.WriteLine(domain + "\\" + user);
}
}

Determining if a folder is shared in .NET

Is there a way through the .net framework to determine if a folder is shared or not?
Neither Diretory, DirectoryInfo or FileAttributes seem to have any corresponding field.
One thing I forgot to mention was that I want to be checking for network shares. But I'll investigate the WMI stuff.
You can get a list of all the shared folders using the WMI Win32_Share and see if the folder you're looking for is between them. Here's a snippet that might help you with this:
public static List<string> GetSharedFolders()
{
List<string> sharedFolders = new List<string>();
// Object to query the WMI Win32_Share API for shared files...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from win32_share");
ManagementBaseObject outParams;
ManagementClass mc = new ManagementClass("Win32_Share"); //for local shares
foreach (ManagementObject share in searcher.Get()){
string type = share["Type"].ToString();
if (type == "0") // 0 = DiskDrive (1 = Print Queue, 2 = Device, 3 = IPH)
{
string name = share["Name"].ToString(); //getting share name
string path = share["Path"].ToString(); //getting share path
string caption = share["Caption"].ToString(); //getting share description
sharedFolders.Add(path);
}
}
return sharedFolders;
}
Please note that I brutally copy-pasted from this link on bytes
You can use WMI Win32_Share.
Take a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id=408923
Shows a sample for querying, creating and deleting shared folders.
One more way to skin this cat is to use powershell (if you have it installed) to invoke the wmi call, include a reference to System.Management.Automation, it will most likley be in \program files\reference assemblies\microsoft\windowspowershell
private void button1_Click(object sender, EventArgs e)
{
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
Pipeline pl = rs.CreatePipeline();
pl.Commands.AddScript("get-wmiobject win32_share");
StringBuilder sb = new StringBuilder();
Collection<PSObject> list = pl.Invoke();
rs.Close();
foreach (PSObject obj in list)
{
string name = obj.Properties["Name"].Value as string;
string path = obj.Properties["Path"].Value as string;
string desc = obj.Properties["Description"].Value as string;
sb.AppendLine(string.Format("{0}{1}{2}",name, path, desc));
}
// do something with the results...
}
Try using WMI and doing a SELECT * FROM Win32_ShareToDirectory query.

Categories