Monitor Drive. Using VB Script

2019-01-12 10:51发布

I want to monitor a drive for file changes, using VBScript. I have the below code. It works fine for InstanceCreationEvent and InstanceDeletionEvent. But InstanceModificationEvent is not happening. From googling I got to know we need to use CIM_DataFile instead of CIM_DirectoryContainsFile to monitor InstanceModificationEvent. I am not sure how to modify the code. Can anyone help.

FYI: One script should monitor all the folders and subfolders in a drive.

PS: Any suggestion to improve the code and performance or other ideas also welcome.

My Code:

Dim arrFolders 
Dim strComputer 
Dim objWMIService 
Dim strFolder 
Dim strCommand 
Dim i 
Dim strQuery 

strChangeFile = "MonitorFolder_Log.txt"
strMailIDFile = "MonitorFolder_MailIDs.txt"

'Check if the log file exists, if not ceate a new file and exit the script. Restart the script again.
Set oFSO = CreateObject("Scripting.FileSystemObject")     
If not oFSO.FileExists(strChangeFile)  then
    'WScript.Echo "Change Log File Not Found. Creating new file..."
    Set oTxtFile = oFSO.CreateTextFile(strChangeFile)  
    WScript.Echo strChangeFile & " File Created." & vbCrLf & "Please restart the script." & vbCrLf
    WScript.Quit
End If

'Prompt for which drive should be monitored. If not a valid drive, then exit the script.
strDrive = InputBox("Enter the drive to monitor: " & vbCrLf & "E.g.: Input C to monitor C:\ drive.", "Monitor Folder - Oracle", "E")
If strDrive = "" then
    WScript.Echo "Not a valid drive. Terminating the script."
    WScript.Quit
End If

'Append ":" with the drive name.
strDrive = strDrive & ":"

'Read the mail IDs.
Set objFSOMailID = CreateObject("Scripting.FileSystemObject")
Set oTSMailID = objFSOMailID.OpenTextFile(strMailIDFile)
strMailIDsList = oTSMailID.ReadAll
oTSMailID.close
'WScript.Echo strMailIDsList

'Array to store the existing folder paths that should be monitored.
arrFolders = Array()
i = 0

Set FSO = CreateObject("Scripting.FileSystemObject")
ShowSubfolders FSO.GetFolder(strDrive)

Sub ShowSubFolders(Folder)
    For Each Subfolder in Folder.SubFolders
    i = i + 1
        folderPath = "" & Subfolder.Path & ""
    folderPath = Replace(folderPath ,"\","\\\\")
    ReDim Preserve arrFolders(i)
    arrFolders(i) = folderPath
    'Wscript.Echo i & " " & arrFolders(i)
        ShowSubFolders Subfolder
    Next
End Sub 

'Set the first path to be the drive.
arrFolders(0) = strDrive & "\\\\"

'Use WMI query to get the file changes.
strComputer = "." 
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
'Loop throught the array of folders setting up the monitor for Each 
i = 0 
For Each strFolder In arrFolders 
   'Create the event sink 
   'WScript.Echo "setup for folder: " & strFolder & vbLf
   strCommand = "Set EventSink" & i & " = WScript.CreateObject" & "(""WbemScripting.SWbemSink"", ""SINK" & i & "_"")" 
   ExecuteGlobal strCommand
   'Setup Notification 
   strQuery = "SELECT * " _
           & "FROM __InstanceOperationEvent " _
           & "WITHIN 1 " _
           & "WHERE Targetinstance ISA 'CIM_DirectoryContainsFile'" _
           & "  AND TargetInstance.GroupComponent = " & "'Win32_Directory.Name=""" & strFolder & """'"
   strCommand = "objWMIservice.ExecNotificationQueryAsync EventSink" & i & ", strQuery"
   ExecuteGlobal strCommand 
   'Create the OnObjectReady Sub 
   strCommand = "Sub SINK" & i & "_OnObjectReady(objObject, " &  "objAsyncContext)" & vbLf _
             & "  'Wscript.Echo objObject.TargetInstance.PartComponent" & vbLf _
             & "  SendNotification(objObject)" & vbLf _
             & "End Sub"
   'WScript.Echo strCommand 
   ExecuteGlobal strCommand 
   i = i + 1 
Next 

'Wait for events.
WScript.Echo "Waiting for events..." 
i = 0 
While (True) 
   Wscript.Sleep(1000) 
Wend


Function SendNotification(objObject)

    strEventType = objObject.Path_.Class
    strPartComp = Split(objObject.TargetInstance.PartComponent, "=")
    strFileName = Replace(strPartComp(1), "\\", "\")

    WScript.Echo strEventType
    WScript.Echo strFileName

    'Some more code to send mail and logs...

End Function

1条回答
放荡不羁爱自由
2楼-- · 2019-01-12 11:55

Monitoring the entire filesystem for file creation is not feasible. It will eat up system resources and might severly affect system operation. Only ever monitor selected folders. The following should work:

Const Interval = 1

Set monitor = CreateMonitor("C:\foo")
Do
  Set evt = monitor.NextEvent()
  Select Case evt.Path_.Class
    Case "__InstanceCreationEvent"     : SendNotification evt.TargetInstance
    Case "__InstanceModificationEvent" : ...
    Case "__InstanceDeletionEvent"     : ...
  End Select
Loop

Function CreateMonitor(path)
  Set wmi = GetObject("winmgmts://./root/cimv2")
  Set fso = CreateObject("Scripting.FileSystemObject")

  path = Split(fso.GetAbsolutePathName(path), ":")
  drv  = path(0) & ":"
  dir  = Replace(path(1), "\", "\\")
  If Right(dir, 2) <> "\\" Then dir = dir & "\\"

  query = "SELECT * FROM __InstanceOperationEvent" & _
          " WITHIN " & Interval & _
          " WHERE Targetinstance ISA 'CIM_DataFile'" & _
          " AND TargetInstance.Drive='" & drv & "'" & _
          " AND TargetInstance.Path='" & dir & "'"
  Set CreateMonitor = wmi.ExecNotificationQuery(query)
End Function

Sub SendNotification(tgtInst)
  'send notification
End Sub

You should run monitors for different folders as separate processes, because NextEvent() is a blocking operation.

查看更多
登录 后发表回答