Problem
Given a process ID & command-line access on a remote Windows host, how can you find its parent's PID?
Solution
Given Marc B's answer, we can use WMIC (Command samples here) and do something like this:
wmic process where (processid=PROCID_HERE) get parentprocessid
C:\> wmic process get processid,parentprocessid,executablepath|find "process id goes here"
In powershell:
PS> wmic process where '(processid=4632)' get 'processid,parentprocessid,executablepath'
ExecutablePath ParentProcessId ProcessId
C:\Program Files\Docker\Docker\Resources\com.docker.db.exe 4488 4632
Based on joslinm's solution in the question, here's a snippet of how to use this in a batch script:
set PID=<this is the child process ID>
for /f "usebackq tokens=2 delims==" %%a in (`wmic process where ^(processid^=%PID%^) get parentprocessid /value`) do (
set PARENT_PID=%%a
)
Or you can do something like this in PowerShell:
Get-CimInstance -className win32_process | where-object {$_.ProcessId -eq processId_goes_here } | select ParentProcessId, Name
as well you can filter by name just substitute $_.ProcessId with $_.Name property
Related
I would like to know how can I adjust the following code, to kill a specific process (there are multiple processes with the same name), based on its Private Working Set memory usage.
Get-Process myPROCESSNAME -ea 0 | where { $_.PM -le 10MB } | foreach {
$Path = $_.Path
if ($Path) {
Stop-Process $_ -Force
}
}
When I open Task Manager, I can clearly see that the processes that I want to automatically kill are using around 4 MB of RAM, while the ones that I don't want to kill use more than 20MB of RAM.
I've fiddled around with a C# console application, but I was not really able to get the same Memory reading, that I can see thru Task Manager.
Then I realised that Task Manager displays the Private Working Set memory (by default), so that's what I need to filter out the bad processes.
Can this be achieved via a batch/PowerShell script?
In batch you can do it as well.:
#echo off
for /f "tokens=2" %%i in ('tasklist /FI "memusage lt 10000" ^|findstr /i "myPROCESSNAME"') do echo taskkill /PID %%i
This will do a tasklist and get processes with memory usage less than 10000kb (10mb).
We then simply use findstr to fiter on your process (myPROCESSNAME) and then kill the process by its PID.
Note I added echo after do. This is for testing purpose so you can at least see what the command will do without actually perfoming the task. Once you are happy with the result, remove echo to actually perform the taskkill command.
I suggest you read up on some help for the above given commands:
for /?
findstr /?
tasklist /?
taskkill /?
If you really do want the Memory (Private Working Set) you could get that information using powershell with Get-WmiObject:
Get-WMIObject -Class Win32_PerfRawData_PerfProc_Process -Property IDProcess,Name,WorkingSetPrivate | `
Where-Object { $_.Name -Eq 'myPROCESSNAME' -And $_.WorkingSetPrivate -Lt 5242880 } | `
ForEach-Object { ( Get-Process -Id $_.IDProcess ).CloseMainWindow() }
Please note that you may need to check what your Name value is, it is usually the name of the executatble without its .exe extension. In this example, I have used 5MB (i.e. 5242880 bytes) as the minimum size to keep open. Additionally, I have for the purpose of this example used the 'friendly' CloseMainWindow instruction for closing the process, depending upon your process, you may need to change that to something more appropriate.
I'm trying to write a cmd that will stop all instances of PostgreSQL on my server
net start | find /I "postgres"
returns all my running instance
I thought this would work
net start | find /I "postgres" | net stop
no luck
I also looked at
for /F "delims=" %A in ('net start | find /I "postgres"') do echo %A
There must be some way to do this
As far as I know the cmd does not provide text trimming function, right? I tried PowerShell with
net start | ? { $_.Contains("postgres")} | % { net stop $_.Trim() }
and works (with UAC of course).
To explain,
? is alias of Where-Object, whilst
% is alias of ForEach-Object, and
$_ is to mention piped element. In this case, every element from traversing array by ForEach-Object(%) is piped into inner expression.
These aliases and commands are available for a help text by Get-Help {func} or man {func}.
wmic service where name='lanmanserver' call stopservice
does lanmanserver, adjust to your program.
wmic /?
wmic service get /?
wmic service call /?
Or same objects in vbscript.
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Service")
For Each objItem in colItems
'msgbox objItem.caption
If LCase(objItem.name) = "lanmanserver" then msgbox objItem.stopservice
Next
I have a text file of the format:
computername1 uninstallkey1
computername2 uninstallkey2
...
computername200 uninstallkey200
I am trying to write a startup script (batch file or powershell?) that generates a msiexec command that looks up and implants the correct key for each computer it executes on e.g.:
msiexec /x install.msi key=uninstallkey
If I have not made anything clear, please ask and any help is much appreciated!
#ECHO OFF
SETLOCAL
FOR /f "tokens=1*" %%i IN (yourtextfilename.txt) DO (
IF /i %%i==%COMPUTERNAME% ECHO MSIEXEC /x install.msi key=%%j
)
This should do as you require - yourtextfilename.txt contains the data, presumably on a shared drive; finds the line where the computername in column 1 is the same as the computername returned by %computername% in the target computer's environment.
(all case-insensitive EXCEPT %%i and %%j which must match and be the same case)
Command simply ECHOed - remove the ECHO keyword after verification to activate.
In PowerShell,
$comp = Import-CSV -Delimiter " " -Path C:\comp.txt -Header computername,uninstallkey
$comp | ForEach-Object {
if ($env:COMPUTERNAME -eq $_.Computername) {
Start-Process -FilePath "msiexec.exe" -ArgumentList "/x install.msi key=$_.uninstallkey"
}
}
How to kill a process by name and orginiated from a particular path using taskkill?
taskkill /F /IM
certainly it cant differentiate 2 process started from two different locations C:\Dir1 and C:\Dir2
Does tasklist has any switch to get the path name
taskkill cannot do it. But you could use PowerShell if it's an option:
(Get-WmiObject Win32_Process | Where-Object { $_.Path.StartsWith('C:\Dir1') }).Terminate()
Use the following command (it works even without powershell):
wmic process where ExecutablePath='C:\\Dir1\\image.exe' delete
NOTE: ExecutablePath is accessable for all processes only if you run wmic as administrator on Windows 8
Based on Joey's answer:
wmic Path win32_process Where "CommandLine Like '%C:\\Dir1\\image.exe%'" Call Terminate
This way I avoid NullReferenceException when Path is null (don't know why) and does not need PowerShell.
Ref: https://superuser.com/questions/52159/kill-a-process-with-a-specific-command-line-from-command-line
Warning
It is dangerous if there are other processes running with the commandline contains that image path. For example:
> start cmd /k "C:\windows\system32\notepad.exe"
> wmic Path win32_process where "CommandLine Like '%C:\\Windows\\system32\\notepad.exe%'" get caption,processid,executablePath,commandline
Caption CommandLine ExecutablePath ProcessId
cmd.exe cmd /k "C:\windows\system32\notepad.exe" C:\WINDOWS\system32\cmd.exe 11384
notepad.exe C:\windows\system32\notepad.exe C:\windows\system32\notepad.exe 9684
So... What if we use "C:\Dir1\image.exe%" instead of "%C:\Dir1\image.exe%"?
If we launched this program from Explorer, its commandline may be quoted. If we ignore it, there will be no matches:
> wmic Path win32_process where "CommandLine Like '%C:\\Windows\\system32\\notepad.exe%'" get caption,processid,executablePath,commandline
Caption CommandLine ExecutablePath ProcessId
notepad.exe "C:\WINDOWS\system32\notepad.exe" C:\WINDOWS\system32\notepad.exe 108
> wmic Path win32_process where "CommandLine Like 'C:\\Windows\\system32\\notepad.exe%'" get caption,processid,executablePath,commandline
No Instance(s) Available.
Therefore, it is recommended to use "ExecutablePath" like l0pan's answer.
Your case seems to be when you have custom services with same process name installed on the machine from different paths. If this is indeed the scenario, you probably have different Service Names which can be used as an additional filter.
See Syntax:
taskkill /S {REPLACE_WITH_SERVER_IP_OR_NAME} /F /FI "IMAGENAME eq {REPLACE_WITH_PROCESS_NAME}" /FI "SERVICES eq {REPLACE_WITH_SERVICENAME}"
See Example:
taskkill /S 10.10.1.1 /F /FI "IMAGENAME eq tomcat7.exe" /FI "SERVICES eq tomcatServiceEngine"
For list of all available filters, please visit taskkill command
You can only find your processes' path unless you are running powershell with administrator privilege.
32-bit PowerShell cannot find the path of 64-bit process via Get-Process, so I suggest you use WMI or CIM. Some references that may be useful:
Process Class (System.Diagnostics) | Microsoft Docs § Remarks
c# - How to get the full path of running process? - Stack Overflow
c - Get command line string of 64-bit process from 32-bit process - Stack Overflow
PowerShell way. Based on Joey's answer and user's comment.
Assuming that the path of the program is C:\Dir1\file.exe. If multiple instances of the program are running, you should use the following command:
Get-WmiObject Win32_Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" } |
ForEach-Object { $_.Terminate() }
Otherwise, Powershell will report an error:
PS > (Get-WmiObject Win32_Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" }).Terminate()
Method invocation failed because [System.Object[]] doesn't contain a method named 'Terminate'.
In addition, the above command also avoids the error when no matching process is found (e.g., the Path of no process is equal to C:\Dir1\file.exe):
PS > (Get-WmiObject Win32_Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" }).Terminate()
You cannot call a method on a null-valued expression.
If you don't like WMI:
Get-Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" } |
ForEach-Object { Stop-Process -Id $_.Id }
I noticed that both Win32_Process.Terminate() and Stop-Process are used to forcibly terminate the process, so the process may not be able to perform any cleanup work.
Tested in Powershell 2.0 on Windows 7 (6.1.7600.0).
If you do like WMI and you are on Windows 6.2 (Windows server 2012 and Windows 8) and later, you should use Get-CimInstance instead of Get-WmiObject in PowerShell 3 and later (Introduction to CIM Cmdlets | PowerShell Team):
Get-CimInstance Win32_Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" } |
Invoke-CimMethod -MethodName "Terminate"
Or, more CIM'y:
Get-CimInstance CIM_Process |
Where-Object { $_.Path -eq "C:\Dir1\file.exe" } |
Invoke-CimMethod -MethodName "Terminate"
Here, you may want to know why Invoke-CimMethod:
WMI CIM-plified Part 5: WSMAN Protocol -- Microsoft Certified Professional Magazine Online
Hey, Dude! Where Are My Methods? | Scripting Blog
I’m afraid you can’t do that anymore | Richard Siddaway's Blog
And, why "CIM":
Should I use CIM or WMI with Windows PowerShell? | Scripting Blog
CIM vs. WMI CmdLets – The top reasons I changed over –
GivingSomethingBack
Get-CIMInstance Vs Get-WMIObject: What’s The Difference?
I didn't test it on Windows 6.2, but Windows 10 (10.0.19041.0).
I need to kill a windows process (java.exe). I'm currently using:
taskkill.exe /F /IM java.exe
I need to use the /F option since is a critical process,but in this way I get a return code 1 instead I need a return code 0 (returned when I don't use /F for killing other not critical processes)
how could I fix this problem?
Many thanks
You can try with :
TASKKILL /F /IM "notepad.exe"
You can know more here. Visit this blog too.
Why don't you use PowerShell?
Stop-Process -Name java.exe
From the old command prompt:
powershell -Command "Stop-Process -Name java.exe"
I am using following command on Windows Server 2008R2
Taskkill /IM B2B_Crawler_V2.exe /F
Refer Taskkill and Killing a process in Batch and reporting on success
Execute this in CMD
Get the list of open processes
netstat -a -o -n
And then kill the process on that port with the following command
taskkill /F /PID <pid>