I'm using the following code to rotate log files. If the Log.txt file is different than the current date-time (based on file property .DateCreated), the file is moved using the .DateCreated value to rename it and then a new Log.txt file is created but the new file date created value is the same as the moved (archived) file.
If the script is run again a few seconds later it fails to move the Log.txt file as an archived version already exist.
Option Explicit
Dim objFS: Set objFS = CreateObject("Scripting.FileSystemObject")
Dim strLogPath: strLogPath = "C:\Logs"
Dim strLogFQFN: strLogFQFN = objFS.BuildPath(strLogPath, "Log.txt")
If objFS.FileExists(strLogFQFN) <> True Then
WScript.Quit
End If
'As file exists, validate if archive is needed
Dim objFile: Set objFile = objFS.GetFile(strLogFQFN)
Dim dtmLog: dtmLog = objFile.DateCreated'DateValue(objFile.DateCreated)
Dim dtmNow: dtmNow = Now 'Date
Set objFile = Nothing
WScript.Echo dtmLog
WScript.Echo dtmNow
If (dtmLog <> dtmNow) Then
Dim tsDate: tsDate = DatePart("yyyy", dtmLog) & "-" & Right("0" & DatePart("m", dtmLog), 2) & "-" & Right("0" & DatePart("d", dtmLog), 2)
Dim tsTime : tsTime = Right("0" & Hour(dtmLog), 2) & Right("0" & Minute(dtmLog), 2) & Right("0" & Second(dtmLog), 2)
Call objFS.MoveFile(strLogFQFN, objFS.BuildPath(strLogPath, tsDate & "T" & tsTime & ".txt"))
Call objFS.CreateTextFile(strLogFQFN, False)
End If
1st run - Original file Log.txt moved to 2022-03-11T014931.txt and new Log.txt created
1st and 2nd run date-time values and error
Thanks
Based on LesFerch comment I have tested adding a delay of 16 seconds to overcome the default Tunneling cache time and that resolved the issue using the C drive.
Call objFS.MoveFile(strLogFQFN, objFS.BuildPath(strLogPath, tsDate & "T" & tsTime & ".txt"))
WScript.Sleep 16000
Call objFS.CreateTextFile(strLogFQFN, False)
Related
The script I have here is attempting to do recurse through an XML file, storing each RegEx match (stored in a search array) into 2 result arrays; 1 for start date, 1 for end date.
Ubounds of both arrays are checked for equality then the text is passed to a function that uses XMLDOM to find the End_Date node in each parent node, then passes that text to another function, adding 30 days and then passing it back, replacing the previous value. Then it's supposed to write back the contents to the file and save it.
I've got a few problems here. 1. I can't get the +30 day value to be passed back to anything past the first parent node--memory space seems to retain the +30 day value from previous For-Each iteration. 2. I can't write anything back to the file.
I was initially writing for text files, but the format changed to XML as the requirements changed on our project.
I'd love to be able to do this all in XMLDOM in vbscript and just use functions to do specific data changes. But my main concern is my sloppy script not doing the basics.
Can anyone help me by pointing out the flaws in the loops I'm running? I've hit a wall and just can't seem to make any more progress!
Here's the XML file I'm reading(shortened to 2 Ad nodes w/ a ton of child nodes removed):
<?xml version="1.0" encoding="utf-8"?>
<XMLFeederRoot>
<ADS_CREATE_TIME>2016-06-07T01:35:39</ADS_CREATE_TIME>
<Ad>
<Ad_Number>d00524224</Ad_Number>
<Start_Date>2016-08-20T00:00:00</Start_Date>
<End_Date>2016-08-20T00:00:00</End_Date>
<Status>Run</Status>
</Ad><Ad>
<Ad_Number>d00524225</Ad_Number>
<Start_Date>2016-08-20T00:00:00</Start_Date>
<End_Date>2016-08-20T00:00:00</End_Date>
<Status>Run</Status>
</Ad>
</XMLFeederRoot>
Here's the script:
'Setting the Regular Expression object and setting occurrences to all in strings searched.
Set objRegEx= CreateObject("VBScript.RegExp")
objRegEx.Global= True
set Shell= createobject("wscript.shell")
Dim FSO, FLD, FIL, TS, strDate, strEDat, i, d, c
Dim strFolder, strContent, strPath
Const ForReading= 1, ForWriting= 2
strFolder= "C:\Scripts\Run"
Set FSO= CreateObject("Scripting.FileSystemObject")
'Get a reference to the folder you want to search
set FLD= FSO.GetFolder(strFolder)
'loop through the folder and get the files
For Each Fil In FLD.Files
'Open the file to read
Set TS= FSO.OpenTextFile(fil.Path, ForReading)
'Read the contents into a variable
strContent= TS.ReadAll
'Close the file
TS.Close
reDim arrMR(1,1)
arrMR(0,0)= "(\s+)(<Start_Date>(.*?)<\/Start_Date>)"
arrMR(1,0)= "(\s+)(<End_Date>(.*?)<\/End_Date>)"
For i= 0 to Ubound(arrMR)
objRegEx.Pattern= arrMR(i,0)
Set objMatches= objRegEx.Execute(strContent)
d=0
For Each objMatch in objMatches
If i= 0 Then
If d>0 Then
reDim Preserve arrStart(d)
Else
reDim arrStart(d)
End If
arrStart(d)= objMatches.Item(d).SubMatches(2)
'Wscript.Echo arrStart(d)
ElseIf i<> 0 Then
If d>0 Then
reDim Preserve arrEnd(d)
ReDim Preserve arrMatch1(d)
Else
reDim arrEnd(d)
ReDim arrMatch1(d)
End If
arrEnd(d)= objMatches.Item(d).SubMatches(2)
arrMatch1(d)= objMatches.Item(d).SubMatches(1)
End If
If objRegEx.Pattern<> arrMR(0,0) Then
If (ubound(arrStart)= ubound(arrEnd)) Then
'Wscript.Echo "Ubounds Match"
Parse strContent
strContent= Parse(strContent)
Else
'Wscript.Echo "Start & End Dates do not match"
End If
End If
d= d+ 1 'increment to next match
Next
Next
'Close the file
TS.Close
'Open the file to overwrite the contents
Set TS= FSO.OpenTextFile(fil.Path, ForWriting)
'Write the contents back
TS.Write strContent
'Close the current file
TS.Close
Next
'Clean up
Set TS= Nothing
Set FLD= Nothing
Set FSO= Nothing
Function Parse(ParseContent)
'Dim sFSpec : sFSpec = FSO.GetAbsolutePathName("C:\Users\j.levine\Desktop\XML Feeder Scripts\Test_Files\monvid.txt")
Dim oXML : Set oXML = CreateObject("Msxml2.DOMDocument.6.0")
Dim strXMLSDat, strXMLarrStartD, XMLEDat
oXML.setProperty "SelectionLanguage", "XPath"
oXML.async = False
oXML.loadXML(ParseContent)
If 0 = oXML.parseError Then
Dim sXPath3 : sXPath3 = "//XMLFeederRoot/Ad[End_Date=Start_Date]"
Dim ndlFnd : Set ndlFnd = oXML.selectNodes(sXPath3)
If 0 = ndlFnd.length Then
WScript.Echo sXPath, "not found"
ElseIf 0<> ndlFnd.length Then
'WScript.Echo "found", ndlFnd.length, "nodes for", sXPath
Dim ndCur, oldNode
For Each ndCur In ndlFnd
oldNode = oXML.selectsinglenode("//End_Date").text
oldNode= XMLSplitArray(oldNode) 'Pass current Date into Array and add 30 days & return as node text
Set newNode= oXML.selectSingleNode("//End_Date")
newNode.text= oldNode
WScript.Echo ndCur.xml
Next
'WScript.Echo "We have nothing to replace"
End If
Else
WScript.Echo oXML.parseError.reason
End If
Parse= ParseContent
End Function
Function XMLSplitArray(strval1)
dim XmlSA, XmlSA2, XMLEDat
XmlSA = split(strval1, "-")
XmlSA(2) = Left(XmlSA(2), 2)
strXMLDate = XmlSA(1) & "/" & XmlSA(2) & "/" & XmlSA(0)
strXMLDate30 = DateAdd("d", 30, strXMLDate)
XmlSA2 = split(strXMLDate30, "/")
'Add zero to the left
XmlSA2(0)= Right("0" & XmlSA2(0), 2)
XmlSA2(1)= Right("0" & XmlSA2(1), 2)
XmlSA2(1) = XmlSA2(1) & "T00:00:00"
XMLEDat = XmlSA2(2) & "-" & XmlSA2(0) & "-" & XmlSA2(1)
XMLSplitArray= XMLEDat
End Function
Thomas was right w/ the KISS method. I took a big step back, and started over.
Here's what I've come up with. It does what I need regarding the Date+30 and writing back to a file. I think this method is cleaner and will allow me to run my other text massaging through functions.
My questions about this new script are:
1. can this be done without having to write to a new file? Keeping to 1 file is easier.
2. Can I avoid cloning the node and deleting the original one and directly change the original node's value?
3. I seem to be missing how to get that last node <Status> onto it's own line.
Script:
Dim xmlDoc: Set xmlDoc = CreateObject("Msxml2.DOMDocument")
xmlDoc.Async = False
xmlDoc.load "C:\Scripts\Run\MonVid-SHORT.xml"
Dim xmldoc2: set xmldoc2 = CreateObject("Msxml2.DOMDocument")
Dim strSkeleton : strSkeleton= "<?xml version=""1.0"" encoding=""utf-8""?>" & _
"<XMLFeederRoot>" & _
"</XMLFeederRoot>"
xmldoc2.loadXML(strSkeleton)
xmldoc2.save "C:\Scripts\Copy\New_MonVid-Short.xml"
xmlDoc2.async = False
xmlDoc2.load "C:\Scripts\Copy\New_MonVid-Short.xml"
Dim sXPath : sXPath = "/XMLFeederRoot/Ad[Start_Date=End_Date]"
For Each n In XMLDoc.SelectNodes(sXpath)
set l = n.cloneNode(True)
q= l.selectSingleNode("/End_Date").text
strSDat=SplitArray(q)
l.removeChild(l.childNodes.item(2))
set Stat= l.selectSingleNode("/Status")
set Parent= Stat.parentNode
set EDate= xmlDoc2.createElement("End_Date")
EDate.appendChild xmlDoc2.createTextNode(strSDat)
Parent.insertBefore EDate, Stat
xmldoc2.documentElement.appendChild parent
Next
xmlDoc2.save xmldoc2.url
Function SplitArray(strval1)
dim SplitArray1, SplitArray2, strSDat
splitArray1 = split(strval1, "-")
splitArray1(2) = left(splitArray1(2), 2)
strDate1 = SplitArray1(1) & "/" & SplitArray1(2) & "/" & SplitArray1(0)
strDate30 = DateAdd("d", 30, strDate1)
SplitArray2 = split(strDate30, "/")
'Add zero to the left
If Len(SplitArray2(0))<2 Then
SplitArray2(0)= Right("0" & SplitArray2(0), 2)
End If
If Len(SplitArray2(1))<2 Then
SplitArray2(1)= Right("0" & SplitArray2(1), 2)
End If
SplitArray2(1) = splitArray2(1) & "T00:00:00"
strSDat = SplitArray2(2) & "-" & SplitArray2(0) & "-" & SplitArray2(1)
SplitArray= strSDat
End Function
Output File:
<?xml version="1.0" encoding="utf-8"?>
<XMLFeederRoot><Ad>
<Ad_Number>d00524224</Ad_Number>
<Start_Date>2016-08-20T00:00:00</Start_Date>
<End_Date>2016-09-19T00:00:00</End_Date><Status>Run</Status>
</Ad><Ad>
<Ad_Number>d00524225</Ad_Number>
<Start_Date>2016-08-20T00:00:00</Start_Date>
<End_Date>2016-09-19T00:00:00</End_Date><Status>Run</Status>
</Ad>
</XMLFeederRoot>
Since Text and XML files don't use file locks by default just overwrite the original file using xmlDoc.Save monvidPath.
Sub setAdEndDate(monvidPath)
Const sXPath = "/XMLFeederRoot/Ad/End_Date"
Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load(monvidPath)
Set colNodes=xmlDoc.selectNodes(sXPath)
For Each n In colNodes
n.Text = SplitArray(n.Text)
Next
xmlDoc.Save monvidPath
End Sub
Function SplitArray(strval1)
Dim SplitArray1, SplitArray2, strSDat
splitArray1 = Split(strval1, "-")
splitArray1(2) = Left(splitArray1(2), 2)
strDate1 = SplitArray1(1) & "/" & SplitArray1(2) & "/" & SplitArray1(0)
strDate30 = DateAdd("d", 30, strDate1)
SplitArray2 = Split(strDate30, "/")
'Add zero to the left
If Len(SplitArray2(0))<2 Then
SplitArray2(0)= Right("0" & SplitArray2(0), 2)
End If
If Len(SplitArray2(1))<2 Then
SplitArray2(1)= Right("0" & SplitArray2(1), 2)
End If
SplitArray2(1) = splitArray2(1) & "T00:00:00"
strSDat = SplitArray2(2) & "-" & SplitArray2(0) & "-" & SplitArray2(1)
SplitArray= strSDat
End Function
I have a script that connects to Oracle, runs a query, and saves the output to a CSV. Is there an easy way of make a copy of the file using the existing TextStream object?
' Execute query
Set objResultSet = objConnect.Execute(strSql)
' Create a filename to save query to
strTimeStamp = DatePart("yyyy",Date) & Right("0" & DatePart("m",Date), 2) & _
Right("0" & DatePart("d",Date), 2) & Right("0" & Hour(Now), 2) & _
Right("0" & Minute(Now), 2) & Right("0" & Second(Now), 2)
strOutputFilename = strTimeStamp & ".csv"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objOutputFile = objFSO.CreateTextFile(strOutputFilename, True)
' Loop through each row of recordset and output to jobcode download file
objResultSet.MoveFirst
Do While Not objResultSet.EOF
objOutputFile.WriteLine (objResultSet(0) & "," & objResultSet(1))
objResultSet.MoveNext
Loop
You could sort-of copy the file by creating files in both locations and writing the content to both files simultaneously. Other than that you'll have to use the Copy or CopyFile method. TextStream objects only have methods for manipulating the content of a file, not its location.
I am having a problem with my script not actually producing a zip file. When I test the script with the paths set to something like this:
C:\Users\Bob\Desktop\Folder1\Folder2
with the test log files in folder 1 being deleted if older than 7 days, and being zipped and moved to folder 2, it will run perfectly fine. It will produce the zipped file with all of the log files in it and have the proper naming set.
So I know that at least the logic of the script works for that.
My problem is that I need this script to go through the security logs on a machine and delete any older than 7 days, and then zip up any that are left and be sent to a mounted shared drive. When I change the path to something like:
C:\Windows\System32\Config (where the logs are located)
it will still delete any log files older than 7 days, but it does not produce a zip file with any that are left. It just does nothing even though the script produces no errors. I've been trying to figure this out with no luck going over my code. If anyone could take a look over what I've had and let me know where I've gone astray that would be extremely helpful.
Thank you in advance, the script is found below.
'READ FIRST
'------------------------------------------------------------------------------------------
'Lines 14-53 delete any log files older than 7 days. Changing the value in "iDaysOld =" will change the time frame in which files are kept or deleted.
'If files do not need to be deleted this part of the script can be taken out and the Archive/Move ability will still be intact
'Lines 57-102 contain the ability to Zip your log files and send them to a new folder. The zipped file is named after the localhost and a date/timestamp is appended to the file name.
'------------------------------------------------------------------------------------------
Option Explicit
Dim oFSO, oFolder, sDirectoryPath
Dim oFileCollection, oFile, sDir
Dim iDaysOld
' Specify Directory Path From Where You want to clear the old files
sDirectoryPath = "C:\Windows\System32\config"
' Specify Number of Days Old File to Delete
iDaysOld = 7
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFolder = oFSO.GetFolder(sDirectoryPath)
Set oFileCollection = oFolder.Files
For each oFile in oFileCollection
'Specify the Extension of file that you want to delete
'and the number with Number of character in the file extension
If LCase(oFSO.GetExtensionName(oFile.Name)) = "log" Then
If oFile.DateLastModified < (Date() - iDaysOld) Then
oFile.Delete(True)
End If
End If
Next
Set oFSO = Nothing
Set oFolder = Nothing
Set oFileCollection = Nothing
Set oFile = Nothing
WScript.Echo "Press to start zipping log files."
Dim objFile, objPath, objFolder, Command, PathLogs, RetVal
Dim objFSO: Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objShell: Set objShell = CreateObject("WScript.Shell")
Dim d : d = Date()
Dim dateStr : dateStr = Year(d) & "-" & Right("00" & Month(d), 2) & "-" & Right("00" & Day(d), 2)
Dim t : t = Time()
Dim timeStr: timeStr = Hour(t) & "-" & Right("00" & Minute(t), 2) & "-" & Right("00" & Second(t), 2)
'Path where logs are located
PathLogs = "C:\Windows\System32\config"
'Loop through the logs and zip
Set objPath = objFSO.GetFolder(PathLogs)
For Each objFile In objPath.Files
If (LCase(objFSO.GetExtensionName(objFile)) = "log") Then
' zip files
Command = """C:\Program Files\7-zip\7z.exe"" a " & PathLogs & "%computername%" & "-" & dateStr & "-" & timeStr & ".zip " & PathLogs & objFile.Name
RetVal = objShell.Run(Command,0,true)
End If
Next
WScript.Echo "Zip Successful."
WScript.Echo "Now Moving Zipped Files into Archived Folder"
'move files
Set objFSO = CreateObject("Scripting.FilesystemObject")
objFSO.MoveFile "C:\Windows\System32\config\*.zip" , "C:\Testscripts\testfolder\Archived"
WScript.Echo "Move Successful."
I'd probably try echoing out the 7zip command line, checking that it looks right and running it manually from the same location as the script runs from. It might look wrong when you see it or 7zip might give you a message to indicate what's going on.
This is my first post so please excuse my ignorance. I am using a vbscript to zip all .csv type files in a particular folder. After some google searches, I have found a workable vbscript to do this and have enabled a scheduled task to automate this.
What I need to do next is to transfer the zip file via sftp and then "move" that zip file into another folder. I believe the former can be achieved using pscp.exe via command line but can someone show me how to do the latter?
Basically the zipping will be done twice a day and so it will have a timestamp similar to yyyymmdd0900.zip (for 9am schedule) and yyyymmdd1800.zip (for 6pm schedule). After the transfer, I want to move (not copy) the zip file generated into another folder.
Any pointers would be greatly appreciated. Thank you all in advance.
EDIT: Here is some code I slapped together based on some Google searches. It does what I want it to do. Please excuse the "pasting" as i couldn't figure out how to format it properly. Currently, it runs the bat file after copying but I just noticed that i need to send (using PuTTY Secure Copy) the "latest" zip file before moving it to the "completed" folder. Can someone please show me how to do this?
Zipping the file and rename the zip file
My Code :
On Error Resume Next
strFilepath = "c:\files"
strDestination = "c:\files\completed\"
strExtension = "csv"
strYear = Year(Now)
strMonth = Right("0" & Month(Now), 2)
strDay = Right("0" & Day(Now), 2)
strHour = Right ("0" & Hour(Now), 2)
strMinute = Right ("0" & Minute (Now), 2)
strZip = strFilepath & "\" & strYear & strMonth & strDay & strHour & strMinute & ".zip"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strFilepath)
For Each objFile in objFolder.Files
strFileExt = objFSO.GetExtensionName(objFile.Path)
If LCase(strFileExt) = LCase(strExtension) Then
ZipFile objFile.Path, strZip
End If
Next
Sub ZipFile(strFileToZip, strArchive)
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FileExists(strArchive) Then
Set objTxt = objFSO.CreateTextFile(strArchive)
objTxt.Write "PK" & Chr(5) & Chr(6) & String(18, Chr(0))
objTxt.Close
End If
Set objApp = CreateObject( "Shell.Application" )
intCount = objApp.NameSpace(strArchive).Items.Count + 1
objApp.NameSpace(strArchive).CopyHere strFileToZip
Do
WScript.Sleep 200
set objNameSpace = objApp.NameSpace(strArchive)
If Not objNameSpace is nothing Then
If objNameSpace.Items.Count = intCount Then
Exit Do
End If
End If
Loop
End Sub
>Move file to a different folder and then run a bat file to secury copy file to a FTP location
'Vars
Dim objFSO, objFileCopy, objFileDelete, dot, files, file
Dim strDestination, folder, subfolder, fileCount, strFilePath
'Strings
strDestination = "C:\Files\Completed\"
strFilePath = "C:\Files"
set objFSO = CreateObject("Scripting.fileSystemObject")
set folder = objFSO.getFolder(strFilePath)
For Each file In folder.files
Set objFileCopy = objFSO.GetFile(file)
If objFSO.GetExtensionName(file) = "zip" Then
objFSO.MoveFile objFileCopy.Path, strDestination
End If
Next
Dim shell
Set shell=createobject("wscript.shell")
Shell.run "C:\testsend.bat"
Set shell=nothing
This will move a file to the specified location.
Sub Move_File(Source_File, Destination_Folder)
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
fso.MoveFile Source_File, Destination_Folder
Set fso = Nothing
End Sub
sftp client provides a means to change working directory on the host before performing any file transfers. It would be better to thus transfer the file directly to the target location.
NOTE: The above answer was a result of misunderstanding the question. I read it to mean the file had to be moved on the destination but the real operation was to move the file on the origin.
I found the following example code that moves a file after checking that it exists. Wildcards are allowed for the source parameter but then FileExists may not work. Requires vbscript 2.0 to work.
<%
dim filesys
set filesys=CreateObject("Scripting.FileSystemObject")
If filesys.FileExists("c:\sourcefolder\anyfile.html") Then
filesys.MoveFile "c:\sourcefolder\anyfile.html", "c:\destfolder\"
End If
%>
I have the following code (manipulated some code from a helpful soul out in cyberspace).
What it is meant to do is to zip all .csv files in a directory and name the zip file with the current timestamp.
My problem - I have setup a scheduled task to execute the below code everyday. As you can see, I am going back a day each time the code is executed. Meaning, zipping the file today with yesterday's "day". When it runs on the 1st of every month, I obviously run into a problem. It will grab yesterday's day (which is fine) but the current month. How can I manipulate the code so that it checks if yesterday was the last day of the month and put the correct timestamp for the filename?
Any assistance is greatly appreciated.
strFilepath = "c:\files"
strDestination = "c:\files\completed\" '"#
strExtension = "csv"
strYear = Year(Now)
strMonth = Right("0" & Month(Now), 2)
strDay = Right("0" & Day(Now -1), 2)
strHour = Right ("0" & Hour(Now), 2)
strMinute = Right ("0" & Minute (Now), 2)
strZip = strFilepath & "\" & strYear & strMonth & strDay & strHour & strMinute & ".zip" '"#
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strFilepath)
For Each objFile in objFolder.Files
strFileExt = objFSO.GetExtensionName(objFile.Path)
If LCase(strFileExt) = LCase(strExtension) Then
ZipFile objFile.Path, strZip
End If
Next
Sub ZipFile(strFileToZip, strArchive)
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FileExists(strArchive) Then
Set objTxt = objFSO.CreateTextFile(strArchive)
objTxt.Write "PK" & Chr(5) & Chr(6) & String(18, Chr(0))
objTxt.Close
End If
Set objApp = CreateObject( "Shell.Application" )
intCount = objApp.NameSpace(strArchive).Items.Count + 1
objApp.NameSpace(strArchive).CopyHere strFileToZip
Do
WScript.Sleep 200
set objNameSpace = objApp.NameSpace(strArchive)
If Not objNameSpace is nothing Then
If objNameSpace.Items.Count = intCount Then
Exit Do
End If
End If
Loop
End Sub
Just check Day(now) value. It it = 1, then Month = Month -1.