Introduction
Sometimes we need to kill a process programatically. For example, in above screenshot, we need to kill the process "EXCEL.EXE", which belongs to user "appdev01", but not to kill other processes which belongs to other users. This article talk about how to use C# to get process by name, and then filter it by user name and process start time.
Background
The background that I write this article has something to do with one of the projects that I am doing. In my this project, I created a web page, allowing internal users to upload a contract in a pre-defined format of EXCEL file. And then my program will open the EXCEL file, and load the contract to our several systems.
You know that after finish everything, my program needs to close the EXCEL file, release all resources. I used methods to release the resources, and it can work, but cannot work 100%. That means sometimes work, sometimes not.
wb.Close(false, NewFileNameFull, Missing.Value);
ap.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
System.Runtime.InteropServices.Marshal.ReleaseComObject(ap);
I also tried many other methods, they also work but none of them can work every time. In internet, many people discuss this issue, but there is no complete solution. So we need to log on the server, launch task manager, and kill the process manually.
The best solution should be use C# code, to kill the process automatically.
Using the Code
At here, I write a class ProcessHelper
, with a public method KillProcessByNameAndUser
. It is easy to use. Below is an example code to use it.
ProcessHelper.ProcessHelper ph = new ProcessHelper.ProcessHelper();
ph.KillProcessByNameAndUser("EXCEL", "myPCName\appdev01", 12);
At here, it finds the "EXCEL" processes, which started 12 hours ago and belongs to a local user "appdev01" in the machine "myPCName", and kill them.
Below is the source code of the class
using System;
using System.Management;
using System.Diagnostics;
namespace ProcessHelper
{
public class ProcessHelper
{
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 argList[1] + "\\" + argList[0]; }
}
return "NO OWNER";
}
public void KillProcessByNameAndUser(string ProcessName, string ProcessUserName, int HasStartedForHours)
{
Process[] foundProcesses = Process.GetProcessesByName(ProcessName);
Console.WriteLine(foundProcesses.Length.ToString() + " processes found.");
string strMessage = string.Empty;
foreach (Process p in foundProcesses)
{
string UserName = GetProcessOwner(p.Id);
strMessage = string.Format("Process Name: {0} | Process ID: {1} | User Name : {2} | StartTime {3}",
p.ProcessName, p.Id.ToString(), UserName, p.StartTime.ToString());
bool TimeExpired = (p.StartTime.AddHours(HasStartedForHours) < DateTime.Now) || HasStartedForHours == 0;
bool PrcoessUserName_Is_Matched = UserName.Equals(ProcessUserName);
if ((ProcessUserName.ToLower() == "all" && TimeExpired) ||
PrcoessUserName_Is_Matched && TimeExpired)
{
p.Kill();
}
}
}
}
}
Note: If you use the code and face a compile error for Using System.Management;
you need to add reference to the System.Management
object.
Points of Interest
Windows has a built-in command "TASKKILL" to kill a process. For example, below command can also kill the EXCEL process which belongs to user appdev01.
TASKKILL /F /FI "USERNAME eq APPDEV01" /IM EXCEL.EXE
But our class is more flexible, it can filter by process running time.
And we can also add logic to filter the process's main window title by the property MainWindowTitle
.
History
This is the initial version of the class ProcessHelper
. In the future, we might add more logics into this function, and I will keep this post updated.