Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

File Modified, Created, Deleted & Write Text File 1

Status
Not open for further replies.

Nu2Java

Technical User
Jun 5, 2012
166
US
Hello,

I have two pieces of code put together... one for file change notification and the other to write the changes to a text file. How can I modify this to tell me in the output text file which operation it was? Changed, Deleted, Created. Now it places the path and file and then places the date and time.

Thanks for any help!

Code:
strComputer = "."
strDrive = "C:"
strFolder = "\\temp\\"
Dim objFSO, objFolder, objShell, objTextFile, objFile
Dim strDirectory, strFile, strText
strDirectory = "c:\Log Folder"
strFile = "\Change Log.txt"


Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    
Set colProcess = objWMIService.ExecQuery("Select * from Win32_Process where name = 'wscript.exe' or name = 'cscript.exe'")

If colProcess.Count > 1 Then
	'  --- a wscript or cscript process is already running
	WScript.quit
End If

' Create the event sink object that receives the events
Set objSink = wscript.CreateObject("WbemScripting.SWbemSink", "SINK_")

strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
objWMIService.ExecNotificationQueryAsync objSink, "SELECT * FROM __InstanceCreationEvent WITHIN 3 " & _
"Where Targetinstance Isa 'CIM_DataFile' And " & _
"TargetInstance.Drive = '" & strDrive & "' And " & _
"TargetInstance.Path = '" & strFolder & "'"

objWMIService.ExecNotificationQueryAsync objSink, "SELECT * FROM __InstanceModificationEvent WITHIN 3 " & _
"Where Targetinstance Isa 'CIM_DataFile' And " & _
"TargetInstance.Drive = '" & strDrive & "' And " & _
"TargetInstance.Path = '" & strFolder & "'"

objWMIService.ExecNotificationQueryAsync objSink, "SELECT * FROM __InstanceDeletionEvent WITHIN 3 " & _
"Where Targetinstance Isa 'CIM_DataFile' And " & _
"TargetInstance.Drive = '" & strDrive & "' And " & _
"TargetInstance.Path = '" & strFolder & "'"

Done = False

Do While True ' We'll end after first event for this example
	wscript.sleep 1000
Loop

Sub SINK_OnObjectReady(wmiObject, wmiAsyncContext)

strText = wmiObject.TargetInstance.Name
' Create the File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject") 

set objFile = nothing
set objFolder = nothing
' ForAppending = 8 ForReading = 1, ForWriting = 2
Const ForAppending = 8

Set objTextFile = objFSO.OpenTextFile _
(strDirectory & strFile, ForAppending, True)

' Writes strText every time you run this VBScript
objTextFile.WriteLine(strText) & " " & Now
objTextFile.Close

wscript.echo wmiObject.TargetInstance.Name
End Sub
 
A very minor modification to my original example:

Code:
[blue]strComputer = "."
strDrive = "C:"
strFolder = "\\temp\\test\\"

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    
Set colProcess = objWMIService.ExecQuery("Select * from Win32_Process where name = 'wscript.exe' or name = 'cscript.exe'")

If colProcess.Count > 1 Then
	'  --- a wscript or cscript process is already running
	WScript.quit
End If

' Create the event sink object that receives the events
Set objSink = wscript.CreateObject("WbemScripting.SWbemSink", "SINK_")

strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
objWMIService.ExecNotificationQueryAsync objSink, "SELECT * FROM [b][red]__InstanceOperationEvent[/red][/b] WITHIN 3 " & _
"Where Targetinstance Isa 'CIM_DataFile' And " & _
"TargetInstance.Drive = '" & strDrive & "' And " & _
"TargetInstance.Path = '" & strFolder & "'"

Done = False

Do Until Done [green]' We'll end after first event for this example[/green]
	wscript.sleep 1000
Loop

Msgbox "All Done"

Sub SINK_OnObjectReady(wmiObject, wmiAsyncContext)
	[b][red]wscript.echo wmiObject.Path_.Class [green]' what event was it?[/green][/red][/b]
	wscript.echo wmiObject.TargetInstance.Name
	Done = True
End Sub  [/blue]
 
Strongm ... thanks for the help. In addition to what you helped me with before, I found some code to write a log text file. In my code above, the text file logging works when the file changes. The part I am stuck on is how to I get the change event to add to the text file? Was it deleted, modified or created ?

Thanks
 
>Was it deleted, modified or created ?

That's what

wscript.echo wmiObject.Path_.Class

tells you
 
DOH!! That's exactly what it was... I'm learning. Thanks a lot for your time and help. Greatly appreciated!
 
Strongm... Will this also cover "Accessed"? I want to add a "Last Accessed" message as well if possible.

Thanks!
 
I don't see anything that covers the Last Accessed. I am finding other code that talks about this.... I'm stuck.
 
1) Neither Vista nor Windows 7 maintain Date Last Accessed because of the performance hit monitoring and maintaining it causes
2) The general activities that cause Windows versions earlier than Vista to update the Date Last Accessed field are - modification, copying, being moved, deletion. In other words all the stuff you are ALREADY monitoring
3) If you really want to capture when a file was last touched without any of the activities mentioned in 2, then I'm afraid WMI and VBScript are not the tools you want to use.
 
This latest script is working GREAT for me... the only part I want to add 'if possible' is to monitor the SUB folders in "C:\Temp" ?

Thanks for any help!
 
There is no really straightforward way to do this with WMI. However, if we can assume that we already know the names of the subfolder(s) then something like the following change would work:
Code:
[blue]strComputer = "."
strDrive = "C:"
[red][bold]strFolder1 = "\\temp\\test\\"
strFolder2 = "\\temp\\test\\subtest\\"[/bold][/red]

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    
Set colProcess = objWMIService.ExecQuery("Select * from Win32_Process where name = 'wscript.exe' or name = 'cscript.exe'")

If colProcess.Count > 1 Then
	'  --- a wscript or cscript process is already running
	WScript.quit
End If

' Create the event sink object that receives the events
Set objSink = wscript.CreateObject("WbemScripting.SWbemSink", "SINK_")

strComputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
objWMIService.ExecNotificationQueryAsync objSink, "SELECT * FROM __InstanceOperationEvent WITHIN 3 " & _
"Where Targetinstance Isa 'CIM_DataFile' And " & _
"TargetInstance.Drive = '" & strDrive & "' And " & _
[red][bold]"(TargetInstance.Path = '" & strFolder1 & "' Or TargetInstance.Path = '" & strFolder2 &"')"[/bold][/red]

Done = False

Do Until Done [green]' We'll end after first event for this example[/green]
	wscript.sleep 1000
Loop

Msgbox "All Done"

Sub SINK_OnObjectReady(wmiObject, wmiAsyncContext)
	wscript.echo wmiObject.Path_.Class [green]' what event was it?[/green]
	wscript.echo wmiObject.TargetInstance.Name
	Done = True
End Sub[/blue]

However ... even though this appears to be an event-driven solution rather than a polling solution, and thus light on resources it is an unfortunate fact that underneath the covers WMI does actually seem to poll (where the WITHIN statement defines how often to poll). So the more folders you add to be monitored, the bigger the potential performance hit on your PC
 
Strongm ... thanks for the help and time with this. I think what will happen over a short period of time is that new folders will be created each day. Is there a way to create an array as new folders are created in "C:\temp" ? I am just thinking of how I could update this in a more automated way.

Thanks
 
>Is there a way to create an array

Sure. Here's a simplistic solution that just scans a selected folder for subfolders, and would build the relevant part of the notification query (i.e the red bit of the example above).

Code:
[blue]    Dim fred()
    Dim strFolder
    
    strdrive = "c:\\"
    strFolder = "\\temp\\test\\"
       
    ' get the root folder
    Set fsoRoot = CreateObject("Scripting.FileSystemObject").GetFolder(fso.BuildPath(strdrive, strFolder)).SubFolders

    lp = 0
    ReDim Preserve fred(lp)
    fred(lp) = strFolder
    lp = 1
    For Each subfolder In fsoRoot
        ReDim Preserve fred(lp)
        fred(lp) = strFolder & subfolder.Name & "\\"
        lp = lp + 1
    Next
    strTarget = "(TargetInstance.Path = '" & Join(fred, "' OR TargetInstance.Path = '") & "')"
    [green]' strTarget now contains the required TargetInstance.Path part of the query[/green][/blue]


Note that there are some limitations to the number of ORs that WQL (WMI Query Language) can support in a query, so if you have dozens of subfolders it'll probably fail. It'll also probably bring your system to a grinding halt ...
 
Thanks strongm.... I am getting a bit worried now about it taxing the system too hard as I could possibly have 75 or so sub Folders in the main folder.
 
Hmmm - in that case I suspect that you might be trying to use the wrong toolset. You might be better off using .NET's System.IO.FileSytemWatcher, which you can chess through Powershell.

Alternatively you might like to explain the problem you are trying to solve, and maybe we can advise on alternative approaches
 
strongm ... thanks for responding. I might just that out as I have played with the .NET filesystemwatcher a little bit. Being new at this, I have a lot to learn but am excited to learn as much as I can.

Let me explain what I am doing with this, aside of trying to learn more about vbscript. I have a machine that has a simple gantry system which is being controlled by a very generic piece of software. One that is pretty much available to use for controlling just about any CNC machine on the market. The machine software has NO data logging of any kind and it is important to us that we log which programs are run, created, modified or even deleted.

The problem is, the structure of the software creates sub directories for the program files we create. The files that will be changed daily are just text files which does make things a bit easier to deal with.

Any advice you might have is more than welcome and very appreciated. I do have Visual Studio 2010 that I have been using also and maybe if I can get some tips on that then I can try that route.

Thanks
-Mike

 
>you can chess through Powershell

Chess? That's what I get for posting quickly via a tablet with autocorrect. Mind you, not entirely sure what the original word was going to be. Let's go with "access"
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top