VBScript keep last 14 files, delete anything older then 14 days - vbscript

i have a VB Script file that goes thru many files and folders within a specific directopry path, and it deletes any files thats older then 30 days
but i want to add an exception, to keep the last 14 files, so lets say if i dont have any new files yesterday, then today it will delete the file older then 14 days, and i will be left with 13 files
i want to keep the last 14 files, no matter of its age, but if there is more then 14 files, then delete the oldest
can anyone assist me where i add it in my script, and how ? here is the script im using
On Error Resume Next
Set oFileSys = WScript.CreateObject("Scripting.FileSystemObject")
sRoot = "C:\Program Files (x86)\Syslogd\Logs" 'Path root to look for files
today = Date
nMaxFileAge = 14 'Files older than this (in days) will be deleted
DeleteFiles(sRoot)
Function DeleteFiles(ByVal sFolder)
Set oFolder = oFileSys.GetFolder(sFolder)
Set aFiles = oFolder.Files
Set aSubFolders = oFolder.SubFolders
For Each file in aFiles
dFileCreated = FormatDateTime(file.DateCreated, "2")
If DateDiff("d", dFileCreated, today) > nMaxFileAge Then
file.Delete(True)
End If
Next
For Each folder in aSubFolders
DeleteFiles(folder.Path)
Next
End Function

I think you could do this a few ways. One would be to use the DIR command to sort the files and then you can just iterate that list and delete the ones starting at the 15th position. For example, this command would return just the filenames, sorted by date in descending order:
dir /o-d /a-d /b
and you could run that using Shell.Run or Shell.Exec to capture its output. The "problem" with Shell.Run is that you'd need to send the output to a file, then open the file, and read it. Not a big deal but requires file I/O. If you use Shell.Exec, you can capture the standard output directly but you have to deal with the command prompt window flashing open whenever a DIR command runs.
If you're fine with either of those "problems", then that method should work fine.
But you could do everything using the FileSystemObject. The key is to just get the date of the 14th most-recent file. Here's how you could do that.
' Only run if we actually have more than 14 files...
If oFolder.Files.Count > 14 Then
' Create an array to the hold the dates of each file in this folder...
ReDim a(oFolder.Files.Count - 1)
' Store the dates...
i = 0
For Each oFile In oFolder.Files
a(i) = oFile.DateLastModified ' Or use DateCreated, if you wish
i = i + 1
Next
' Sort the array...
Sort a
' Get the 14th most-recent date...
dtmCutOff = a(13)
' Iterate the files once more and delete any files older than our cut-off...
For Each oFile In oFolder.Files
If oFile.DateLastModified < dtmCutOff Then oFile.Delete
Next
End If
' Simple bubble sort...
Sub Sort(a)
For i = UBound(a) - 1 To 0 Step -1
For j = 0 To i
If a(j) > a(j + 1) Then
temp = a(j + 1)
a(j + 1) = a(j)
a(j) = temp
End If
Next
Next
End Sub
The only issue I think you'll have is if two files with the exact same date and time occupy the 14th position. Using this method, the script would keep both, and you'd end up with 15 files (or more, if there were more matches). But that's going to be an issue no matter what method you use. If your 20 most-recent files have the same date and time, how you do choose 14 from amongst those 20 to keep? =)

Related

vbscript compare string contents (folder directory) of text files and creates the missing folders

I am currently working on a school assignment to compare strings within text files. These text files contains paths of folder directories. If a directory is not found on the other textfile, it will create that directory, else nothing will happen.
diretory1.txt contains directory strings that are:
C:\mcgfiles\avp
C:\mcgfiles\temp
C:\mcgfiles\logs\activity
C:\mcgfiles\logs\program
C:\mcgfiles\logs\status
C:\mcgfiles\generatedhtml
and diretory2.txt, contains the following
C:\mcgfiles
C:\mcgfiles\avp
C:\mcgfiles\temp
C:\mcgfiles\logs
C:\mcgfiles\logs\activity
C:\mcgfiles\logs\program
C:\mcgfiles\logs\status
C:\mcgfiles\generatedhtml
In the case of my textfiles, directories "C:\mcgfiles" and "C:\mcgfiles\logs" will be created on my drive C:\ since they are missing.
Here is the code I used:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Set objFile1 = objFSO.OpenTextFile("C:\scripts\directory1.txt", ForReading)
strAddresses = objFile1.ReadAll
objFile1.Close
Set objFile2 = objFSO.OpenTextFile("C:\scripts\directory2.txt", ForReading)
Do Until objFile2.AtEndOfStream
strCurrent = objFile2.ReadLine
If InStr(strAddresses, strCurrent) = 0 Then
objFSO.CreateFolder(strCurrent)
End If
Loop
It works fine when I use "C:\mcgfiles\temp" as the missing directory. But it cant differentiate what's missing when I use "C:\mcgfiles" or "C:\mcgfiles\logs". Maybe its because I used InStr function and it considers "C:\mcgfiles" and "C:\mcgfiles\logs" not missing since it can also be found in "C:\mcgfiles\logs\activity" etc.
I tried to use strComp but still nothing happens. Please help. Thank you
InStr() "returns the position of the first occurrence of one string within another". So "C:\mcgfiles" is found in "C:\mcgfiles\logs". If all of the pathes in the string you search in are terminated by an EOL marker (eg.g vbCrLf) you can use target & EOL as the needle:
>> haystack = "c:\a\b;c:\a;"
>> eol = ";"
>> needle = "c:\a" & eol
>> WScript.Echo InStr(haystack, needle)
>>
8
Other techniques - e.g. using a dictionary of the pathes - are possible, but would need more work.

vbscript error path not found while using movefolder method

I am fairly new to vbscript, and attempting to write a script that will pick up month and year stamped folders (2012_04) and move them to a year stamped folder (2012). I am getting a Path not found error though when I attempt to move the folder, and I can't seem to find an answer anywhere as to why it is happening.
for i = 0 to UBound(yearArray)
Set folder = fso.GetFolder(InputP)
Set subFold = Folder.Subfolders
yearStamp = yearArray(i)
if not fso.FolderExists(ArchiveP & yearStamp) then
fso.createFolder(ArchiveP & yearStamp)
end if
ArchiveP = ArchiveP & yearStamp & "\"
for each dateFold in subFold
Set fo = fso.GetFolder(InputP & dateFold.Name)
folderName = InputP & dateFold.name & "\"
foldName = fo.name & "\"
if left(foldName,4) = yearStamp then
fso.MoveFolder folderName , ArchiveP & foldName
end if
next
ArchiveP = UnChangeP & PreArchP
Next
The error happens at fso.MoveFolder folderName , ArchiveP & foldName and I can't figure out what is happening.
The error you're getting is caused by misconstructed paths. What you're trying to do is something like this:
fso.MoveFolder "C:\input\2013_03", "D:\archive\2013\2013_03"
However, what you're acutally doing is this:
fso.MoveFolder "C:\input\2013_03\", "D:\archive\2013\2013_03\"
^ ^
A trailing backslash is only valid in the destination path, and only if the destination path is the parent folder to which you want to move the source folder, i.e. your statement should look either like this:
fso.MoveFolder "C:\input\2013_03", "D:\archive\2013\"
or like this:
fso.MoveFolder "C:\input\2013_03", "D:\archive\2013\2013_03"
Avoid building paths via string concatenation. The FileSystemObjects provides a method BuildPath that will handle path separators correctly.
Your code is rather convoluted, BTW. Instead of using indexed access to yearArray you could simply iterate over all elements with a For Each loop. Also, your iteration over the subfolders of InputP already provides you with Folder objects. fso.GetFolder(InputP & dateFold.Name) is the exact same object as dateFold. Plus, Folder objects come with a Move method, so you'd only need to handle the destination path.
I believe your code could be simplified to the following, which should do what you want:
For Each year In yearArray
dst = fso.BuildPath(ArchiveP, year)
If Not fso.FolderExists(dst) Then fso.CreateFolder dst
For Each dateFold In fso.GetFolder(InputP).SubFolders
If Left(dateFold.Name, 4) = year Then dateFold.Move dst & "\"
Next
Next
In terms of performance it might be a good idea to switch the two loops, though. Iterating over folders means you have to read from disk whereas yearArray is in memory, thus the former iteration is bound to be slower than the latter. By making the subfolder iteration the outer loop (and putting the destination folder creation in a separate loop) you eliminate this bottleneck, because that way you read each subfolder just once.
For Each year In yearArray
dst = fso.BuildPath(ArchiveP, year)
If Not fso.FolderExists(dst) Then fso.CreateFolder dst
Next
For Each dateFold In fso.GetFolder(InputP).SubFolders
For Each year In yearArray
dst = fso.BuildPath(ArchiveP, year)
If Left(dateFold.Name, 4) = year Then dateFold.Move dst & "\"
Next
Next

VBScript to find and move files automatically

I've been tasked with trying to automate a task at work, because we've had issues lately with people remembering to do it.
In general, here's what I need a script to do:
Get the date of the previous day, in the format YYYYMMDD
Enter a folder with that given name
Search within all the folders underneath that location for 4 specific files
Copy those files to several different locations
The issue I'm having is that, for the 4 files I'm looking for, they're located in 2 different folders. 3 in 1, 1 in the other. The names of these folders changes daily, depending on what queue they got put into when generated by some other software. I need these files to be moved so that another script can be run on them. I'm having trouble figuring out how to accomplish this. Anyone have some ideas?
If the folders containing the interesting files are subfolders of your dated directory, you can use a nested loop:
Dim sDFolder : sDFolder = "..\data\20110105"
Dim dicFiNa : Set dicFiNa = CreateObject("Scripting.Dictionary")
dicFiNa("1.txt") = ""
dicFiNa("3.txt") = ""
dicFiNa("5.txt") = ""
Dim oRDir : Set oRDir = goFS.GetFolder(sDFolder)
Dim oSDir
For Each oSDir In oRDir.SubFolders
Dim oFile
For Each oFile In oSDir.Files
WScript.Echo "looking at", oFile.Path
If dicFiNa.Exists(oFile.Name) Then
WScript.Echo "found", oFile.Name, "will copy"
End If
Next
Next
output:
looking at E:\trials\SoTrials\answers\8750206\data\20110105\whatever\6.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\whatever\5.txt
found 5.txt will copy
looking at E:\trials\SoTrials\answers\8750206\data\20110105\unknown\4.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\unknown\3.txt
found 3.txt will copy
looking at E:\trials\SoTrials\answers\8750206\data\20110105\puzzle\2.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\puzzle\1.txt
found 1.txt will copy
A full recursive walk would be a bit more complex, so say so, if you need it.
Just for fun: a recursive version:
Dim sDFolder : sDFolder = "..\data\20110105"
Dim dicFiNa : Set dicFiNa = CreateObject("Scripting.Dictionary")
dicFiNa("1.txt") = ""
dicFiNa("3.txt") = ""
dicFiNa("55.txt") = ""
Dim oRDir : Set oRDir = goFS.GetFolder(sDFolder)
walk oRDir, dicFiNa, "whatever you need to copy the files"
Sub walk(oDir, dicFiNa, vCargo)
Dim oItem
For Each oItem In oDir.Files
WScript.Echo "looking at", oItem.Path
If dicFiNa.Exists(oItem.Name) Then
WScript.Echo "found", oItem.Name, "will copy"
End If
Next
For Each oItem In oDir.SubFolders
walk oItem, dicFiNa, vCargo
Next
End Sub
output:
looking at E:\trials\SoTrials\answers\8750206\data\20110105\whatever\6.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\whatever\5.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\unknown\4.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\unknown\3.txt
found 3.txt will copy *
looking at E:\trials\SoTrials\answers\8750206\data\20110105\puzzle\2.txt
looking at E:\trials\SoTrials\answers\8750206\data\20110105\puzzle\1.txt
found 1.txt will copy *
looking at E:\trials\SoTrials\answers\8750206\data\20110105\puzzle\deep\deeper\55.txt
found 55.txt will copy *
(*) as soon as the permission problem is solved.

Renaming pdf files with a batch file

I need to either write a batch file or a vbscript that will rename files. I need to keep everything in the file name up to the second "." but delete what comes after the second dot.
This is a sample of what the file names look like:
nnnnnnnnnnnnnnnn.xxxxxxxx.dddddddddd.pdf
n= 16 numbers 0-9
x= date in this format ex:02232008
d= 10 numbers 0-9, this is the part of the file name that I want to delete.
I need the d's from the sample above to be deleted but keep the rest of the file name the same. I need to be able to run this batch file on a folder that contains about 3,000 pdf files. It can either be put right back into the same folder or outputted into a different folder.
FOR /F "USEBACKQ delims=. tokens=1-4" %%F IN (`DIR /B /A-D "C:\Path\To\PDFs\"`) DO (
REN "%%~fF.%%G.%%H.%%I" "%%F.%%G.%%I"
)
If you have files that vary in how many periods there are, just need to add a simple argument to count how many period delimiters exist then execute.
In VBScript, you can use something like
' the file paths. hardcoded, but you could alternatively collect these via command line parameters
Const IN_PATH = "path\to\directory"
Const OUT_PATH = "path\to\another\directory"
' check that the directories exist. you could create them instead, but here
' it just throws an error as that's easier
dim fso: set fso = CreateObject("Scripting.FileSystemObject")
if not fso.FolderExists(IN_PATH) then
err.raise 1,, "Path '" & IN_PATH & "' not found"
end if
if not fso.FolderExists(OUT_PATH) then
err.raise 1,, "Path '" & OUT_PATH & "' not found"
end if
dim infolder: set infolder = fso.GetFolder(IN_PATH)
dim file
for each file in infolder.files
dim name: name = file.name
dim parts: parts = split(name, ".")
' we're expecting a file format of a.b.c.pdf
' so we should have 4 elements in the array (zero-indexed, highest bound is 3)
if UBound(parts) = 3 then
' rebuild the name with the 0th, 1st and 3rd elements
dim newname: newname = parts(0) & "." & parts(1) & "." & parts(3)
' use the move() method to effect the rename
file.move fso.buildpath(OUT_PATH, newname)
else
' log the fact that there's an erroneous file name
WScript.Echo "Unexpected file format: '" & name & "'"
end if
next 'file
You would run it in a batch file thus, redirecting output to a log file
cscript rename-script.vbs > logfile.txt
This assumes that you can simply rely on the period to delimit the parts of the file name rather than the specifics of the format of the delimited parts.
To rearrange the date, which I think is in the parts(1) array element, you can simply extract each bit of the string because it's in a specific format:
'date in format mmddyyyy
dim month_, day_, year_, date_
month_ = left(parts(1), 2)
day_ = mid(parts(1), 3, 2)
year_ = right(parts(1), 4)
date_ = year_ & month_ & day_ ' now yyyymmdd
so when rebuilding the filename, you can replace parts(1) with the new formatted date
dim newname: newname = parts(0) & "." & date_ & "." & parts(3)
Using StringSolver, a semi-automatic renaming tool, just rename the first file, check that the generalized renaming is ok, and then accept it on all other files.
> move 1234567890123456.02232008.1946738250.pdf 1234567890123456.02232008.pdf
Get the explanation:
> move --explain
the file name until the end of the second number + the extension
If you are satisfied, you can run the semi-automated tool using move --auto or the succint version:
> move
DISCLAIMER: I am a co-author of this free software made for academic purposes.

VB Script Files Collection

I'm working on some logic that will remove files from a particular folder if the disk space reaches a defined max capacity, I have the following code:
'Remove files if disk space falls below 100GB
While hDisk.FreeSpace < 100000000000
Set Directory = Fso.GetFolder("C:\backups")
Set Files = Directory.Files
Dim file1
Dim file2
For n = Files.Count - 1 to 0 Step - 1
If IsEmpty(file1) or IsNull(file1) Then
ERROR Here -->Set file1 = Files.Item(n)
ElseIf n > 0 Then
Set file2 = Files.Item(n)
If hDisk.FreeSpace > 100000000000 Then
Exit For
ElseIf file2.DateLastModified < file1.DateLastModified And DateDiff("D", file2.DateLastModified, Now) > 7 Then
file2.Delete
ElseIf file1.DateLastModified < file2.DateLastModified And DateDiff("D", file1.DateLastModified, Now) > 7 Then
file1.Delete
Set file1 = Files.Item(n)
Else
'Nothing
End If
Else
'Nothing
End If
Next
Wend 'End loop when drive is below max capacity
What it's supposed to do is loop through a collection of files in a folder and remove the oldest file(s) until the disk space is above capacity. So there is some file comparison that must be done. I'm encountering a Invalid procedure call or argument error on the line above (see comment). I'd also like to know if this is the best approach, I'm open to better suggestions, preferably ones that will cut down on code.
UPDATE:
Tried adding Set, in front of the assignment statement, but still get the same error.
UPDATE 2 (WORKING SCRIPT!!):
Played with it a bit more and was able to get the script working, here it is in its entirety in case anyone else wants to use it. I added comments to indicate custom values, it can be safely assumed that any other similar value is also customizable, i.e. the disk size is defined in multiple locations.
Dim Fso
Dim hDisk
Dim Directory
Dim Files
Dim myArray()
Set Fso = CreateObject("Scripting.FileSystemObject")
Set hDisk = Fso.GetDrive("c:") 'Custom Value - drive to monitor
If hDisk.FreeSpace < 100000000000 Then
'Delete files until free space is below max capacity (defined here as 100GB)
While hDisk.FreeSpace < 100000000000 'Custom Value - disk size in bytes
Set Directory = Fso.GetFolder("C:\backups") 'Custom Value - Directory to monitor
Set Files = Directory.Files
Redim myArray(Files.Count)
i=0
For Each fl in Files
Set myArray(i)=fl
i=i+1
Next
Dim file1
Dim file2
For n = Files.Count - 1 to 0 Step - 1
'1st PASS: Instantiate first file
If IsEmpty(file1) or IsNull(file1) Then
Set file1 = myArray(n)
'Compare 1st file with next file and current date, remove oldest if it's older than a week
ElseIf n > 0 Then
Set file2 = myArray(n)
If hDisk.FreeSpace > 100000000000 Then
Exit For
ElseIf file2.DateLastModified < file1.DateLastModified And DateDiff("D", file2.DateLastModified, Now) > 7 Then 'Custom Value - File age in number of days
file2.Delete
ElseIf file1.DateLastModified < file2.DateLastModified And DateDiff("D", file1.DateLastModified, Now) > 7 Then
file1.Delete
Set file1 = myArray(n)
Else
'Nothing
End If
'Remove remaining file if it's older than a week
Else
Set file1 = myArray(n)
If DateDiff("D", file1.DateLastModified, Now) > 7 Then
file1.Delete
End If
End If
Next
Wend 'End loop when drive is below max capacity
End If
UPDATE 3:
To clarify what's being done, the pseudocode is as follows:
If disk space is maxed
While disks space is maxed
For each file
If 1st File is empty
Get 1st File
If disk space is below max
Exit
Else Get Next File
If Next File is older than 1st File and older than a week
Delete Next File
Continue
Else if 1st File is older and older than a week
Delete current 1st File
Set 1st File to Next File
Continue
Else if 1st file is the only file and is older than a week
Delete 1st File
Reinventing the wheel. You're trying to create a script to perform a task that already exists in Windows.

Resources