Properly constructed incremental backup schemes use a file’s archive bit to determine what files to include in each backup increment. Currently indexed files should have the archive bit set, while modified or newly created files should have it unset to mark them for inclusion in the next backup. The following code sample can be used to set the archive bit based on a file’s creation date in WSH.
If you’ve installed the Windows Backup program in Windows XP, it will set archive bits based on age. The default will set an archive bit on any file older than 90 days so this example will do the same.
The code sample we will be creating will look into a provided folder and enumerate all files in that folder. It will then move through each file, check for the existence of an archive bit, and set it if the file is older than the set number of days.
The first step in creating this code sample will be to establish our constants. This includes the number of days that represents an archived file’s age (90 days) and the folder where the script should operate. This is done quite simply by assigning a couple of variables.
numDays = 90 strPath = "C:WindowsTemp"
Next, we’ll instantiate the FileSystemObject and check to see that our folder path really exists.
Set objfso = CreateObject("Scripting.FileSystemObject") If objfso.FolderExists(strPath) Then 'Make sure folder exists
If is does in fact exist, we should instantiate the folder object using the FileSystemObject’s GetFolder method and enumerate its file collection with the Folder object’s Files property. Keep in mind that this should all be done inside of the IF statement to prevent any errors that would occur if the path did not exist.
Set objFolder = objfso.GetFolder(strPath) Set colFiles = objFolder.Files 'Enumerate files
Once we’ve created the collection of files, we should move through each of them with a For Each loop and call a subroutine that will do the work of checking and setting the archive bit. We’ll be creating this function later.
Again, to prevent errors, we should nest the For Each loop inside of an IF statement that verifies that the file collection is not empty. We can do this simply by checking that the collection’s count property does not return 0.
If colFiles.Count > 0 Then For Each objFile In colFiles Call SetArchiveFlag(objFile, numDays) 'Call subroutine for each file found. Next Else 'colFiles collection was empty WScript.Echo "No files in folder", objFolder.Path End If
In this example, I’ve used the Else branch of our If statement to display a message box if there are no files in the file collection. This should be replaced with logging code or any other appropriate error-handling code.
The same is true as we complete our first IF statement. This Else branch will execute if the supplied folder path was not valid.
Else 'Folder path could not be found WScript.Echo "The specified folder", strPath, "does not exist" End If
That completes the basic code construct. This could be incorporated into a class or function in a larger script. Now we need to create the subroutine that will actually check and set the archive bit on each file.
You may be wondering why I’ve chosen to pass the numDays variable every time I call the SetArchiveFlag subroutine in the code example from the previous page. The reasoning is simple: flexibility. I wanted this code sample to be universal. By doing this, I’ve allowed the file age to be set at a folder level rather than globally. By recreating the previous code segment, you can use different age settings on different folders without recreating the entire code sample in your script.
This is where the dirty work begins. Anytime you’re dealing with file properties, it’s a good idea to disable script debugging that can halt execution of your script if errors are generated. We’ll make sure to check and respond to our own errors.
Unless your are fully handling all errors in your script, you should only disable this feature for small sections of your script. In this case, I’ve only disabled script debugging within this subroutine 1)You may also notice that I never turned script debugging back on. This was not an oversight. By design, script debugging will be enabled again as soon as execution leaves the subroutine..
Sub SetArchiveFlag(objFile, numDays) On Error Resume Next 'Disable error handling Err.Clear
Next, we’ll check the date of the file, using the File object’s DateCreated property, and establish a variable containing the current date of execution using VBScript’s Now function. All of the File object’s date properties 2)DateCreated, DateLastModified, and DateLastAccessed. and VBScript’s Now function return values of type Date. This will make things easier for us later. Since they are numbers of the same type, VBScript will allow us to perform calculations on them without first converting them to a standard number type.
dateFile = objFile.DateCreated 'Can also use DateLastModified or DateLastAccessed dateToday = Now()
Now we’ll check the age of the file, but before we do, let’s not forget that we’ve disabled script debugging. We want to be sure to capture any possible errors that our script could encounter. Do do this, we should encapsulate our code segment in an IF statement that checks to be sure that our file’s date is in fact less than today. This would indicate either a problem in the system clock or an incorrect date stamp–presumably that latter.
“But what if the file was created today?” You ask.
Remember that date stamps include data down to the second. The chances that a file was created at the exact second this code executed are very slim to none.
If dateFile < = dateToday Then daysOld = dateToday - dateFile 'Calculate file age If daysOld < numDays Then strFile = objFile.Path 'Retrieve file path for error handling or logging. Can be omitted if unused.
See how simple VBScript makes it for us to perform those date calculations?
What we’ve got here is the beginning of yet another IF statement. The latter most one is actually checking to see of the provided file should have the archive bit set by checking that its age is greater than the number of days we’ve specifiied. This is so that we don’t set the archive bit on file’s that are too young.
Now that we’ve determined that a file should have its archive bit set, we need to do the actual work of setting it. This is done very easily using the File object’s Attributes property. This Read/Write property accepts a pre-determined constant value that indicates which of the possible property settings should be set for a file. These include Read-Only, System, Hidden, and Archive among others.
At the file system level, a bit code is used to indicate these properties on a file. Likewise, the Attributes property retrieves or assigns a binary constant. VBScript allows us to use the decimal number 32 in place of its bit code equivalent (100000). Further, because we’re dealing with bit codes and binary data, we’re using And to perform a bitwise comparison rather than attempting a mathematical calculation. This is a little beyond the scope of this article so if you don’t completely understand it, just trust me that it works.
If Not objFile.Attributes And 32 Then 'Check for existing Archive bit objFile.Attributes = objFile.Attributes And 32 'Set archive bit
Finally, we’ll wrap up this subroutine. First, we should check to make sure that there were no errors setting the Archive bit. This is done by making sure that our error level is still 0. Then, it’s just a matter of closing up all of our remaining IF statements and closing the subroutine.
If Err.number <> 0 Then 'Check for error setting bit WScript.Echo Err.number, Err.Description, Err.Source, strFile End If End If End If Else WScript.Echo "Incorrect date stamp in", strFile End If End Sub
Notice that last Else branch that corresponds to the first IF statement that we created. This branch is executed if the File’s date stamp is newer than the time of code execution. In reality, code branch should never execute, but it doesn’t hurt to check for those unexpected, albeit unheard of, possibilities.
And there you have it! A simple code sample that sets a file’s archive bit based on age in WSH. Use this code sample to improve or build your own better-formed backup schemes.
You can see and download this code sample in its entirety on the next page.
numDays = 90 strPath = "C:\Windows\Temp" Set objfso = CreateObject("Scripting.FileSystemObject") If objfso.FolderExists(strPath) Then 'Make sure folder exists Set objFolder = objfso.GetFolder(strPath) Set colFiles = objFolder.Files 'Enumerate files If colFiles.Count > 0 Then For Each objFile In colFiles Call SetArchiveFlag(objFile, numDays) 'Call subroutine for each file found. Next Else 'colFiles collection was empty WScript.Echo "No files in folder", objFolder.Path End If Else 'Folder path could not be found WScript.Echo "The specified folder", strPath, "does not exist" End If Sub SetArchiveFlag(objFile, numDays) On Error Resume Next 'Disable automatic error handling Err.Clear 'Clear the StdErr object before continuing dateFile = objFile.DateCreated 'Can also use DateLastModified or DateLastAccessed dateToday = Now() If dateFile < = dateToday Then daysOld = dateToday - dateFile 'Calculate file age If daysOld > numDays Then strFile = objFile.Path 'Retrieve file path for error handling or logging. Can be omitted if unused. If Not objFile.Attributes And 32 Then 'Check for existing Archive bit objFile.Attributes = objFile.Attributes And 32 'Set archive bit If Err.number <> 0 Then 'Check for error setting bit WScript.Echo Err.number, Err.Description, Err.Source, strFile End If End If End If Else WScript.Echo "Incorrect date stamp in", strFile End If End Sub
References [ + ]
|1.||↑||You may also notice that I never turned script debugging back on. This was not an oversight. By design, script debugging will be enabled again as soon as execution leaves the subroutine.|
|2.||↑||DateCreated, DateLastModified, and DateLastAccessed.|