Monday, May 18, 2009

Finding Old Files = Old Stuff is New Again

There are a lot of scripts (and canned apps as well) floating about that will find files older than a given date or older than a given number of hours, days, weeks, months, years, decades, centuries, millenium.  Ok, seriously, you can't have any "real" electronic files older than a decade unit of measure.  Can you?

Some of the most succinct examples I've seen are those written by Don Hite.  If you haven't seen Don's site, you should (click here).  Here's one, and another.

Rather than try to "me-too!" this, I thought about dropping this into the blender to find out Will it Blend?  What I mean is: how does it look in different scripting languages.

Task: Identify files in a specified folder older than "x" days.  Either by Date-Created or Date-LastModified.  You have to be careful.  Sometimes, and I still don't know why, you can find situations where Windows reports that a file was Created on a date which is more recent than the LastModified date.  Maybe a time warp?  Who knows.  So I take the most-recent date for comparison.

Let's blend them, shall we?

VBScript Example

strFolder = "c:\temp"
intDaysOld = 60

Dim objFSO, objFolder, objFile, age, age1, age2, note
Dim iCount : iCount = 0
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(strFolder)

Wscript.Echo "scanning " & strFolder
Wscript.Echo

For each objFile in objFolder.Files
age1 = DateDiff("d", objFile.DateLastModified, Now)
age2 = DateDiff("d", objFile.DateCreated, Now)
If age1 < age2 Then
age = age1
note = ""
ElseIf age2 < age1 Then
age = age2
note = "*"
Else
age = age1
note = ""
End If
If age > intDaysOld Then
Wscript.Echo objFile.Name & vbTab & _
objFile.DateCreated & vbTab & _
objFile.DateLastModified & vbTab & _
objFile.Size & vbTab & _
age & vbTab & note
iCount = iCount + 1
End If
Next

Set objFolder = Nothing
Set objFSO = Nothing

Wscript.Echo
Wscript.Echo iCount & " files found older than " & intDaysOld & " days old"


KiXtart Example



Break ON

$strFolder = "c:\temp"
$intDaysOld = 60

Dim $objFSO, $objFolder, $objFile, $age, $age1, $age2, $note
Dim $iCount, $Tab

$iCount = 0
$Tab = Chr(9)

$objFSO = CreateObject("Scripting.FileSystemObject")
$objFolder = $objFSO.GetFolder($strFolder)

? "scanning $strFolder" ?

For each $objFile in $objFolder.Files
$filename = $objFile.Name
$age1 = DaysOld($objFile.DateLastModified)
$age2 = DaysOld($objFile.DateCreated)
If $age1 < $age2
$age = $age1
$note = ""
Else
If $age2 < $age1
$age = $age2
$note = "*"
Else
$age = $age1
$note = ""
EndIf
EndIf
If $age > $intDaysOld
? $objFile.Name + $Tab +
$objFile.DateCreated + $Tab +
$objFile.DateLastModified + $Tab +
$objFile.Size + $Tab +
$age + $Tab + $note
$iCount = $iCount + 1
EndIf
Next

$objFolder = 0
$objFSO = 0

?
? "$iCount files found older than $intDaysOld days old"

;----------------------------------------------------------------
; comment: Calculate Days from DATE to Today
;----------------------------------------------------------------

Function DaysOld($date)
Dim $sc, $result
$sc = CreateObject("ScriptControl")
$sc.Language = "vbscript"
$result = $sc.Eval("DateDiff(" + Chr(34) + "d" + Chr(34) + ", " + Chr(34) + $date + Chr(34) + ", Now)")
$sc = 0
$DaysOld = $result
EndFunction


PowerShell v2 Example



param(
[string]$compare_method = "created"
)

$strFolder = "c:\temp"
$intDaysOld = 60
$tab = [char]9
$backdate = (Get-Date).AddDays($intDaysOld * -1)
$i = 0

# verify a valid compare-method argument value was requested
# default is "created" if none is specified

if (($compare_method -ieq "created") -or ($compare_method -ieq "modified")) {

# determine most-recent age of a given file object

function ShowInfo($file) {
if ($compare_method -eq "created") {
$d = new-timespan $(get-date $file.CreationTime) $(get-date)
if ($file.CreationTime.AddDays($intDaysOld * -1) -le $backdate) {
$file.Name $tab $file.CreationTime $tab $file.Length $tab $d.Days $tab "C"
}
}
else {
$d = new-timespan $(get-date $file.LastWriteTime) $(get-date)
if ($file.LastWriteTime.AddDays($intDaysOld * -1) -le $backdate) {
$file.Name $tab $file.LastWriteTime $tab $file.Length $tab $d.Days $tab "M"
}
}
}

#****************************************************************
# comment: filter files using datestamp age comparison
#****************************************************************

filter FileAge($days) { if (( $_.LastWriteTime -le $backdate -and $_.CreationTime -le $backdate )) { $_ }}

write-host "scanning $strFolder...`n"
if ($compare_method -eq "created") {
write-host "FileName $tab DateCreated $tab Size $tab Age $tab Note"
}
else {
write-host "FileName $tab DateModified $tab Size $tab Age $tab Note"
}
dir $strFolder | FileAge $intDaysOld | foreach-object { ShowInfo $_; $i++; }
write-host "`n$i files were found older than $intDaysOld days"
}
else {
write-host "`ninvalid parameter!"
write-host
write-host "usage: .\list-old-files.ps1 [compare-method]"
write-host
write-host " created - compare files by date-created"
write-host " modified - compare files by date last-modified"
write-host " created is the default (if not specified)"
write-host
}


### Some useful links...


http://powershell.com/cs/blogs/tips/archive/2008/11/20/finding-old-files.aspx


http://www.microsoft.com/technet/scriptcenter/topics/winsh/convert/dateadd.mspx


Code Talk



Most of the code you see here is adapted from what others post on the Internet.  I search and scavenge and assembly my own spin on things to suit (a) my needs and (b) my preferences for format, structure and documentation.  What you see here is about 75 percent discovery and 25 percent adaptation and reformatting.



The PowerShell example warrants a little explanation.  It's very different from the other two obviously.  I had to scrounge around to put that together, and I'm almost certain someone will look at it either laugh hysterically or throw-up all over their screen and keyboard.  Following up with something like "wow, what an idiot!  That can be done with [x] lines of code!"  So, don't blindly accept my work as the end-all solution to a problem.  It's simply meant to be an "example".  One example.  I urge you to explore your own solutions and improve upon anything I spew forth.



Ok, back to the code: First, I establish a date ($backdate) which is [60] days in the past from the current date.  Then I compare datestamps of files against that.  The function ShowInfo() compares the date stamp on the file object with the $backdate value to determine the age and then formats a line of data with tab separation.  The collection is first obtained from the Dir() function.  The output of which is piped directly into the FileAge filter expression to weed out files that do not exceed the specified age limit (60 days).  Then I allow the use of an input argument ($compare-method) to determine whether to calculate the file age by using the CreationTime property, or the LastWriteTime property.



Conclusion



Each of these can easily be ammended, appended, prepended, suspended and stipended (maybe up-ended) to do more useful things.  Maybe delete, rename or move the files it finds.  Whatever.  The point of this exercise is as always to just observe each language next to the other and see how they can each help.  If you work with one language all the time, it's like using the same hammer all the time.



You need to open your tool box and play with the other tools.  Wait, that didn't sound quite right, umm, whatever.  If you have a snippet posted that you'd like to share, drop a comment here and I'll gladly link you up.

Post a Comment