none
VBScript WMI FileSystemWatcher RRS feed

  • Question

  • Hey everybody, I am trying to create a VBscript that will use WMI to monitor a network folder and perform an action when a new file has been added. I am using as a base the code found at http://blogs.technet.com/b/heyscriptingguy/archive/2004/10/11/how-can-i-automatically-run-a-script-any-time-a-file-is-added-to-a-folder.aspx :

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & _
            strComputer & "\root\cimv2")
    Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
        ("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _
            & "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _
                & "TargetInstance.GroupComponent= " _
                    & "'Win32_Directory.Name=""H:\\\\Remote\\\\Remot077""'") ' NOTE -- each slash (\) needs to be FOUR slashes (\\\\)
    Do
    	Wscript.Echo objLatestEvent.TargetInstance.PartComponent
    	
    Loop

    The main problem that I am running into is that according to this page http://www.codeproject.com/Articles/42212/WMI-and-File-System-Monitoring :

     ' When you run the script, you will immediately receive a modification event for
     ' every file in the monitored directory. This is because the way WMI monitoring works –
     ' it first enumerates all the files and their properties, and then polls for changes
     ' within the given interval. This is the reason why it is not a good idea to use WMI
     ' to monitor a large number of files.

    Is there any way that I can make this script NOT enumerate all the existing files on the first pass? Or does anybody have any otherwise creative solutions for how I can circumvent this?

    Thanks,

        Nick

    Friday, April 27, 2012 7:57 PM

Answers

  • This will work with all events and not give you false notifications. 

    ' VBScript source code
    'WMIFileEvents.vbs
    intInterval = "2"
    strDrive = "f:" 
    strFolder = "\\test1\\"
    strComputer = "." 
    Set objWMIService = GetObject( "winmgmts:" & _ 
        "{impersonationLevel=impersonate}!\\" & _ 
        strComputer & "\root\cimv2" )
    strQuery =  _
        "Select * From __InstanceOperationEvent" _
        & " Within " & intInterval _
        & " Where Targetinstance Isa 'CIM_DataFile'" _
        & " And TargetInstance.Drive='" & strDrive & "'" _
        & " And TargetInstance.Path='" & strFolder & "'"
    Set colEvents = objWMIService. ExecNotificationQuery (strQuery) 
    WScript.Echo "Monitoring events...[Ctl-C] to end"
    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" 
                WScript.Echo "Modified: " & objTargetInst.Name
        End Select 
    Loop


    ¯\_(ツ)_/¯


    Saturday, April 28, 2012 9:49 AM

All replies

  • Use Cim_Datafile pointed at the folder you are interested.  This calss will only alert on a file that is being monitored.

    Also the code appears to be completely wrong.

    Here is an example that works.

    #FOr more information see:  http://social.technet.microsoft.com/Forums/en/ITCG/thread/c75c7bbd-4e32-428a-b3dc-815d5c42fd36
    $folder = 'e:\test2'
    $filter = '*.txt'                 
    $fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
         IncludeSubdirectories = $true 
         NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
    }
    $onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
         $path = $Event.SourceEventArgs.FullPath
         $name = $Event.SourceEventArgs.Name
         $changeType = $Event.SourceEventArgs.ChangeType
         $timeStamp = $Event.TimeGenerated
         Write-Host "The file '$name' was $changeType at $timeStamp"
         #Move-Item $path -Destination $destination -Force -Verbose # Force will overwrite files with same name
    }
    #Unregister-Event -SourceIdentifier FileCreated


    ¯\_(ツ)_/¯

    Friday, April 27, 2012 8:18 PM
  • Here is a version in VBScript that works well.

    '==========================================================================
    '
    ' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009
    '
    ' NAME: WMI-FileCreationEvent.vbs
    '
    ' AUTHOR: jv, Designed Systems & Services
    ' DATE  : 12/8/2010
    '
    ' COMMENT: 
    '
    '==========================================================================
    sComputer = "."
    sDrive = "e:"
    sFolders = "\\test2\\"
    Set objWMIService = GetObject("winmgmts:\\" & sComputer & "\root\cimv2")
    Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
        ("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE " _
        & "TargetInstance ISA 'CIM_DataFile' AND " _
        & "TargetInstance.Drive='" & sDrive & "' AND " _
        & "TargetInstance.Path='" & sFolders & "'")
    Wscript.Echo "Begin Monitoring for event..."
    Do
        Set objLatestEvent = colMonitoredEvents.NextEvent
        For Each p In objLatestEvent.TargetInstance.Properties_
            WScript.Echo vbTab & p.Name & ":" & p.Value
        Next
    Loop


    ¯\_(ツ)_/¯

    Friday, April 27, 2012 8:22 PM
  • jv: thanks for your help. This doesn't seem to work on my system...

    I am attempting to monitor the folder named H:\Remote\Remot077 and am using this code

    sComputer = "."
    sDrive = "H:"
    sFolders = "\\Remote\\Remot077"
    Set objWMIService = GetObject("winmgmts:\\" & sComputer & "\root\cimv2")
    Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
        ("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE " _
        & "TargetInstance ISA 'CIM_DataFile' AND " _
        & "TargetInstance.Drive='" & sDrive & "' AND " _
        & "TargetInstance.Path='" & sFolders & "'")
    Wscript.Echo "Begin Monitoring for event..."
    Do
        Set objLatestEvent = colMonitoredEvents.NextEvent
        For Each p In objLatestEvent.TargetInstance.Properties_
            WScript.Echo vbTab & p.Name & ":" & p.Value
        Next
    Loop

    Any thoughts?

    Friday, April 27, 2012 8:33 PM
  • What do you mean it doesn't work.  How does it not work?

    What system are you running?

    Is it possibelthat your WMI is broken.

    Are you running as an administrator?


    ¯\_(ツ)_/¯

    Friday, April 27, 2012 8:58 PM
  • Here is the perferred method for monitoring because it lets the events drive the code instead of sitting in a tight loop trying  to read th collection.  On very fast systems the directmethod is apt to fail due to timeing.  Placing a wait in the code is very useful because the code will suspend and only execute when an event arrives.

    '================e==========================================================
    '
    ' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009
    '
    ' NAME: WMI-SinkFileCreationEvent.vbs
    '
    ' AUTHOR: JV , Designed Systems & Services
    ' DATE  : 12/8/2010
    '
    ' COMMENT: 
    '
    '==========================================================================
    sDrive="e:"
    sFolders="\\test2\\"
    strSQL = "Select * from __InstanceCreationEvent within 1 where TargetInstance isa 'Win32_Process'"
    strSQL="SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE " _
        & "TargetInstance ISA 'CIM_DataFile' AND " _
        & "TargetInstance.Drive='" & sDrive & "' AND " _
        & "TargetInstance.Path='" & sFolders & "'"
    Set objWMIconn = GetObject("winmgmts:\\.\root\CIMV2")
    Set objSink = WScript.CreateObject("WbemScripting.SWbemSink","objSink_")
    objWMIconn.ExecNotificationQueryAsync objSink, strSQL
    WScript.Echo "Waiting for events...."
    Do while(True)
        WScript.Sleep 500
    loop
    Sub objSink_OnObjectReady(objLatestEvent, objWMIAsyncContext)
        For Each p In objLatestEvent.TargetInstance.Properties_
            WScript.Echo vbTab & p.Name & ":" & p.Value
        Next
    End Sub

    The sleep is for  ahalf second.  That will allow the code to be suspended about 99.9% of the time.  It can still receive events while suspended.


    ¯\_(ツ)_/¯

    Friday, April 27, 2012 9:28 PM
  • I looked over your original code.  It desn't run due to some error in the pasting.  I went the TSG site and ran that.  It runs as expected and does not list all files.

    I do not see twhere the article you referenced makes the claim you are making.

    If event code only executes when there is a change.

    When playing with this it is very easy to break WMI.  I recommend periodically rebooting intil you get your code to work reliably.


    ¯\_(ツ)_/¯

    Friday, April 27, 2012 10:18 PM
  • It doesn't work because the event never fires, even when new items are added to the folder. I am running Windows XP (it's a work machine and there is no other option). I am not using the Administrator account. I don't know how I would tell if WMI is "broken."
    Saturday, April 28, 2012 3:03 AM
  • Thanks, will try this also.
    Saturday, April 28, 2012 3:04 AM
  • It definitely lists all the files on my system.

    The article I referenced makes the claim I am making in the last paragraph, before the large yellow-ish text that says "License."

    I might just throw something together that manually compares the contents of the folder over multiple time periods if I can't count on WMI to reliably act ..... reliable.

    Thanks for your assistance,

        --Nick

    Saturday, April 28, 2012 3:08 AM
  • It won't wotk if you are not runniong as an administrator.  YOu have to have sufficient DCOM privileges to use many aspects of WMI.

    You did not post the whole script you were  runnig.  REd teh text more carefully:

     

    The __InstanceModificationEvent class has an additional property called PreviousInstance that you can use to get a copy of the CIM_DataFile instance prior to modification – comparing the TargetInstance and PreviousInstance properties, we can find out which property has changed.


    That is NOT the code you posted.

    I cannot be of much help it you give me the wrong information.


    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 9:18 AM
  • You can poll for events without being an admin but you will always get the initial list.  Just set a flage that ignores the first modification event or check all instances for the write time and throw away all that are not different.

    Note that th e code you psted above was only the instance creation event.  It does not have this issue.  It is only th emodification event that does this and it is by design.  WMI has to build a table of 'previous instances' in order to detect mods.  That is becuse the granularity of the event sink is only at the folder level.  Be carefull about monitoring large sets of files fo mofification as this can ve resource intensive.

    PowerShell uses the Net Framework implementation of the FileWatcher Class.  It is more efficient and does not exhibit this behavior.


    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 9:35 AM
  • This will work with all events and not give you false notifications. 

    ' VBScript source code
    'WMIFileEvents.vbs
    intInterval = "2"
    strDrive = "f:" 
    strFolder = "\\test1\\"
    strComputer = "." 
    Set objWMIService = GetObject( "winmgmts:" & _ 
        "{impersonationLevel=impersonate}!\\" & _ 
        strComputer & "\root\cimv2" )
    strQuery =  _
        "Select * From __InstanceOperationEvent" _
        & " Within " & intInterval _
        & " Where Targetinstance Isa 'CIM_DataFile'" _
        & " And TargetInstance.Drive='" & strDrive & "'" _
        & " And TargetInstance.Path='" & strFolder & "'"
    Set colEvents = objWMIService. ExecNotificationQuery (strQuery) 
    WScript.Echo "Monitoring events...[Ctl-C] to end"
    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" 
                WScript.Echo "Modified: " & objTargetInst.Name
        End Select 
    Loop


    ¯\_(ツ)_/¯


    Saturday, April 28, 2012 9:49 AM
  • This will work with all events and not give you false notifications. 

    ' VBScript source code
    'WMIFileEvents.vbs
    intInterval = "2"
    strDrive = "f:" 
    strFolder = "\\test1\\"
    strComputer = "." 
    Set objWMIService = GetObject( "winmgmts:" &_ 
        "{impersonationLevel=impersonate}!\\" &_ 
        strComputer & "\root\cimv2" )
    strQuery =  _
        "Select * From __InstanceOperationEvent" _
        & " Within " & intInterval _
        & " Where Targetinstance Isa 'CIM_DataFile'" _
        & " And TargetInstance.Drive='" & strDrive & "'"_
        & " And TargetInstance.Path='" & strFolder & "'"
    Set colEvents = objWMIService. ExecNotificationQuery (strQuery) 
    WScript.Echo "Monitoring events...[Ctl-C] to end"
    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" 
                WScript.Echo "Modified: " & objTargetInst.Name
        End Select 
    Loop


    ¯\_(ツ)_/¯

    This does nothing except the print the title "Monitoring events..." .  When I create a new file in the monitored folder, no change in my monitoring window.


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Saturday, April 28, 2012 10:51 PM
  • This does nothing except the print the title "Monitoring events..." .  When I create a new file in the monitored folder, no change in my monitoring window.

    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    It works fine for me everywhere I have tested it. 

    Did you break your computer? Awe...


    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 11:00 PM
  • Just to be sure I went to a completely different system and downloaded the code above - just like a newbie - and ran it.

    Here is what I saw"

    C:\scripts>testevents
    Microsoft (R) Windows Script Host Version 5.7
    Copyright (C) Microsoft Corporation. All rights reserved.

    Monitoring events...[Ctl-C] to end
    Modified: c:\test\new text document (2).txt
    Modified: c:\test\new text document.txt
    Modified: c:\test\primalformsupload.pff
    Modified: c:\test\primalformsupload.zip
    Modified: c:\test\sdw.vbs
    Modified: c:\test\sysinternalssuite.zip
    Deleted: c:\test\new text document (2).txt
    Deleted: c:\test\new text document.txt
    Modified: c:\test\sdw.vbs

    The first time I ran it it appeared to not work.  I went back and looked at the code and noticed this:

    Set objWMIService = GetObject( "winmgmts:" &_
        "{impersonationLevel=impersonate}!\\" &_ 
        strComputer & "\root\cimv2" )

    Note that the _ has no space before it and a space after.  This is not allowed.  I removed the space and added the space thusly....

    Set objWMIService = GetObject( "winmgmts:" & _
        "{impersonationLevel=impersonate}!\\" & _
        strComputer & "\root\cimv2" )

    ...and then reran the code.  'Drat!'  It still doesn't work.  BigTeddy has be by the cajones. 

    I looked again and found I had the folder set to \\test1\\ when, in fact, the folder name is \\test\\.  Hah!  It now works as expected.

    I have  now run this on 4 (5?) different systems so don't just say it doesn't work. 

    Actually, it  is an old example that works almost anywhere as long as we don't post it on the web. The line continuation issue is one reason why I hate the _ and this is one reason why...( of why..oh why) 

    The _ doesn't play fair on web pages.  I usually remove all of the line continuations on downloaded code to avoid this nonsense.  I suspect that this or some other little wart on the implementation is the issue.

    Tune in later for more adventures of the Code Enigma Generator Dude.


    ¯\_(ツ)_/¯



    • Edited by jrv Saturday, April 28, 2012 11:28 PM
    Saturday, April 28, 2012 11:09 PM
  • Richard - all - be careful of copying and pasting with continuation lines.  The HTML colorizer tends to lose and add spaces.

    The code I pasted was tested and it definitely has spaces. I pasted from PrimalScript directly.  Unfortunately the spaces disappear when pasting from PrimalScript.  They do not seem to disappear when pasting from notepad.

    The other thing I noticed is that the HTML colorizer will add an extra character after the underscore.  Sometime it adds two or more.  You need to go in with an editor that will let you see this extra garbage.  Notepad works. PrimalScript works.  Some other editors seem to ignore the extra characters.

    All of this is why I gained the habit of always undoing all continued lines when I first copy from the web.  It seems to save time.


    ¯\_(ツ)_/¯

    Thursday, May 3, 2012 9:55 PM
  • As there has been no activity in this thread for a few days, we assume the issue is resolved. We will mark it as "answered" to assist others in similar situations. If you disagree, please reply with further information. You can unmark the answer if you wish. If a reply helped answer your question, please mark it as the answer.


    Richard Mueller - MVP Directory Services

    Monday, May 7, 2012 10:39 AM
    Moderator
  • HI 

    i  am New to  VB.NET

    can u say the header  for the above script .

    r can u paste the  eniter code with  header  .

    thank u 

    Friday, October 12, 2012 6:39 AM