I need to find the PID of a program that I am starting via the shell. The Shell is mode 1 and I am using a thread to control sending the commands and receiving the data back from the shell. The program I need to close is plink. The problem is I already have one instance of plink running that I need to keep open so I can’t just do this: Shell.Execute("taskkill /F /IM plink*") otherwise it would close both instances.
I found that I could rename the plink file itself to something else and close that instead and it works but I really don’t want to have to include two versions of the same file with my program. Or rename the file that’s probably some kind of no no licensing issue anyway.
This is what I would like to do (this is within a thread):
dim xShell As New Shell
xShell.Mode = 1
xShell.Execute(strConnect) //Starts the file instance that I need to close later
me.Sleep(10000) //Gives time to connect
xShell.Write(strCommand) //Executes a command I need
me.Sleep(5000) //Give time for result back
strResult = xShell.Result
//FIND THE PID of the process started with xShell.Execute(strConnect)
xShell.Execute("taskkill /F /PID <pid>") //Close the process
xShell.Close
If there isn’t a way to do this is there a way to assign a different name to the process when you open it? Thanks for any help.
One way that was thrown about in the past was to grab a process list immediately before starting the shell and then again immediately after and comparing them. The new plink process is the one you want to kill later.
The issue with “read the process list, start your shell, read it again” is there is the very real possibility you end up with a race condition where several start “all at once” and you get several pids for “the one you just started”
wmic should be able to avoid this and get JUST the pid for the process started
its just not really clear to use
Lots of boards have questions about using it to start a process, set the working directory when you do this etc
[quote=272558:@Marco Hof]I think I’m missing something.
Doesn’t xShell.PID return the PID?
(and about the sleeps, why not use the DataAvailable event and follow up there?)[/quote]
I’m not looking for the PID of the shell I’m looking for the PID of a program started in the shell.
I probably will use the DataAvailable event in the final code this is just code I wrote for testing.
Well, not sure if it helps but (at least in OSX and Linux) if you kill a parent, the childs also go away.
But I understand now. I didn’t see at first that your shell is starting other shells.
A couple of methods I’ve used (but you still have to parse the stuff). Both have filtering options you can use. I think there was a WFS method or Win32 declare that gets the processID of the launched process, but can’t seem to find it. There are a couple of Win32 gurus around so I hope you get more answers.
This works, my app receives the PID from the shell BUT it launches a second command window outside of my app with the plink session so I can’t send any commands via plink. Any ideas on how to get around this? Thanks!
So I finally had to give up on WMIC PROCESS CALL CREATE because even though it works to provide me the PID of the plink instance as it’s opened it opens plink in a new command window outside of my application when the WMIC command is used from a shell in my application. I’m sure there is probably some clever way using a good amount of VB code to use the PID of the shell and send commands to it outside of the application but using the plink session outside of the shell in my application is just not a solution for me. What a shame.
I ended up using a different WMIC command and writing a parsing method that gives me all of the PIDs of every plink instance. However the last PID is always the last one that was opened so if I call this method right after I create a new plink instance I will always have the PID of the plink instance I need.
So @Tim Hare I more or less used your solution. Just one without a need to compare lists.
Here’s my method, I’m sure there is a better way to parse this out, but it’s what I came up with. Feel free to improve on it if you like, I’m always open to improvements.
Method getPID returns the last PID of the last plink instance opened.
dim s as string
dim a as string
dim r as string
dim arr() as string
dim arr2() as string
dim i as integer
dim x as integer
dim z as integer
dim strConnect As String = "WMIC PROCESS WHERE " + chr(34) + "NAME like '%%plink.exe%%'" + chr(34) + " GET PROCESSID"
dim pShell As New Shell
pShell.Mode = 0
pShell.Execute(strConnect)
s = pShell.Result
s = s.Replace("ProcessId"," ")
for i = 1 to s.len
a = Mid(s, i, 1)
if a = " " then
a = "_"
end
r = r + a
next i
arr = Split(r, "_")
for i = 0 to arr.ubound
x = cDbl(arr(i))
if x <> 0 then
arr2.Append(arr(i))
end
next
' Get the most recent plink PID
z = arr2.Ubound
Return arr2(z)
I also found another unusual idea I thought I would share. If you are using the same process multiple times like this and need to close a specific one if the process takes parameters and they are different for each instance you could also use this command to close a specific process. Too broad for me but someone else might find it useful.
wmic Path win32_process Where "CommandLine Like '%%-ssh -pw%%'" Call Terminate
Hello, a little late but you can use also tasklist to do that, the result is easier to parse and the command is most commun :
[code] dim s as string
dim arr() as string
dim arr2() as string
dim arr3() as String
dim i as integer
dim z as integer
dim strConnect As String = "tasklist /fo csv | findstr /i " + chr(34) + "plink" + chr(34)
dim pShell As New Shell
pShell.Mode = 0
pShell.Execute(strConnect)
s = pShell.Result
s = s.Replaceall(chr(34),"")
arr = Split(s,EndOfLine)
for i = 0 to arr.ubound
arr2 = Split(arr(i),",")
arr3.Append arr2(1)
next
z = arr3.ubound
' Get the most recent plink PID
return arr3(z)
Added a small check in case tasklist returns an empty line.
[code] dim s as string
dim arr() as string
dim arr2() as string
dim arr3() as String
dim i as integer
dim z as integer
dim strConnect As String = "tasklist /fo csv | findstr /i " + chr(34) + "plink" + chr(34)
dim pShell As New Shell
pShell.Mode = 0
pShell.Execute(strConnect)
s = pShell.Result
s = s.Replaceall(chr(34),"")
arr = Split(s,EndOfLine)
for i = 0 to arr.ubound
arr2 = Split(arr(i),",")
if arr2.ubound<1 then continue //Added
arr3.Append arr2(1)
next
z = arr3.ubound
' Get the most recent plink PID
return arr3(z)[/code]