I am writing a vb script to monitor a process. The script monitors the status of a process and if the process is not running since 10 mins it should execute a command.Below is my script:
set objWMIService = GetObject ("winmgmts:")
foundProc = False
procName = "calc.exe"
Dim wshell
' Initialise the shell object to return the value to the monitor
Set wshell = CreateObject("WScript.Shell")
if err.number <> 0 then
WScript.Echo "Error: could not create WScript.Shell (error " & err.number & ", " & err.Description & ")"
WScript.quit(255)
end if
for each Process in objWMIService.InstancesOf ("Win32_Process")
If StrComp(Process.Name,procName,vbTextCompare) = 0 then
foundProc = True
procID = Process.ProcessId
End If
Next
#####code to check the proces status
If foundProc = True Then
WScript.Quit(0)
Else
WScript.sleep(1*60*1000)
If foundProc = True Then
WScript.Echo "Found Process (" & procID & ")"
Else
WScript.Echo "Process not running since 10 mins"
WScript.Quit(0)
End If
End If
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM Win32_ProcessTrace")
Do
Set objReceivedEvent = objEvents.NextEvent
If objReceivedEvent.ProcessName = "svchost.exe" then msgbox objReceivedEvent.ProcessName
' msgbox objReceivedEvent.ProcessName
Loop
You also have Win32_ProcessTraceStart and Win32_ProcessTraceStop. Above code is both.
It is also pointless doing error checking on WScript.Shell. It's a system component - it should be available. Also if it's not your script won't run as wscript isn't available to run your script.
Related
Any thoughts on why this script always entering the If statment even the process is not running?
If isProcessRunning("Allplan_2022.exe") Then
MsgBox "Allplan is running!"
WScript.Quit
End If
Function isProcessRunning(ByVal processName)
Dim objProcessList
Set isProcessRunning = FALSE
Set objProcessList = GetObject("Winmgmts:").ExecQuery ("Select * from Win32_Process")
For Each item In objProcessList
If item.Name = processName Then
isProcessRunning = TRUE
Exit For
End If
Next
End Function
Here is an example for checking if mspaint.exe is running or not and let one instance to be run !
Option Explicit
Dim WS,ProcessName,Msg,Title
Title = "Cheking if a Windows process is running by using VBScript"
Set WS = CreateObject("wscript.shell")
ProcessName = "mspaint.exe"
If isProcessRunning("mspaint.exe") Then
Msg = "ATTENTION ! There is another instance in execution !"
ws.Popup Msg & VbCrLF &_
chr(34) & ProcessName & chr(34),"5",Title,VbExclamation+vbSystemModal
WScript.Quit(1)
End If
WS.Run ProcessName,1,False
'------------------------------------------------------------------------------------------
Function isProcessRunning(ProcessName)
Dim objProcessList,item
isProcessRunning = FALSE
set objProcessList = GetObject("Winmgmts:").ExecQuery ("Select * from Win32_Process")
For Each item In objProcessList
If item.Name = processName Then
isProcessRunning = TRUE
Exit For
End If
Next
End Function
'-------------------------------------------------------------------------------------------
For example:
I have a code of VBS, it will help me check a program is already running
Function isProcessRunning(strComputer, strProcess)
Dim Process, strObject
strObject = "winmgmts://" & strComputer
For Each Process In GetObject(strObject).InstancesOf("Win32_Process")
If UCase(Process.Name) = UCase(strProcess) Then
isProcessRunning = True
Exit Function
Else
isProcessRunning = False
End If
Next
End Function
But, I want to get process is already running for re-using.
Function shell()
If isProcessRunning(".", "cmd.exe") == False Then
Dim objShell
Set objShell = WScript.CreateObject("WScript.Shell")
shell = objShell.Run(cmd)
Else
shell = ... 'how can I get cmd.exe already running here
End If
Next
End Function
Update my problem
Actually, I want to get instance of cmd.exe if it's already running. I mean, I don't want re-open cmd.exe again.
Example:
I have just opened cmd.exe.
I run this code below (its name is laucher.vbs).
Function isProcessRunning(strComputer, strProcess)
Dim Process, strObject
strObject = "winmgmts://" & strComputer
For Each Process In GetObject(strObject).InstancesOf("Win32_Process")
If UCase(Process.Name) = UCase(strProcess) Then
isProcessRunning = True
Exit Function
Else
isProcessRunning = False
End If
Next
End Function
Function getProcessRunning(strComputer, strProcess)
Dim Process, strObject
strObject = "winmgmts://" & strComputer
For Each Process In GetObject(strObject).InstancesOf("Win32_Process")
If UCase(Process.Name) = UCase(strProcess) Then
... 'I do not know how to code this here for return instance of Process is running ...
Exit Function
End If
Next
End Function
Function shell()
If isProcessRunning(".", "cmd.exe") == False Then
Dim objShell
Set objShell = WScript.CreateObject("WScript.Shell")
shellFn = objShell.Run("cmd")
Else
shellFn = getProcessRunning(".", "cmd.exe")
End If
End Function
Dim cmdExe
cmdExe = shell
cmdExe "shutdown -s -t 60"
Because cmd.exe is already running cmdExe "shutdown -s -t 60" will re-using cmd and execute command.
Give a try for this example :
Option Explicit
Dim ProcessPath1,ProcessPath2
ProcessPath1 = "%windir%\system32\cmd.exe"
ProcessPath2 = "%ProgramFiles%\Internet Explorer\iexplore.exe"
Call CheckProcess(ProcessPath1)
Call CheckProcess(ProcessPath2)
'**************************************************************************
Sub CheckProcess(ProcessPath)
Dim strComputer,objWMIService,colProcesses,WshShell,Tab,ProcessName
strComputer = "."
Tab = Split(ProcessPath,"\")
ProcessName = Tab(UBound(Tab))
ProcessName = Replace(ProcessName,Chr(34),"")
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = '"& ProcessName & "'")
If colProcesses.Count = 0 Then
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run DblQuote(ProcessPath)
Else
MsgBox DblQuote(ProcessName) & " is aleardy running !", vbExclamation,_
DblQuote(ProcessName) & " is aleardy running !"
Exit Sub
End if
End Sub
'**************************************************************************
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'**************************************************************************
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
'**********************************************************************************************
I am trying to run following VB Script to run command on remote machine. I want this script to wait until command is executed completely.
Here is my code:
Function RemoteExecute(strServer, strUser, strPassword, strCommand,pro)
Dim objLocator , objWMIService
wbemImpersonationLevelImpersonate = 3
wbemAuthenticationLevelPktPrivacy = 6
RemoteExecute = -1
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
On Error Resume Next
Set objWMIService = objLocator.ConnectServer(strServer,"root\cimv2", strUser,strPassword)
objWMIService.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate
objWMIService.Security_.AuthenticationLevel = wbemAuthenticationLevelPktPrivacy
If Err.Number <> 0 Then
WScript.Echo "Failed to connect to " &strServer, "Error # " & CStr(Err.Number) & " " & Err.Description & vbcrlf & _
"Please check if " & strServer & " is pingable from this client & credentials are correct"
Err.Clear
On Error GoTo 0
RemoteExecute = -1
Set objWMIService = nothing
Set objLocator = nothing
Exit function
end if
' Configure the process to show a window
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = SW_NORMAL
Set Process = objWMIService.Get("Win32_Process")
'Process.Create Syntax: '
' uint32 Create(
'[in] string CommandLine,
'[in] string CurrentDirectory,
'[in] Win32_ProcessStartup ProcessStartupInformation,
'[out] uint32 ProcessId
');
'Return code Description
'0 Successful Completion
'2 Access Denied
'3 Insufficient Privilege
'8 Unknown failure
'9 Path Not Found
'21 Invalid Parameter
intReturn = Process.Create(strCommand,NULL, objConfig, intProcessID)
If intReturn <> 0 Then
Wscript.Echo "Process could not be created." & _
vbNewLine & "Command line: " & strCommand & _
vbNewLine & "Return value: " & intReturn
Wscript.Quit
Else
Wscript.Echo "Process created." & _
vbNewLine & "Command line: " & strCommand & _
vbNewLine & "Process ID: " & intProcessID
RemoteExecute = intProcessID
End If
' Set objWMIService = GetObject("winmgmts:\\" & strServer & "\root\cimv2")
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery_("SELECT *" +" FROM __InstanceDeletionEvent " +"WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' " )
Do
Set objProcess = colMonitoredProcesses.NextEvent
Wscript.Echo objProcess.TargetInstance.Name
Wscript.Echo objProcess.TargetInstance.ExecutablePath
Wscript.Echo "1"
Wscript.Echo "proc:" & objProcess.TargetInstance.ProcessID
Wscript.Echo "int:" & intProcessID
If objProcess.TargetInstance.ProcessID = intProcessID Then
Wscript.Echo "I will end the monitoring of the process "
Wscript.Echo pro & objProcess.TargetInstance.Name
Exit Do
end If
Loop
Set objWMIService = nothing
Set objLocator = nothing
End Function
strServer = WScript.Arguments.Item(0)
strUser = WScript.Arguments.Item(1)
strPassword = WScript.Arguments.Item(2)
strCommand = WScript.Arguments.Item(3)
pro = WScript.Arguments.Item(4)
Call RemoteExecute(strServer, strUser, strPassword, strCommand,pro)
But problem I am facing is that, script run the process in background but not waiting for it.
Another point that I do not understand is, when try to echo following:
Wscript.Echo objProcess.TargetInstance.Name
Wscript.Echo objProcess.TargetInstance.ExecutablePath
Wscript.Echo "proc:" & objProcess.TargetInstance.ProcessID
it does no echo anything, whereas following are properly echoed with a nice pop up
Wscript.Echo "1"
Wscript.Echo "int:" & intProcessID
Can someone please resolve my problem, may be this problem is naive for someone, sorry I am naive here.
I'm having an issue with a VBScript that looks for printers on computers from a list on an Excel sheet and then finds them through WMI. It matches them through the IP address name and then writes a batch file that I can install them from. My issue is that when I have a computer that is turned off I get a 462 error which is then cleared but then the printers for the previous computer are written again. I'm quite new at this so I'm not sure if I'm just missing something really basic here.
Batch = "printerOutput.txt"
Const ForWriting = 2 'Set to 8 for appending data
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(Batch, ForWriting)
On Error Resume Next
Dim printerDictionary 'Create Printer dictionary of names and IP addresses
Set printerDictionary = CreateObject("Scripting.Dictionary")
printerDictionary.Add "Printer","xxx.xxx.xxx.xxx"
Set objExcel_1 = CreateObject("Excel.Application")
' Statement will open the Excel Workbook needed.
Set objWorkbook = objExcel_1.Workbooks.Open _
("x\p.xls")
If Err.Number <> 0 Then
MsgBox "File not Found"
Wscript.Quit
End If
'Checks for errors
f = 1 'Sets variable that will loop through Excel column
Do
' Msgbox f,, "Begining of Do Loop"
strComputer = objExcel_1.Cells(f, 1).Value
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
For Each objPrinter in colPrinters 'For ever objPrinter found in the computers WMIService
If Err.Number = 0 Then
objFile.WriteLine Err.Number
If InStr(ObjPrinter.PortName,".") = 4 then 'If the printers IP port name is written like 128.xxx.xxx.xxx
'MsgBox ObjPrinter.Name & " " & ObjPrinter.PortName,, "IfStatement"
PrtDict ObjPrinter.PortName, StrComputer
ElseIf InStr(ObjPrinter.PortName,"_") = 3 Then 'If the printers IP port name is written like IP_128.xxx.xxx.xxx
cleanIP = GetIPAddress(objPrinter.PortName) 'Clean IP
PrtDict cleanIP, StrComputer
End If
Else
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Err.Clear
End If
Next
f = f + 1
Loop Until objExcel_1.Cells(f, 1).Value = ""
objExcel_1.ActiveWorkbook.Close
ObjExcel_1.Quit
Function PrtDict(PrtMn, CMP) 'Loops through the dictionary to find a match from the IP address found
For Each x in printerDictionary
'MsgBox PrtMn & "=" & printerDictionary.Item(x),,"InPtrDict"
If printerDictionary.Item(x) = PrtMn Then
objFile.WriteLine "psexec -u \%1 -p %2 " & CMP & " path\" & x & ".bat"
End If
Next
End Function
'100
Function GetIPAddress(Address) 'For cleaning up IP address with names like IP_128.xxx.xxx.xxx
IPtext = InStr(Address,"_")
IPaddress = len(Address) - IPtext
GetIPAddress = Right(Address,IPaddress)
End Function
What happens is this:
On Error Resume Next
This enables error-handling (or rather error suppression) for the rest of the script, since it's never disabled.
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
This command fails, because strComputer is not reachable. Because of the error the variable Err is set and objWMIService retains its previous value.
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
This command succeeds and re-reads the printer list from the previous computer, because objWMIService still refers to that computer.
For Each objPrinter in colPrinters
The script enters the loop, because colPrinters got populated with the printers from the previous computer (again), …
If Err.Number = 0 Then ... Else ... End If
… but because Err is still set, the script goes into the Else branch, where the error is reported and cleared:
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Err.Clear
Then the script goes into the next iteration of the loop. Err is now cleared, so the rest of the printers in colPrinters is being processed normally.
Global On Error Resume Next is the root of all evil. Don't do this. EVER.
If you absolutely must use On Error Resume Next, enable error-handling locally, put some actual error handling code in place, and disable error-handling right afterwards. In your case one might implement it like this:
...
Do
strComputer = objExcel_1.Cells(f, 1).Value
On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
If Err Then
objFile.WriteLine "REM " & strComputer & " - Error: " & err.number
Set objWMIService = Nothing
End If
On Error Goto 0
If Not objWMIService Is Nothing Then
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")
For Each objPrinter in colPrinters
...
Next
f = f + 1
End If
Loop Until objExcel_1.Cells(f, 1).Value = ""
...