Rally the orphan processes
Some processes start child processes; they are set up that way. Sometimes, when the parent process stops, or it is stopped, some of the child processes remain running. That can be by design, but in some cases the orphan process needs to be terminated as well.
The first step in determining if a running process is an orphan process is to check if it has a parent process. Next, we need to check if the parent process is running or not; this can cause a problem though (more on this later). If the parent process is not running, we got ourselves an orphan process.
First things first, let’s determine if a process has a parent process. It is not easy to achieve this task with the Get-Process cmdlet because the System.Diagnostics.Process object does not have a Parent* property. That is fine—we can take the Windows Management Instrumentation (WMI) route. The Win32_Process class is used to retrieve running processes, we just need to pass it to the Get-WmiObject cmdlet. The objects returned do have a ParentProcessID property, exactly what we are looking for.
Next, we have to resolve the parent process’ state, whether it is running or not. The process of interest’s ParentProcessID value can also help us with this task, but it will not be a straight forward solution. The problem arises if the parent process is not running and its ID, stored in the potentially orphaned process, was assigned to a new process that is not related to the process of interest. To ensure that the process that has the ParentProcessID as its ID is the parent, we will compare its creation time against that of our process of interest. If our process was started—or created—after the possible parent process creation time, the parent is legitimate, it is not a foster parent.
Creating the filter we will apply to all running process sounds complicated but it is easy to understand. Basically, we will ask PowerShell to filter through the piped process object if…
- it has a ParentProcessID but its parent process is not running, or
- its creation time is less than the prospective parent process’ creation time, that is, it started before the substitute parent
Finally, any process object that goes through the filter is piped and bound to the Get-Process cmdlet via its ProcessID value. This way we have the list of orphan System.Diagnostics.Process objects.
Here is the Get-OrphanProcess script:
Now that we have a list of the orphan ones, we can filter further and do with them what we find appropriate. To kill or not to kill, that is the question.
Let me demonstrate. Let’s suppose the Get-OrphanProcess.ps1 script is located in C:\Scripts (it could be anywhere, really, just change the call to the script in the sample code accordingly); we will use it to retrieve an orphan calc process we will start from a non-interactive PowerShell session that will also output its process ID before it exits. Here is the code and the output it returned. Try it!