Insert Reboot Command in Microsoft Update Script - vb.net

I'm a complete novice in scripting, so starting off just trying to tweak other scripts. I found a script that checks, downloads, and installs Microsoft updates from command line. Is there a way to include a reboot command when complete, or perhaps daisy chain or pipe in a command after it?
To run it, you type cscript.exe ForceAU.vbs
Is there a way to add a command (shutdown /r) to/after it, or does it have to be a setting in the script itself?
'************************************
'* Force Automatic Update Script *
'* Goto http://www.intelliadmin.com *
'* for more tools and utilities *
'************************************
' This script was adapted to only
' install non-prompting updates
' and not ask any questions
' Original script can be found here:
' http://msdn.microsoft.com/en-us/library/windows/desktop/aa387102(v=vs.85).aspx
On Error Resume Next
function IsSecurityUpdate(Update)
Set Categories = Update.Categories
sName = lcase(Categories.Item(0).Name)
'This works on all languages...the category name is always in english
if (sName = "security updates" or sName="critical updates") then
IsSecurityUpdate = TRUE
else
IsSecurityUpdate = FALSE
end if
end function
Sub ForceUpdate()
Set updateSession = CreateObject("Microsoft.Update.Session")
Set updateSearcher = updateSession.CreateupdateSearcher()
WScript.Echo "Searching for updates..." & vbCRLF
Set searchResult = updateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
WScript.Echo vbCRLF & "Creating collection of updates to download:"
Set updatesToDownload = CreateObject("Microsoft.Update.UpdateColl")
bFound = FALSE
For I = 0 to searchResult.Updates.Count-1
Set update = searchResult.Updates.Item(I)
If IsSecurityUpdate(update) then
WScript.Echo " " & update.Title
updatesToDownload.Add(update)
bFound = TRUE
end if
Next
if (NOT(bFound)) then
WScript.Echo "This computer is up to date"
Exit Sub
end if
WScript.Echo vbCRLF & "Downloading updates..."
Set downloader = updateSession.CreateUpdateDownloader()
downloader.Updates = updatesToDownload
downloader.Download()
WScript.Echo vbCRLF & "List of downloaded updates:"
For I = 0 To searchResult.Updates.Count-1
Set update = searchResult.Updates.Item(I)
If update.IsDownloaded Then
WScript.Echo I + 1 & "> " & update.Title
End If
Next
Set updatesToInstall = CreateObject("Microsoft.Update.UpdateColl")
WScript.Echo vbCRLF & _
"Creating collection of downloaded updates to install:"
For I = 0 To searchResult.Updates.Count-1
set update = searchResult.Updates.Item(I)
If update.IsDownloaded = true Then
if (IsSecurityUpdate(update)) then
WScript.Echo I + 1 & "> adding: " & update.Title
updatesToInstall.Add(update)
end if
End If
ext
WScript.Echo "Installing updates..."
Set installer = updateSession.CreateUpdateInstaller()
installer.Updates = updatesToInstall
Set installationResult = installer.Install()
'Output results of install
WScript.Echo "Installation Result: " & _
installationResult.ResultCode
WScript.Echo "Reboot Required: " & _
installationResult.RebootRequired & vbCRLF
WScript.Echo "Listing of updates installed " & _
"and individual installation results:"
For I = 0 to updatesToInstall.Count - 1
WScript.Echo I + 1 & "> " & _
updatesToInstall.Item(i).Title & _
": " & installationResult.GetUpdateResult(i).ResultCode
Next
end sub
ForceUpdate()
if (Err.Number<>0) then
WScript.Echo "Error Downloading Updates. Check your internet connection"
end if

You can try to execute "shutdown -r -t 5" will reboot after 5 seconds.
Maybe something like this:
Set oShell = WScript.CreateObject("WSCript.shell")
oShell.run "cmd shutdown -r -t 5"

Related

vbs script upload only the file name without inside data

The problem of this script is that it shows an unknown error Message while running the script.
I called the function by echo method in my ftp which is "filezilla".
every thing is working fine as it logs into the server check for the path, open channel for data writing. Still dont know where is the problem
Function FTPUpload(sSite, sUsername, sPassword, sLocalFile, sRemotePath)
'This script is provided under the Creative Commons license located
'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
'be used for commercial purposes with out the expressed written consent
'of NateRice.com
Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const ForReading = 1
Const ForWriting = 2
Set oFTPScriptFSO = CreateObject("Scripting.FileSystemObject")
Set oFTPScriptShell = CreateObject("WScript.Shell")
sRemotePath = Trim(sRemotePath)
sLocalFile = Trim(sLocalFile)
'----------Path Checks---------
'Here we willcheck the path, if it contains
'spaces then we need to add quotes to ensure
'it parses correctly.
If InStr(sRemotePath, " ") > 0 Then
If Left(sRemotePath, 1) <> """" And Right(sRemotePath, 1) <> """" Then
sRemotePath = """" & sRemotePath & """"
End If
End If
If InStr(sLocalFile, " ") > 0 Then
If Left(sLocalFile, 1) <> """" And Right(sLocalFile, 1) <> """" Then
sLocalFile = """" & sLocalFile & """"
End If
End If
'Check to ensure that a remote path was
'passed. If it's blank then pass a "\"
If Len(sRemotePath) = 0 Then
'Please note that no premptive checking of the
'remote path is done. If it does not exist for some
'reason. Unexpected results may occur.
sRemotePath = "\"
End If
'Check the local path and file to ensure
'that either the a file that exists was
'passed or a wildcard was passed.
If InStr(sLocalFile, "*") Then
If InStr(sLocalFile, " ") Then
FTPUpload = "Error: Wildcard uploads do not work if the path contains a " & _
"space." & vbCRLF
FTPUpload = FTPUpload & "This is a limitation of the Microsoft FTP client."
Exit Function
End If
ElseIf Len(sLocalFile) = 0 Or Not oFTPScriptFSO.FileExists(sLocalFile) Then
'nothing to upload
FTPUpload = "Error: File Not Found."
Exit Function
End If
'--------END Path Checks---------
'build input file for ftp command
sFTPScript = sFTPScript & "USER " & sUsername & vbCRLF
sFTPScript = sFTPScript & sPassword & vbCRLF
sFTPScript = sFTPScript & "cd " & sRemotePath & vbCRLF
sFTPScript = sFTPScript & "binary" & vbCRLF
sFTPScript = sFTPScript & "prompt n" & vbCRLF
sFTPScript = sFTPScript & "put " & sLocalFile & vbCRLF
sFTPScript = sFTPScript & "quit" & vbCRLF & "quit" & vbCRLF & "quit" & vbCRLF
sFTPTemp = oFTPScriptShell.ExpandEnvironmentStrings("%TEMP%")
sFTPTempFile = sFTPTemp & "\" & oFTPScriptFSO.GetTempName
sFTPResults = sFTPTemp & "\" & oFTPScriptFSO.GetTempName
'Write the input file for the ftp command
'to a temporary file.
Set fFTPScript = oFTPScriptFSO.CreateTextFile(sFTPTempFile, True)
fFTPScript.WriteLine(sFTPScript)
fFTPScript.Close
Set fFTPScript = Nothing
oFTPScriptShell.Run "%comspec% /c FTP -n -s:" & sFTPTempFile & " " & sSite & _
" > " & sFTPResults, 0, TRUE
Wscript.Sleep 1000
'Check results of transfer.
Set fFTPResults = oFTPScriptFSO.OpenTextFile(sFTPResults, ForReading, _
FailIfNotExist, OpenAsDefault)
sResults = fFTPResults.ReadAll
fFTPResults.Close
oFTPScriptFSO.DeleteFile(sFTPTempFile)
oFTPScriptFSO.DeleteFile (sFTPResults)
If InStr(sResults, "226 Transfer complete.") > 0 Then
FTPUpload = True
ElseIf InStr(sResults, "File not found") > 0 Then
FTPUpload = "Error: File Not Found"
ElseIf InStr(sResults, "cannot log in.") > 0 Then
FTPUpload = "Error: Login Failed."
Else
FTPUpload = "Error: Unknown."
End If
Set oFTPScriptFSO = Nothing
Set oFTPScriptShell = Nothing
WScript.Echo "Process Completed (" & Now & ")"
End Function

VB script + delete files that contain word and older then X month

the following VB script , will remove the files under Temp dir and contain the word access.log
how to change this VB script in order to remove only files that contain the word "access.log" and are old then 1 or 2 or 3 ... month
I want to add in the VB some parameter that will contain the month Number
and the files will be deleted according to this parameter
for example if Month_do_del=12
Then only files that contain access.log that old then 12 month will be deleted
If LCase(Right(Wscript.FullName, 11)) = "wscript.exe" Then
strPath = Wscript.ScriptFullName
strCommand = "%comspec% /k cscript """ & strPath & """"
Set objShell = CreateObject("Wscript.Shell")
objShell.Run(strCommand), 1, True
Wscript.Quit
End If
Set objNetwork = CreateObject("WScript.Network")
strLog = "Files deleted on " & objNetwork.ComputerName & " at " & Now & VbCrLf & "===================================================="
Set objFSO = CreateObject("Scripting.FileSystemObject")
strFilesToDelete = ""
ShowSubFolders objFSO.GetFolder("G:\Temp")
If InStr(strFilesToDelete, "|") > 0 Then
arrFiles = Split(strFilesToDelete, "|")
For Each strFilePath In arrFiles
DeleteFile strFilePath
Next
ElseIf strFilesToDelete <> "" Then
DeleteFile strFilesToDelete
Else
WScript.Echo "No files were found."
strLog = strLog & VbCrLf & "No files were found."
End If
Set objLogFile = objFSO.CreateTextFile("C:\FileDeletionLog.log", True)
objLogFile.Write strLog
objLogFile.Close
Set objLogFile = Nothing
Sub ShowSubFolders(Folder)
On Error Resume Next
For Each objFile In Folder.Files
If Err.Number <> 0 Then
WScript.Echo "Error reading " & Folder.Path
strLog = strLog & VbCrLf & "Error reading " & Folder.Path
Err.Clear
On Error Resume Next
Exit For
Else
On Error GoTo 0
If Instr(UCase(objFile.Name), UCase ("access.log")) Then
If strFilesToDelete = "" Then
strFilesToDelete = objFile.Path
Else
strFilesToDelete = strFilesToDelete & "|" & objFile.Path
End If
End If
End If
Next
For Each Subfolder in Folder.SubFolders
ShowSubFolders Subfolder
Next
End Sub
Sub DeleteFile(strFilePath)
On Error Resume Next
WScript.Echo "Deleting " & strFilePath
objFSO.DeleteFile strFilePath, True
If Err.Number <> 0 Then
WScript.Echo "Could not delete " & strFilePath
strLog = strLog & VbCrLf & "Could not delete " & strFilePath
Err.Clear
On Error GoTo 0
Else
On Error GoTo 0
strLog = strLog & VbCrLf & "Successfully deleted " & strFilePath
End If
End Sub
I don't know if FileDateTime, Date and DateDiff are supported in VBS. If not you can easily port your VBS code to VBA. DateDiff will find the difference between two dates in months.
Function CheckMonths(nMonths As Integer, fPath As String) As Boolean
CheckMonths = False
If DateDiff("m", FileDateTime(fPath), Date) = nMonths Then
CheckMonths = True
End If
End Function
Change this line
If Instr(UCase(objFile.Name), UCase ("access.log")) Then
to this
If Instr(1, UCase(objFile.Name), UCase("access.log")) And DateDiff("m", objFile.DateLastModified, Date) >= 12 Then

Run command prompt commands as admin

I can use the following code to run a command from vba in the command prompt window
Private Sub CMDTest()
'command for cmd to execute
Dim command As String
command = "dir"
Call Shell("cmd.exe /S /K" & command)
End Sub
However it does not run with admin privileges. If command was something that required administrative privileges, how can I run it from vba with administrative privileges?
I have tried to used ShellExecute various ways and have had no luck. The code I used is below, I can open the command prompt window as an admin, however can not run the dir command.
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Const SW_SHOWNORMAL = 1
Public Sub test()
ShellExecute 0, "runas", "cmd.exe", "", vbNullString, SW_SHOWNORMAL
End Sub
Well, I may be late! say it is for the record :) Trying to answer the same question, the other topics I've read do not mention vba so I propose here a way to do it.
What it does: run wsshl from vba that opens a cmd prompt that test
current user rights, if not admin then it opens a powershell window
that opens a cmd prompt in admin mode that runs some cmd line
arguments... in one go (late binding, just msdos)
The trick: instead of running an external batch file or else, all
command are send in assembly line using dos & operator.
The problem: VBA wont wait for the last opened cmd window
(asynchrone) so I added... another cmd prompt to serve as 'waitonrun'
but also to check that no terrible thing happened. If there is no
need to wait or verify anything, they can be 'released'.
How it works: Enter your cmd arguments in mycmd variable, it can be
parametrized with vba variables, and run/compile. the UAC will prompt
to open a cmd window in admin mode and then follow the instructions.
Other possible use: use psargsList="echo." in psmeth 2, access to
last cmd prompt (admin mode) will be granted if you want to type
other commands instead of sending a bunch of arguments. In that case
the 'waitonrun' prompt allow to pause vba until you finished.
Here an example to take back ownership of a file using icacls.
Sub acmd()
'--------
'settings
'--------
Dim output As String: output = Environ("userprofile") & "\Desktop\test.txt" ' a file
Dim mycmd As String: mycmd = "icacls " & output & " /grant %username%:F " 'an msdos cmd to run as admin
'---------
'2 methods
'---------
'exact same versions but different syntax, the first is shorter, the second uses -ArgumentList argument of powershell that can be usefull in other cases
'note: first run of powershell may take some time
Dim psmeth As Long: psmeth = 1 '2
Dim psargsList As String, psargs As String
'------
'layout
'------
'trying to lighten a bit the expression and the cmd prompt
'msg could also be other cmd arguments
Dim msg1 As String, msg2 As String, msg3 As String
msg1 = "echo.& echo.""- listing files with ownership"" & echo."
msg2 = "echo.& echo.""- applying cmd"" & echo.& echo. "
msg3 = "echo.& echo.""Done! now press [enter]"" & echo."
With CreateObject("wScript.Shell")
If psmeth = 1 Then
'add an msdos '&' between msdos args and cut the vba string with a vba '&' where you want to insert vba variables
'from the last cmd point of view it will be the same cmd line, a succession of cmd arg1 & arg2 & arg3, the 'encapsulation' between \"""" is a bit more tricky
'there are some warnings you can see when using -noexit after powershell cmd but it doesn't seems to hurt
psargs = msg1 & " & dir " & output & " /q & " & msg2 & " & " & mycmd & " & " & msg3 & " & pause"
.Run "cmd /c net session >nul 2>&1 & if ERRORLEVEL 1 ( Powershell -Command ""& { Start-Process cmd.exe \""""/c " & psargs & "\"""" -verb RunAs -wait }"" )", 1, True ' 3rd win only? ok too; add -noexit after Powershell to see warnings
ElseIf psmeth = 2 Then
'based on same principle, it works also with powershell's -ArgumenList 'arg1','& arg2','& arg3',.. syntax, there is a little less escaping but it needs to open a '4th' cmd window with /k (and VBA wont wait for it!) so that it doesn't close and runs cmd line args in assembly line
'the cuts '...', are arbitrary, then inside them cut the vba string to insert vba variables
psargsList = "-ArgumentList 'cmd /k ','" & msg1 & " & echo. &','dir " & output & " /q ',' & echo. & " & msg2 & "',' & " & mycmd & " ','& " & msg3 & " & pause ','& exit'"
.Run "cmd /c net session >nul 2>&1 & if ERRORLEVEL 1 ( Powershell -Command ""& { Start-Process cmd.exe " & psargsList & " -verb RunAs -wait }"" )", 1, True
End If
If psmeth = 1 Or psmeth = 2 Then
'we need some 'waitonrun', here a simple confirmation window
.Run "cmd /c tasklist |find ""cmd.exe"" >nul && (set /p""= Holding on VBA till you close admin windows. Press [enter] when ready"" & taskkill /f /im ""cmd.exe"") || echo. ""dummy"">nul", 1, True
End If
End With
'------------------
Debug.Print "-end-"
'------------------
End Sub
What you are doing should work. Here is a helper I have used.
Private Sub RunAsAdmin(ByVal command As String, ByVal parameters As String)
ShellExecute 0, "runas", command, parameters, vbNullString, SW_SHOWNORMAL
End Sub
This vbsscript, compatable with VBA, runs a verb from right click menu on a file. Programs have RunAs to elevate to admins on their menus.
HelpMsg = vbcrlf & " ShVerb" & vbcrlf & vbcrlf & " David Candy 2014" & vbcrlf & vbcrlf & " Lists or runs an explorer verb (right click menu) on a file or folder" & vbcrlf & vbcrlf & " ShVerb <filename> [verb]" & vbcrlf & vbcrlf & " Used without a verb it lists the verbs available for the file or folder" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The program lists most verbs but only ones above the first separator" & vbcrlf & " of the menu work when used this way" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The Properties verb can be used. However the program has to keep running" & vbcrlf & " to hold the properties dialog open. It keeps running by displaying" & vbcrlf & " a message box."
Set objShell = CreateObject("Shell.Application")
Set Ag = WScript.Arguments
set WshShell = WScript.CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
If Ag.count = 0 then
wscript.echo " ShVerb - No file specified"
wscript.echo HelpMsg
wscript.quit
Else If Ag.count = 1 then
If LCase(Replace(Ag(0),"-", "/")) = "/h" or Replace(Ag(0),"-", "/") = "/?" then
wscript.echo HelpMsg
wscript.quit
End If
ElseIf Ag.count > 2 then
wscript.echo vbcrlf & " ShVerb - To many parameters" & vbcrlf & " Use quotes around filenames and verbs containing spaces" & vbcrlf
wscript.echo HelpMsg
wscript.quit
End If
If fso.DriveExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetFileName(Ag(0)))
' Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Set objFolderItem = objFolder.self
msgbox ag(0)
ElseIf fso.FolderExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
ElseIf fso.fileExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Else
wscript.echo " ShVerb - " & Ag(0) & " not found"
wscript.echo HelpMsg
wscript.quit
End If
Set objVerbs = objFolderItem.Verbs
'If only one argument list verbs for that item
If Ag.count = 1 then
For Each cmd in objFolderItem.Verbs
If len(cmd) <> 0 then CmdList = CmdList & vbcrlf & replace(cmd.name, "&", "")
Next
wscript.echo mid(CmdList, 2)
'If two arguments do verbs for that item
ElseIf Ag.count = 2 then
For Each cmd in objFolderItem.Verbs
If lcase(replace(cmd, "&", "")) = LCase(Ag(1)) then
wscript.echo(Cmd.doit)
Exit For
End If
Next
'Properties is special cased. Script has to stay running for Properties dialog to show.
If Lcase(Ag(1)) = "properties" then
WSHShell.AppActivate(ObjFolderItem.Name & " Properties")
msgbox "This message box has to stay open to keep the " & ObjFolderItem.Name & " Properties dialog open."
End If
End If
End If

Can't define f.WriteLine (vbscript)

I want to log my windows updates script, but I get the following error.
800a005b object variable not setline: 28, 1
which refers to:
f.WriteLine 'some text here'
I also tried Dim f.WriteLine and Dim f, neither of which solve my problem.
What should I do to resolve this?
Full code:
set test = CreateObject("Scripting.FileSystemObject")
set f = fso.CreateTextFile(write_to_File,8)
Dim fso
Set fso = WScript.CreateObject("Scripting.Filesystemobject")
Set f = fso.OpenTextFile("C:\output.txt", 2)
f.Close
'End of Script
'ServerSelection values
ssDefault = 0
ssManagedServer = 1
ssWindowsUpdate = 2
ssOthers = 3
strComputer = "." ' Local Computer
'InStr values
intSearchStartChar = 1
dim strTitle
Set updateSession = CreateObject("Microsoft.Update.Session")
Set updateSearcher = updateSession.CreateupdateSearcher()
updateSearcher.ServerSelection = ssWindowsUpdate
Set searchResult = updateSearcher.Search("IsInstalled=0 and Type='Software'")
f.WriteLine "Lijst met beschikbare updates op deze machine:"
For I = 0 To searchResult.Updates.Count-1
Set update = searchResult.Updates.Item(I)
WScript.Echo I + 1 & "> " & update.Title
Next
If searchResult.Updates.Count = 0 Then
f.WriteLine "Er zijn geen updates beschikbaar."
WScript.Quit
End If
f.WriteLine vbCRLF & "Aanmaken lijst met te downloaden updates:"
Set updatesToDownload = CreateObject("Microsoft.Update.UpdateColl")
For I = 0 to searchResult.Updates.Count-1
Set update = searchResult.Updates.Item(I)
addThisUpdate = false
If update.InstallationBehavior.CanRequestUserInput = true Then
WScript.Echo I + 1 & "> skipping: " & update.Title & _
" because it requires user input"
Else
If update.EulaAccepted = false Then
WScript.Echo I + 1 & "> note: " & update.Title & _
" has a license agreement that must be accepted:"
WScript.Echo update.EulaText
update.AcceptEula()
addThisUpdate = false
Else
addThisUpdate = false
End If
End If
If addThisUpdate = true Then
WScript.Echo I + 1 & "> adding: " & update.Title
updatesToDownload.Add(update)
End If
Next
If updatesToDownload.Count = 0 Then
f.WriteLine "All applicable updates were skipped."
WScript.Quit
End If
f.WriteLine vbCRLF & "Downloading updates..."
Set downloader = updateSession.CreateUpdateDownloader()
downloader.Updates = updatesToDownload
downloader.Download()
Set updatesToInstall = CreateObject("Microsoft.Update.UpdateColl")
rebootMayBeRequired = false
f.WriteLine vbCRLF & "Successfully downloaded updates:"
For I = 0 To searchResult.Updates.Count-1
set update = searchResult.Updates.Item(I)
If update.IsDownloaded = true Then
WScript.Echo I + 1 & "> " & update.Title
updatesToInstall.Add(update)
If update.InstallationBehavior.RebootBehavior > 0 Then
rebootMayBeRequired = true
End If
End If
Next
If updatesToInstall.Count = 0 Then
f.WriteLine "No updates were successfully downloaded."
WScript.Quit
End If
If rebootMayBeRequired = true Then
f.WriteLine vbCRLF & "These updates may require a reboot."
End If
f.WriteLine "Installing updates..."
Set installer = updateSession.CreateUpdateInstaller()
installer.Updates = updatesToInstall
Set installationResult = installer.Install()
'Output results of install
f.WriteLine "Installation Result: " & _
installationResult.ResultCode
f.WriteLine "Reboot Required: " & _
installationResult.RebootRequired & vbCRLF
f.WriteLine "Listing of updates installed " & _
"and individual installation results:"
For I = 0 to updatesToInstall.Count - 1
WScript.Echo I + 1 & "> " & _
updatesToInstall.Item(i).Title & _
": " & installationResult.GetUpdateResult(i).ResultCode
Next
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\" & _
strComputer & "\root\cimv2")
Set colOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each objOS in colOS
objOS.Reboot()
Next
This code should enable you to use writeline, my example is to a log file
Firstly set test to be a "Scripting.FileSystemObject"
Next set your f to equal test and test points to a log file location (write_to_file), and append to it using value 8
Finally use the f.writeline line to write strings to the log file
set test = CreateObject("Scripting.FileSystemObject")
set f = test.OpenTextFile(write_to_File,8)
f.writeline "Some text here"

Monitor Drive. Using VB Script

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
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.