taskkill to differentiate 2 images by path - windows

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

Related

Kill a process with shell/batch script based on Private Working Set Memory value

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.

Use BAT file to check if PSSnapin is registered

I've hit a little bit of a brick wall here. I have written a rather large PS script that requires the SQLServerProviderSnapin100 and this all works happily.
To run the script I have written a BAT file for the users to run so that they won't have to fiddle around with execuptionpolicy, so it sets it unrestricted calls the script and once the script completes it sets the executionpolicy back to restricted.
The problem I have is that I need the BAT file to detect if the user has the SqlServerProvider100 snapin registered to the 32Bit Powershell or the 64Bit powershell.
I know I could run something like this in powershell
$prov = get-pssnapin -registered | where-object{$_.Name -eq "Sqlserverprovidersnapin100"}
if($prov -eq $null){ <call powershell x86>}else{<call powershell 64Bit>}
But how do I do this in the BAT, or is what I am trying to do even possible?
I hope I making sense to someone who can help me get over this bump! :)
Try these 2 commands:
C:\Windows\Syswow64\WindowsPowerShell\v1.0\powershell.exe "if(Get-PSSnapin -registered "SqlServerCmdletSnapin100" -ea 0){ write-host "sql snapin present in 32bit shell"}"
for 64bit:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe "if(Get-PSSnapin -registered "SqlServerCmdletSnapin100" -ea 0){ write-host "sql snapin present in 64bit shell"}"
They will return a pretty message if sql snapin is present.
Ok worked it out!
FOR /F "usebackq delims=" %%i IN (`powershell -command "get-pssnapin -registered | where-object { $_.Name -eq 'sqlserverprovidersnapin100' }"`) DO ( set snapin=%%i )
REM if /i {%snapin:~0,4%}=={%test:~0,4%} (goto :there)
if not defined snapin goto :notthere
(goto :there)
:there
echo %snapin%
pause
exit
:notthere
echo "Not loaded!"
pause
exit
This exercise has taught me two things now: apparently when I was testing against NULL within a BAT, if the value was NULL it would remove the variable and secondly how to pass a PS variable back to BAT.

PowerShell in command prompt issue, 'Format-Table' is not recognized as an internal or external command, operable program or batch file

I am executing powershell script in cmd.
First i write command
C:\Windows\system32>start powershell.exe Set-ExecutionPolicy RemoteSigned
it works successfully
than for running script i write command
C:\Windows\system32>start powershell.exe C:\\Get-NetworkStatistics.ps1
It also works successfully
the problem is when i try to run the function
C:\Windows\system32>start powershell.exe Get-NetworkStatistics -computername Gbsi1 | Format-Table -autosize
it gives error that "'Format-Table' is not recognized as an internal or external command,
operable program or batch file."
here is the screenshot for it.
It runs successfully in powershell but no in cmd. Is there any issue with pipe | which i put before Format-Table
As your it is, the pipe is interpreted by CMD not powershell.
Thus, CMD will try to execute a command named Format-Table, which does not exist (outside powershell).
You can escape it using ^:
start powershell.exe Get-NetworkStatistics -computername Gbsi1 ^| Format-Table -autosize
Or by quoting the complete command line
start powershell.exe "Get-NetworkStatistics -computername Gbsi1 | Format-Table -autosize"
Note that your invocation is errnous anyhow, you need to provide the -Command option to powershell, like so:
start powershell.exe -Command "Get-NetworkStatistics -computername Gbsi1 | Format-Table -autosize"
Finally, do you really want to use start? It will open a new window, that will close immediately after the command is through. You could also use:
powershell.exe -Command "Get-NetworkStatistics -computername Gbsi1 | Format-Table -autosize"

How can I programatically check that I am running Windows 8.1?

How can I programatically check that I am running Windows 8.1 using cmd.exe or PowerShell?
Powershell
get-wmiobject win32_operatingsystem will return several properties you can use to check the OS.
get-wmiobject win32_operatingsystem|select-object name,caption,buildnumber,version|format-list
name : Microsoft Windows 8.1 Enterprise|C:\WINDOWS|\Device\Harddisk0\Partition2
caption : Microsoft Windows 8.1 Enterprise
buildnumber : 9600
version : 6.3.9600
CMD
wmic os get caption /value|find "="
to put it into a variable:
for /f %%i in ('wmic os get caption /value^|find "="') do set version=%%i
Another method using PowerShell:
(Get-Command -Name $env:windir\system32\ntoskrnl.exe).FileVersionInfo.FileVersion -match '6.3.9600';
This command returns $true or $false. To be honest, alroc's is the ideal solution, in my opinion. This is just an alternative.

Finding parent process ID on Windows

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

Resources