VBScript 看门狗
VBScript watchdog
我正在尝试创建一个脚本,该脚本将查看本地计算机上的特定 .txt 文件,获取它的 DateLastModified 属性,并将其与上次检查时的 last/previous 值进行比较(在循环,每 1-2 秒)。
循环(运行 每秒 1 次)会递增一个计数器,如果计数器达到限制(比如 10 秒),一段代码将执行 "kill/terminate" 次任务可能挂掉的具体进程/.exe,重启一下。
我在网上找到了一些使用订阅事件的非常好的 .vbs 示例,我不认为这是我要走的路 want/need,因为脚本实际上需要连续 运行仅当特定文件被修改时才不会异步。
Edit:我正在寻找一个提供 "watchdog" 函数的 VBScript,通过监视 .txt 文件的修改。该脚本应该 运行 每秒循环一次,检查是否有修改,如果没有修改,则增加一个计数器。一旦计数器达到限制(10 秒?),它将终止固定进程(硬编码为 VBScript 中的参数),然后重新启动进程(进程路径作为 VBScript 中的参数)。
到目前为止我还没有找到一个很好的例子来分享。我一直在玩其他使用 objWMIService.ExecNotificationQuery(Query)
的例子,这看起来很酷,因为使用了很少的开销(本质上是异步的)——如上所述,它似乎不符合我的需要。
如果我必须分享我发现和玩弄的东西……好吧……这里是:
intInterval = "1"
strDrive = "C:"
strFolder = "\Project\"
strComputer = "."
intTmrVal = 0
Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\" & strComputer & "\root\cimv2" )
strQuery = "Select * From __InstanceOperationEvent" _
& " Within " & intInterval _
& " Where Targetinstance Isa 'CIM_DataFile'" _
& " And TargetInstance.Name='C:\Project\test.txt'"
Set colEvents = objWMIService.ExecNotificationQuery(strQuery)
Do
Set objEvent = colEvents.NextEvent()
Set objTargetInst = objEvent.TargetInstance
Select Case objEvent.Path_.Class
Case "__InstanceCreationEvent"
WScript.Echo "Created: " & objTargetInst.Name
Case "__InstanceDeletionEvent"
WScript.Echo "Deleted: " & objTargetInst.Name
Case "__InstanceModificationEvent"
Set objPrevInst = objEvent.PreviousInstance
For Each objProperty In objTargetInst.Properties_
If objProperty.Value <> objPrevInst.Properties_(objProperty.Name) Then
WScript.Echo "Changed: " & objTargetInst.Name
WScript.Echo "Property: " & objProperty.Name
WScript.Echo "Previous value: " & objPrevInst.Properties_(objProperty.Name)
WScript.Echo "New value: " & objProperty.Value
End If
Next
End Select
'Count how many times it has been modified // just playing with a counter
If objEvent.TargetInstance.LastModified <> objEvent.PreviousInstance.LastModified Then
intTmrVal = intTmrVal+1
WScript.Echo "Changed: " & intTmrVal & " times"
WScript.Echo
End If
Loop
事件观察者在事件发生时做出反应。但是,您想要对 未发生 的事件做出反应(即文件未被修改)。出于显而易见的原因,您不能为此使用事件观察器。
您需要的是检查文件最后修改日期的代码
path = "C:\Project\test.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
ts = fso.GetFile(path).DateLastModified
然后在时间戳大于 x 时终止给定进程 seconds/minutes
pname = "foo.exe"
wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_Process WHERE Name='" & pname & "'"
If DateDiff("s", ts, Now) > 10 Then
For Each p In wmi.ExecQuery(qry)
p.Terminate
Next
End If
但是,Windows 任务计划程序不支持您希望的 运行 每秒(或每 2 秒)执行一次任务的粒度。即便如此,每秒生成一个新进程首先对系统性能来说也不是很好。您可以设置每日计划,然后指示任务计划程序在一天中每 5 分钟重新运行 任务。其余的你需要在你的脚本中考虑。
定义 5 分钟的超时并重新运行循环检查直到超时到期:
interval = 2 'seconds
timeout = 5 'minutes
endtime = DateAdd("n", timeout, Now)
sleeptime = interval * 1000 'milliseconds
Do
'check and process handling go here
WScript.Sleep sleeptime
Loop Until Now >= endtime
因为 fso
和 wmi
可以重复使用,所以不要通过在循环中一遍又一遍地重新定义它们来浪费资源。在脚本的开头只定义一次。
一个简单的方法是直接在下一个事件的WMI请求中设置超时
Option Explicit
Const MONITOR_FILE = "c:\temp\test.txt"
Const MONITOR_LIMIT = 10
Dim wmi
Set wmi = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\.\root\cimv2" )
Dim query
query = "SELECT * FROM __InstanceOperationEvent WITHIN 1 " _
& " WHERE TargetInstance ISA 'CIM_DataFile' " _
& " AND TargetInstance.Name='" & Replace(MONITOR_FILE, "\", "\") & "'"
Dim colEvents
Set colEvents = wmi.ExecNotificationQuery( query )
Dim currentEvent
Do
' Flag value
Set currentEvent = Nothing
' Try to get the next event with a timeout limit
' If a timeout happens we need to catch raised error
On Error Resume Next
Set currentEvent = colEvents.NextEvent( MONITOR_LIMIT * 1000 )
On Error GoTo 0
' If there is not an event there was a timeout
If currentEvent Is Nothing Then
Exit Do
End If
Loop
WScript.Echo "File has not been changed for " & MONITOR_LIMIT & " seconds."
我正在尝试创建一个脚本,该脚本将查看本地计算机上的特定 .txt 文件,获取它的 DateLastModified 属性,并将其与上次检查时的 last/previous 值进行比较(在循环,每 1-2 秒)。
循环(运行 每秒 1 次)会递增一个计数器,如果计数器达到限制(比如 10 秒),一段代码将执行 "kill/terminate" 次任务可能挂掉的具体进程/.exe,重启一下。
我在网上找到了一些使用订阅事件的非常好的 .vbs 示例,我不认为这是我要走的路 want/need,因为脚本实际上需要连续 运行仅当特定文件被修改时才不会异步。
Edit:我正在寻找一个提供 "watchdog" 函数的 VBScript,通过监视 .txt 文件的修改。该脚本应该 运行 每秒循环一次,检查是否有修改,如果没有修改,则增加一个计数器。一旦计数器达到限制(10 秒?),它将终止固定进程(硬编码为 VBScript 中的参数),然后重新启动进程(进程路径作为 VBScript 中的参数)。
到目前为止我还没有找到一个很好的例子来分享。我一直在玩其他使用 objWMIService.ExecNotificationQuery(Query)
的例子,这看起来很酷,因为使用了很少的开销(本质上是异步的)——如上所述,它似乎不符合我的需要。
如果我必须分享我发现和玩弄的东西……好吧……这里是:
intInterval = "1"
strDrive = "C:"
strFolder = "\Project\"
strComputer = "."
intTmrVal = 0
Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\" & strComputer & "\root\cimv2" )
strQuery = "Select * From __InstanceOperationEvent" _
& " Within " & intInterval _
& " Where Targetinstance Isa 'CIM_DataFile'" _
& " And TargetInstance.Name='C:\Project\test.txt'"
Set colEvents = objWMIService.ExecNotificationQuery(strQuery)
Do
Set objEvent = colEvents.NextEvent()
Set objTargetInst = objEvent.TargetInstance
Select Case objEvent.Path_.Class
Case "__InstanceCreationEvent"
WScript.Echo "Created: " & objTargetInst.Name
Case "__InstanceDeletionEvent"
WScript.Echo "Deleted: " & objTargetInst.Name
Case "__InstanceModificationEvent"
Set objPrevInst = objEvent.PreviousInstance
For Each objProperty In objTargetInst.Properties_
If objProperty.Value <> objPrevInst.Properties_(objProperty.Name) Then
WScript.Echo "Changed: " & objTargetInst.Name
WScript.Echo "Property: " & objProperty.Name
WScript.Echo "Previous value: " & objPrevInst.Properties_(objProperty.Name)
WScript.Echo "New value: " & objProperty.Value
End If
Next
End Select
'Count how many times it has been modified // just playing with a counter
If objEvent.TargetInstance.LastModified <> objEvent.PreviousInstance.LastModified Then
intTmrVal = intTmrVal+1
WScript.Echo "Changed: " & intTmrVal & " times"
WScript.Echo
End If
Loop
事件观察者在事件发生时做出反应。但是,您想要对 未发生 的事件做出反应(即文件未被修改)。出于显而易见的原因,您不能为此使用事件观察器。
您需要的是检查文件最后修改日期的代码
path = "C:\Project\test.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
ts = fso.GetFile(path).DateLastModified
然后在时间戳大于 x 时终止给定进程 seconds/minutes
pname = "foo.exe"
wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_Process WHERE Name='" & pname & "'"
If DateDiff("s", ts, Now) > 10 Then
For Each p In wmi.ExecQuery(qry)
p.Terminate
Next
End If
但是,Windows 任务计划程序不支持您希望的 运行 每秒(或每 2 秒)执行一次任务的粒度。即便如此,每秒生成一个新进程首先对系统性能来说也不是很好。您可以设置每日计划,然后指示任务计划程序在一天中每 5 分钟重新运行 任务。其余的你需要在你的脚本中考虑。
定义 5 分钟的超时并重新运行循环检查直到超时到期:
interval = 2 'seconds
timeout = 5 'minutes
endtime = DateAdd("n", timeout, Now)
sleeptime = interval * 1000 'milliseconds
Do
'check and process handling go here
WScript.Sleep sleeptime
Loop Until Now >= endtime
因为 fso
和 wmi
可以重复使用,所以不要通过在循环中一遍又一遍地重新定义它们来浪费资源。在脚本的开头只定义一次。
一个简单的方法是直接在下一个事件的WMI请求中设置超时
Option Explicit
Const MONITOR_FILE = "c:\temp\test.txt"
Const MONITOR_LIMIT = 10
Dim wmi
Set wmi = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\.\root\cimv2" )
Dim query
query = "SELECT * FROM __InstanceOperationEvent WITHIN 1 " _
& " WHERE TargetInstance ISA 'CIM_DataFile' " _
& " AND TargetInstance.Name='" & Replace(MONITOR_FILE, "\", "\") & "'"
Dim colEvents
Set colEvents = wmi.ExecNotificationQuery( query )
Dim currentEvent
Do
' Flag value
Set currentEvent = Nothing
' Try to get the next event with a timeout limit
' If a timeout happens we need to catch raised error
On Error Resume Next
Set currentEvent = colEvents.NextEvent( MONITOR_LIMIT * 1000 )
On Error GoTo 0
' If there is not an event there was a timeout
If currentEvent Is Nothing Then
Exit Do
End If
Loop
WScript.Echo "File has not been changed for " & MONITOR_LIMIT & " seconds."