I am looking for a way to ping a hostname via a VBScript and if it fails after some bad counts, if offline, it runs another vbs file.
I have many scripts that can ping a host via VBScript, but I don't know and I couldn't find a way to ping a host and if not pinging, to redirect and run another VBScript.
I've tried to add in the end of one of those scripts something like:
If strFailedPings = "" Then
WScript.Echo "Ping status of specified computers is OK"
Else
(here is the place that goes the code to open another vbs)
Example:
strComputers = "192.168.1.1,192.168.1.4"
arrComputers = Split(strComputers, ",")
For Each strComputer In arrComputers
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}")._
ExecQuery("SELECT * from Win32_PingStatus WHERE address = '" & _
strComputer & "'")
For Each objPingStatus In objPing
If IsNull(objPingStatus.StatusCode) Or objPingStatus.StatusCode<>0 Then
If strFailedPings <> "" Then strFailedPings = strFailedPings & vbCrLf
strFailedPings = strFailedPings & strComputer
End If
Next
Next
If strFailedPings = "" Then
WScript.Echo "Ping status of specified computers is OK"
Else
WScript.Echo "Ping failed for the following computers:" & _
vbCrLf & vbCrLf & strFailedPings
End If
Run the WMI query n times in a For loop and count and count the failed pings, then run the other script if the fail count exceeds a given threshold.
n = 3
threshold = 1
Set wmi = GetObject("winmgmts://./root/cimv2")
For Each strComputer In arrComputers
qry = "SELECT * FROM Win32_PingStatus WHERE address='" & strComputer & "'"
cnt = 0
For i = 1 To n
For Each objPingStatus In wmi.ExecQuery(qry)
If IsNull(objPingStatus.StatusCode) Or objPingStatus.StatusCode<>0 Then
cnt = cnt + 1
End If
Next
Next
If cnt > threshold Then
'ping failed 2 or more times
CreateObject("WScript.Shell").Run "wscript.exe ""C:\other\script.vbs""", 0, True
End If
Next
Side note: you may want to distinguish between sNull(objPingStatus.StatusCode) and objPingStatus.StatusCode<>0. Only the latter represents the actual ping status. The former indicates a WMI error.
I don't think you can break up the GetObject line:
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery("SELECT * from Win32_PingStatus WHERE address = '" & strComputer & "'")
When I run the script (I replaced the Echo with MsgBox but it shouldn't matter) it works fine:
strComputers = "192.168.1.1,192.168.1.4,100.100.100.100"
arrComputers = Split(strComputers, ",")
For Each strComputer In arrComputers
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery("SELECT * from Win32_PingStatus WHERE address = '" & strComputer & "'")
For Each objPingStatus In objPing
If IsNull(objPingStatus.StatusCode) Or objPingStatus.StatusCode <> 0 Then
If strFailedPings <> "" Then strFailedPings = strFailedPings & vbCrLf
strFailedPings = strFailedPings & strComputer
End If
Next
Next
If strFailedPings = "" Then
MsgBox "Ping status of specified computers is OK"
Else
MsgBox "Ping failed for the following computers:" & _
vbCrLf & vbCrLf & strFailedPings
End If
Related
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 have this code to remotely kill a certain process on 5 servers. My problem is that i want to cut it short and kill the process in all servers in 1 click. The code now asks if i am sure i want to kill the process, then kills the process, then asks if i want to proceed to the next server. i would like to just have a messge saying, "Killing process on all servers" and done
`Option Explicit
Dim objWMIService, objProcess, colProcess
Dim strProcessKill, item
Dim strComputer(4)
Dim ans, killFLag
strComputer(0) = "server1"
strComputer(1) = "server2"
strComputer(2) = "server3"
strComputer(3) = "server4"
strComputer(4) = "server5"
strProcessKill = "'notepad.exe'"
For item = 0 To 4 Step 1
if MsgBox("Are you sure you want to kill " & strProcessKill & " on " & strCOmputer(item) & "?" , vbYesNo + vbQuestion) = vbYes then
killFLag = 1
end if
if KillFlag = 1 then
msgbox "KILLING PROCESS ON" & strComputer(item)
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer(item) & "\root\cimv2")
Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill)
For Each objProcess in colProcess
objProcess.Terminate()
Next
WSCript.Echo "Just killed process " & strProcessKill & " on " & strComputer(item)
else
WScript.Quit
end if
Next`
Move the for loop down so that you are not prompted for each server. Something like this should work
Option Explicit
Dim objWMIService, objProcess, colProcess
Dim strProcessKill, item
Dim strComputer(4)
Dim ans, killFLag
strComputer(0) = "server1"
strComputer(1) = "server2"
strComputer(2) = "server3"
strComputer(3) = "server4"
strComputer(4) = "server5"
strProcessKill = "'notepad.exe'"
if MsgBox("Are you sure you want to kill " & strProcessKill & " on all servers?" , vbYesNo + vbQuestion) = vbYes then
killFLag = 1
end if
if KillFlag = 1 then
msgbox "KILLING PROCESS ON ALL SERVERS"
For item = 0 To 4 Step 1
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer(item) & "\root\cimv2")
Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill)
For Each objProcess in colProcess
objProcess.Terminate()
Next
next
msgBox "Done"
else
WScript.Quit
end if
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 trying to create a script that will connect to remote computers within an IP address range and then echo which of those is running the explorer.exe process.
When I run the script within a small range (10.2.1.1 - 10.2.1.10), I know that 10.2.1.4 is offline and that 10.2.1.9 and 10.2.1.10 are not Windows based computers and should therefore echo "Explorer.exe is not running" however that doesn't seem to be the case. They appear to return the same result of the previous server. For instance, 10.2.1.3 has 3 instances of Explorer.exe and echo's 3 times, I then get the same result for 10.2.1.4 which is offline.
My script is as follows:
On Error Resume Next
intStartingAddress = InputBox("Please enter a starting address: (e.g. 1)", "Starting Address")
intEndingAddress = InputBox("Please enter an ending address: (e.g. 254)", "Ending Address")
strSubnet = InputBox("Please enter a subnet excluding the last octet: (e.g. 10.2.1.)", "Subnet")
For i = intStartingAddress to intEndingAddress
strComputer = strSubnet & i
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcess = objWMIService.ExecQuery("Select * From Win32_Process Where Name = 'Explorer.exe'")
For Each objProcess in colProcess
If colProcess.Count > 0 Then
Wscript.Echo strComputer & " Explorer.exe is running."
Else
Wscript.Echo strComputer & " Explorer.exe is not running."
End If
Next
Next
Wscript.Echo "That's all folks!"
What makes you believe that non-Windows computers would respond to WMI queries in the first place? For most non-Windows computers the statement
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
will simply fail, because they don't support WMI (which is short for Windows Management Instrumentation). Because of this error, the objWMIService object remains the same as it was in the previous loop cycle, so your subsequent instructions query the same host you did before. You never see the error, though, because it's masked by the global On Error Resume Next.
This can be mitigated by removing the global On Error Resume Next and changing this loop:
For i = intStartingAddress to intEndingAddress
strComputer = strSubnet & i
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
...
Next
into something like this:
For i = intStartingAddress to intEndingAddress
strComputer = strSubnet & i
Set objWMIService = Nothing
On Error Resume Next
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
On Error Goto 0
If Not objWMIService Is Nothing Then
...
Else
WScript.Echo strComputer & " cannot be accessed."
End If
Next
You can distinguish between unreachable computers and computers that don't appear to be running Windows by combining the above with a ping test:
Set wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_PingStatus WHERE Address='" & strComputer & "'"
For Each ping In wmi.ExecQuery(qry)
reachable = (0 = ping.StatusCode)
Next
If reachable Then
If objWMIService Is Nothing Then
'computer is not running Windows
Else
'computer is running Windows
End If
Else
'computer is offline
End If
First: I would move the colProcess.Count check to occur before the colProcess loop. If there are no collections in the object you will not get an echo response.
Second: I would test for a value within the WMI query such as ProcessID and check if it is Null or if it does have a value, meaning that it is actually running.
intStartingAddress = InputBox("Please enter a starting address: (e.g. 1)", "Starting Address")
intEndingAddress = InputBox("Please enter an ending address: (e.g. 254)", "Ending Address")
strSubnet = InputBox("Please enter a subnet excluding the last octet: (e.g. 10.2.1.)", "Subnet")
For i = intStartingAddress to intEndingAddress
strComputer = strSubnet & i
Set objWMIService = Nothing
On Error Resume Next
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
On Error Goto 0
If objWMIService Is Nothing Then
Wscript.Echo strComputer & " Explorer.exe is not running."
Else
Set colProcess = objWMIService.ExecQuery("Select * From Win32_Process Where Name = 'Explorer.exe'")
If colProcess.Count = 0 Then
Wscript.Echo strComputer & " Explorer.exe is not running."
Else
For Each objProcess in colProcess
If IsNull(objItem.ProcessID) Or Not IsNumeric(objItem.ProcessID) Then
Wscript.Echo strComputer & " Explorer.exe is not running."
Else
Wscript.Echo strComputer & " Explorer.exe is running. (Process ID: " & objItem.ProcessID & ")"
End If
Next
End If
End If
Next
Wscript.Echo "That's all folks!"
EDIT:
Modified Script to take into account the WMI Query will fail on Non-Windows Operating Systems as pointed out by Ansgar Wiechers.
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 = ""
...