I need to do exactly as I asked in the question for any program that I have just started from my VBScript.
I am starting the System Properties program from VBscript as below:
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run "SystemPropertiesAdvanced.exe"
WScript.Sleep 1000
Now I want to get the process id of SystemPropertiesAdvanced.exe program, how can I do that ?
I would like to do this purely by VBScript without mix coding as much as possible.
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process where name='Calculator.exe'")
'msgbox colitems
For Each objItem in colItems
msgbox objItem.name & " " & objItem.ProcessID & " " & objItem.CommandLine
If objItem.name = "Calculator.exe" then objItem.terminate
Next
This uses WMI to query for Calculator.exe and then terminates it.
This is how to to start process and get processID with WshShell Object:
Dim sh : Set sh = CreateObject("WScript.Shell")
Set Rtn = sh.Exec("SystemPropertiesAdvanced.exe") 'write the full path of application
WScript.Sleep 1000 'stop script 1 sec waiting run the App
MsgBox "my App PID : " & Rtn.ProcessID 'Process ID for App
OR use WMI to start process and get the processID
set process = GetObject("winmgmts:Win32_Process")
process.Create "SystemPropertiesAdvanced.exe",null,null,processid
MsgBox "my App PID : " & Processid
I'm trying to close an open OneNote application on a user's computer using VB Script. However, I cannot seem to get it to work. I need to close any open OneNotes before I run the rest of the VBS file. So far I've tried this, but doesn't work for OneNote.
Set oNote= CreateObject("WScript.Shell")
oNote.Exec "onenote"
oNote.Terminate
This is another code I've tried. Neither work.
Set oNote= CreateObject("onenote")
oNote.Quit
You can try like this way to kill Onenote.exe process
Option Explicit
Dim Process
Process = "Onenote.exe"
Call Kill(Process)
'****************************************************
Sub Kill(Process)
Dim Ws,Command,Execution
Set Ws = CreateObject("Wscript.Shell")
Command = "cmd /c Taskkill /F /IM "& Process &""
Execution = Ws.Run(Command,0,True)
Set Ws = Nothing
End Sub
'****************************************************
Or by this way :
Option Explicit
Dim objWMIService, objProcess, colProcess
Dim strComputer, strProcessKill
strComputer = "."
strProcessKill = "'Onenote.exe'"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill )
For Each objProcess in colProcess
objProcess.Terminate(1)
Next
MsgBox ("Do you want to start the autoclicker?", vbOkOnly, "Autoclicker")
CreateObject("WScript.Shell").Run("""C:\Users\Henry\Desktop\Fun.vbs""")
MsgBox ("Do you want to stop the autoclicker?", vbOkOnly, "Autoclicker")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objItem in colItems
'msgbox objItem.ProcessID & " " & objItem.CommandLine
If objItem.name = "Calculator.exe" then objItem.terminate
Next
This kills calculator.exe. Change it to wscript.exe. You might want to check command line if you just want to kill fun.vbs.
The following routine kills all processes whose command lines contain a specified string. The 3 lines below the routine are for testing it. We pause the routine by showing a message box and when you dismiss the message box, we kill the script instance, so the second message box doesn't show up. When you use it, you want to replace the last 3 lines with
KillProcesses "Fun.vbs"
I'd be careful using this and specify as much of the command line as possible to make sure I absolutely, positively match only the processes I want to terminate. You can modify the Task Manager and add a column to show the command line for every running process. In the routine below, the search in command line is case-insensitive.
Option Explicit
Sub KillProcesses(strPartOfCommandLine)
Dim colProcesses
Dim objProcess
Dim lReturn
' Get list of running processes using WMI
Set colProcesses = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("Select * From Win32_Process")
For Each objProcess in colProcesses
If (Instr(1, objProcess.Commandline, strPartOfCommandLine, vbTextCompare) <> 0) Then
lReturn = objProcess.Terminate(0)
End If
Next
End Sub
Msgbox "Before being killed"
KillProcesses "KillProcesses.vbs"
Msgbox "After being killed"
I made before a script that ask you what vbscript did you want to kill and log the result into file.
So just, give a try :
Option Explicit
Dim Titre,Copyright,fso,ws,NomFichierLog,temp,PathNomFichierLog,OutPut,Count,strComputer
Copyright = "[© Hackoo © 2014 ]"
Titre = " Process "& DblQuote("Wscript.exe") &" running "
Set fso = CreateObject("Scripting.FileSystemObject")
Set ws = CreateObject( "Wscript.Shell" )
NomFichierLog="Process_WScript.txt"
temp = ws.ExpandEnvironmentStrings("%temp%")
PathNomFichierLog = temp & "\" & NomFichierLog
Set OutPut = fso.CreateTextFile(temp & "\" & NomFichierLog,1)
Count = 0
strComputer = "."
Call Find("wscript.exe")
Call Explorer(PathNomFichierLog)
'***************************************************************************************************
Function Explorer(File)
Dim ws
Set ws = CreateObject("wscript.shell")
ws.run "Explorer "& File & "\",1,True
end Function
'***************************************************************************************************
Sub Find(MyProcess)
Dim colItems,objItem,Processus,Question
Set colItems = GetObject("winmgmts:").ExecQuery("Select * from Win32_Process " _
& "Where Name like '%"& MyProcess &"%' AND NOT commandline like '%" & wsh.scriptname & "%'",,48)
For Each objItem in colItems
Count= Count + 1
Processus = Mid(objItem.CommandLine,InStr(objItem.CommandLine,""" """) + 2) 'Extraction of the commandline script path
Processus = Replace(Processus,chr(34),"")
Question = MsgBox ("Did you want to stop this script : "& DblQuote(Processus) &" ?" ,VBYesNO+VbQuestion,Titre+Copyright)
If Question = VbYes then
objItem.Terminate(0)'Kill this process
OutPut.WriteLine DblQuote(Processus)
else
Count= Count - 1 'decrement the counter -1
End if
Next
OutPut.WriteLine String(100,"*")
OutPut.WriteLine count & Titre & " were stopped !"
End Sub
'**********************************************************************************************
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'**********************************************************************************************
Is there any way to kill a wscript.exe (windows process for vb script) from another VBScript (not from the currently executing wscript)?
If I create a script like this:
Set s = CreateObject("WScript.Shell")
s.Run "taskkill /im wscript.exe", , True
instead of killing the former script, this will kill itself.
I'd recommend using WMI for selecting and terminating the processes. Something like this should work:
Set wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_Process WHERE Name='wscript.exe' AND NOT " & _
"CommandLine LIKE '%" & Replace(WScript.ScriptFullName, "\", "\\") & "%'"
For Each p In wmi.ExecQuery(qry)
p.Terminate
Next
Option Explicit
Dim strScriptToKill
strScriptToKill = "ItIsDead.vbs"
Dim objWMIService, objProcess, colProcess
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcess = objWMIService.ExecQuery ( _
"Select * from Win32_Process " & _
"WHERE (Name = 'cscript.exe' OR Name = 'wscript.exe') " & _
"AND Commandline LIKE '%"& strScriptToKill &"%'" _
)
For Each objProcess in colProcess
objProcess.Terminate()
Next
I'm using the following code snippet to determine what process ID my vbscript is running as:
On Error Resume Next
Dim iMyPID : iMyPID = GetObject("winmgmts:root\cimv2").Get("Win32_Process.Handle='" & CreateObject("WScript.Shell").Exec("mshta.exe").ProcessID & "'").ParentProcessId
If Err.Number <> 0 Then Call Handle_Error(Err.Description)
On Error Goto 0
On my Windows 7 (32-bit) machine this works about 90% of the time and iMyPID contains the process ID of the currently running script. However 10% of the time Handle_Error gets called with the error message "SWbemServicesEX: Not found".
Recently someone else running Windows 7 (64-bit) reported that Handle_Error always gets called with the error message "Out of memory". This seems an insane error message just to find out your own process ID!
Can anyone recommend a better way of doing this?
mshta terminates itself immediately. Maybe it's too late to achieve parent process id by using WMI service.
So, I'd use something like this to eliminate concurrent script processes.
Generate random things.
Determine an application which could be installed on each system, never terminates by itself (e.g. command prompt with /k parameter).
Start the application in hidden mode with generated random argument (WshShell.Run).
Wait a few milliseconds
Query the running processes by using command line argument value.
Get the ParentProcessId property.
Function CurrProcessId
Dim oShell, sCmd, oWMI, oChldPrcs, oCols, lOut
lOut = 0
Set oShell = CreateObject("WScript.Shell")
Set oWMI = GetObject(_
"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
sCmd = "/K " & Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
oShell.Run "%comspec% " & sCmd, 0
WScript.Sleep 100 'For healthier skin, get some sleep
Set oChldPrcs = oWMI.ExecQuery(_
"Select * From Win32_Process Where CommandLine Like '%" & sCmd & "'",,32)
For Each oCols In oChldPrcs
lOut = oCols.ParentProcessId 'get parent
oCols.Terminate 'process terminated
Exit For
Next
CurrProcessId = lOut
End Function
Dim ProcessId
ProcessId = CurrProcessId 'will remain valid indefinitely
WScript.Echo ProcessId
Here's an even better code snippet:
' ***********************************************************************************************************
' lng_MyProcessID finds and returns my own process ID. This is excruciatingly difficult in VBScript. The
' method used here forks "cmd /c pause" with .Exec, and then uses the returned .Exec object's .ProcessID
' attribute to feed into WMI to get that process's Win32_Process descriptor object, and then uses THAT
' WMI Win32_Process descriptor object's .ParentProcessId attribute, which will be OUR Process ID, and finally
' we terminate the waiting cmd process. Execing cmd is what causes the brief cmd window to flash at start up,
' and I can' figure out out how to hide that window.
' returns: My own Process ID as a long int; zero if we can't get it.
' ************************************************************************************************************
Function lng_MyProcessID ()
lng_MyProcessID = 0 ' Initially assume failure
If objWMIService Is Nothing Then Exit Function ' Should only happen if in Guest or other super-limited account
Set objChildProcess = objWshShell.Exec ( """%ComSpec%"" /C pause" ) ' Fork a child process that just waits until its killed
Set colPIDs= objWMIService.ExecQuery ( "Select * From Win32_Process Where ProcessId=" & objChildProcess.ProcessID,, 0 )
For Each objPID In colPIDs ' There's exactly 1 item, but .ItemIndex(0) doesn't work in XP
lng_MyProcessID = objPID.ParentProcessId ' Return child's parent Process ID, which is MY process ID!
Next
Call objChildProcess.Terminate() ' Terminate our temp child
End Function ' lng_MyProcessID
I like Kul-Tigin's idea (+1), and Asok Smith's idea (based on .Exec) deserve respect (+1), and it w'd been even better if .Exec run hidden process. So, to feed my curiosity, I also toyed with this and this's what I did.
ts1 = Timer : res1 = CurrProcessId : te1 = Timer - ts1
ts2 = Timer : res2 = ThisProcessId : te2 = Timer - ts2
WScript.Echo "CurrProcessId", res1, FormatNumber(te1, 6), _
vbCrLf & "ThisProcessId", res2, FormatNumber(te2, 6), _
vbCrLf & "CurrProcessId / ThisProcessId = " & te1 / te2
'> CurrProcessId 6946 0,437500
'> ThisProcessId 6946 0,015625
'> CurrProcessId / ThisProcessId = 28
Function ThisProcessId
ThisProcessId = 0
Dim sTFile, oPrc
With CreateObject("Scripting.FileSystemObject")
sTFile = .BuildPath(.GetSpecialFolder(2), "sleep.vbs")
With .OpenTextFile(sTFile, 2, True)
.Write "WScript.Sleep 1000"
End With
End With
With CreateObject("WScript.Shell").Exec("WScript " & sTFile)
For Each oPrc In GetObject("winmgmts:\\.\root\cimv2").ExecQuery(_
"Select * From Win32_Process Where ProcessId=" & .ProcessID)
Exit For : Next
ThisProcessId = oPrc.ParentProcessId
End With
End Function
28 times faster(!), not bad :)
You may use Sleep from kernel32 instead of mshta.
MsgBox GetProcId()
Function GetProcId()
With GetObject("winmgmts:\\.\root\CIMV2:Win32_Process.Handle='" & CreateObject("WScript.Shell").Exec("rundll32 kernel32,Sleep").ProcessId & "'")
GetProcId = .ParentProcessId
.Terminate
End With
End Function
Code taken from here.
Also there is parent process name detection based on this approach.
Here is a better one, but in JScript (sorry, you translate it to VB ...)
var WshShell = WScript.CreateObject("WScript.Shell");
var objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2");
var childProcess =
WshShell.Exec
(
'"' + WshShell.Environment('PROCESS')('ComSpec') + '"'
+
" /C Echo \"Text lines\" && Set /p VarName="
);
childProcess.StdOut.ReadLine();
var current_pid =
objWMIService.ExecQuery
(
"Select * From Win32_Process Where ProcessId=" + childProcess.ProcessID
);
current_pid = (new Enumerator(current_pid)).item().ParentProcessId;
if (current_pid)
{
childProcess.StdIn.WriteLine("value"); // child process should now exit
WScript.Echo("Current PID: " + current_pid);
}
else
{
WScript.StdErr.WriteLine("Get current PID from WMI failed.");
WScript.Quit(7);
}
I just found this thread that partly solved my problem.
Thank you all.
"the code is unable to determine which process ID belongs to which script" : true, but as this is the first task that your script must achieve , you can keep the Pid that has the shortest lifetime.
Set com = CreateObject("Wscript.Shell")
Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
Set colProcess = objSWbemServices.ExecQuery ("Select * From Win32_Process")
dim toto, thisPid
thisPid=""
toto=200 ' just a high value like 200sec
For Each objProcess In colProcess
If InStr (objProcess.CommandLine, WScript.ScriptName) <> 0 Then
Ptime=((Cdbl(objProcess.UserModeTime)+Cdbl(objProcess.KernelModeTime))/10000000)
if toto > Ptime then
toto = Ptime
thisPid = objProcess.ProcessId
End If
End If
Next
If thisPid="" then
WScript.Echo "unable to get the PID"
Else
WScript.Echo "PID of this script : "&thisPid
End If
Except if you fired scripts quicker more than each one can retrieve their Pid, everything must be ok.
To retrieve the own process ID of a VB Script you can rely on the property CreationDate of the Process object.
At the moment a VB Script is started, the process that runs the script will have the latest CreationDate of all processes that runs the same script.
In fact, it will have the highest CreationDate of all running processes.
So, to get the PID, first thing to do is to search for the process with the highest CreationDate.
'Searching for processes
Dim strScriptName
Dim WMI, wql
Dim objProcess
'
'My process
Dim datHighest
Dim lngMyProcessId
'Which script to look for ?
strScriptName = "WScript.exe"
'strScriptName = "Notepad.exe"
'Iniitialise
datHighest = Cdbl(0)
Set WMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
wql = "SELECT * FROM Win32_Process WHERE Name = '" & strScriptName & "'"
'
For Each objProcess In WMI.ExecQuery(wql)
'The next If is not necessary, it only restricts the search to all processes on the current VB Script
'If Instr(objProcess.CommandLine, WScript.ScriptName) <> 0 Then
If objProcess.CreationDate > datHighest Then
'Take the process with the highest CreationDate so far
' e.g. 20160406121130.510941+120 i.e. 2016-04-06 12h11m:30s and fraction
datHighest = objProcess.CreationDate
lngMyProcessId = objProcess.ProcessId
End If
'End If
Next
'Show The result
WScript.Echo "My process Id = " & lngMyProcessId
Powershell can be used to retrieve the calling VBScript process ID. This approach utilizes the optional argument of the exit command which specifies the program's exit code. And, if the optional 3rd argument of the WShell.Run method is set to True, then it will return the exit code (which is the VBScript process ID) after powershell has closed.
Dim sCmd
Dim WShell
sCmd = _
"powershell -command exit " & _
"(gwmi Win32_Process -Filter " & _
"\""processid='$PID'\"").parentprocessid"
Set WShell = CreateObject("WScript.Shell")
MsgBox WShell.Run(sCmd, 0, True)
This is not my answer, I found this in some google groups discussion forum... See if it helps you.
Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
Set colProcess = objSWbemServices.ExecQuery ("Select * From Win32_Process")
For Each objProcess In colProcess
If InStr (objProcess.CommandLine, WScript.ScriptName) <> 0 Then
WScript.Echo objProcess.Name, objProcess.ProcessId, objProcess.CommandLine
End If
Next
Original Discussion Thread in Google Groups forum
Get the current processID
Set WshShell = CreateObject("WScript.Shell")
currentProgram=wscript.ScriptName
Const strComputer = "."
Dim objWMIService, colProcessList
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
query="SELECT * FROM Win32_Process WHERE Name = 'wscript.exe' "
Set colProcessList = objWMIService.ExecQuery(query)
For Each objProcess in colProcessList
If (InStr (objProcess.commandLine,wscript.ScriptName) <> 0 )Then
processDetails="Current ProcessId : "& objProcess.ProcessId & " \n, And Process Name:" & objProcess.name &"\n CommandLine is :"& objProcess.CommandLine
message = msgbox(processDetails,16,"Details")
End If
I used this to get a scripts own process id.
Function GetPid()
GetPid=GetObject("winmgmts:\\.\root\CIMV2").ExecQuery("Select * From Win32_Process Where CommandLine Like '%" &Wscript.ScriptName& "%'").ItemIndex(0).ProcessId
End Function
Wscript.Echo GetPid()