Submitted By: Ralph Edington

Incrementally deletes the oldest files in a folder until a specified amount of free disk space has been reached.

Visual Basic
Edit|Remove
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
'''
''' DELETE OLDEST FILES BASED ON AVAILABLE DISK SPACE
'''
''' This script will delete the oldest files in a directory, until free disk space on the drive
'''    rises above a value.
'''
''' The value of space needed is variable, and is calculated at runtime. 
'''
''' The value is determined based on the size of the largest file in the directory,
'''    multiplied by an upsizing "factor".
'''
''' This is useful for cleaning up old backup files in a directory.  
'''
''' Enough space will be left free for a new backup,
'''    as long as it isn't bigger than "factor" times the largest of the old backups.
''' 
''' This allows backup sizes to gradually grow or shrink while always maintaining acceptable 
'''    levels of free space needed for new backups.
'''
''' THIS FILE IS WRITTEN TO WORK ON THE LOCAL COMPUTER ONLY.
'''
''' PARAMETERS NEEDED:
'''
''' 1 - disk to be operated on, e.g. "E:" 
'''
''' 2 - path to be operated on, e.g. "\backups\".  Leading and trailing backslashes are necessary.
'''                                                 Enclose in quotes if path contains spaces.
'''
''' 3 - Space factor, e.g. "1.2", which would mean "Leave free at least 120% of the largest file size."
'''
'''
''' EXAMPLE COMMAND LINES:
'''
'''     cscript F:\cleanup_files.vbs   F:  \backups\  1.1    //Nologo >> F:\cleanup_log.txt
'''
'''  or
'''
'''    cscript F:\cleanup_files.vbs   "F:"  "\backups\dir with space\"  "1.2"    //Nologo >> F:\cleanup_log.txt
'''
'''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 

Const GroupDigits = true ''' for formatting numeric output



'''
'''  Were any parameters passed in?
'''

Set CmdArg_Object = Wscript.Arguments

Select Case (CmdArg_Object.Count)
    Case 3
        DiskToCheck     = CmdArg_Object.item(0)
        PathToCheck     = CmdArg_Object.item(1)
        Factor         = CmdArg_Object.item(2)
        Case Else
              WScript.Echo "This script requires 3 parameters. " &_ 
                "Please see comments within the script file for details." & vbcrlf
              WScript.Quit
End Select


''''
'''' Do a quick calculation to find the largest file, which in turn will tell us 
''''    the minimum disk space we need to have free at the end
''''

largest = 0
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFolder = fso.GetFolder(DiskToCheck & PathToCheck) 
Set oFileList = oFolder.Files
For Each f in oFileList
        if f.Size > largest then
        largest = f.Size
    end if
Next


''''
'''' Don't forget to upsize by "Factor", since we actually want MORE space left free than the size of the biggest file: 
''''

NeedFree = Factor * largest  ''' NeedFree is crucial, it's the free space target we're shooting for.



''''
'''' Now spit out some startup diagnostic info about what we're going to be doing: 
''''

Wscript.Echo "======================================================================================="
Wscript.Echo "The largest file in " & DiskToCheck & PathToCheck &_
        " is currently " & FormatNumber (largest, 0, 0, 0, GroupDigits) & " bytes." &_
        vbcrlf

Wscript.Echo "This script will delete the oldest file from directory " & DiskToCheck & PathToCheck &_ 
        vbcrlf &_
        " until free disk space on " & DiskToCheck & " rises above " &_
        Factor & " * " & FormatNumber (largest, 0, 0, 0, GroupDigits) &_ 
        vbcrlf &_
        " which is " & FormatNumber (NeedFree, 0, 0, 0, GroupDigits) & " bytes." &_
        vbcrlf

''''
'''' Spit out the Date and Time. Especially useful when appending output to a log file. 
''''

Set objWMIService = GetObject("winmgmts:"  & "{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_LocalTime")
For Each objItem in colItems   
    Wscript.Echo "  Current Date & Time is: " & objItem.Month & "/" & objItem.Day & "/" & objItem.Year & "  " & _
                objItem.Hour & ":" & objItem.minute & ":" & objItem.Second
Next


''''
''''  Do the initial check for current free disk space.  Additional checks will be done toward the end of the loop. 
''''    See function code below.
''''

FreeSpace = FindFreeDiskSpace (DiskToCheck)


''''
''''  Output some diagnostic info as to whether we're going to do anything:
''''    See subroutine code below. 
''''

OutputDiagnostic


'''''''''''''''''''''''''''''''''''''' START OF THE BIG LOOP  '''''''''''''''''''''''''''''''''''''''''''''
''''
''''  Now, here's the fun part, the main loop:
''''  
''''  Find oldest file and delete it until FreeSpace > NeedFree
'''' 
''''  Note that in the loop test comparison, you need to divide the terms by 1 or else the comparison fails
''''    for really large numbers, don't ask me why. Something to do with converting from Integer to Double? 
''''
''''

Do Until FreeSpace/1 >= NeedFree/1 

    ''''
    '''' Find the oldest file name:
    ''''

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set oFolder = fso.GetFolder(DiskToCheck & PathToCheck)
    Set oFileList = oFolder.Files
    Oldest = Now
    For Each f in oFileList
            if f.DateLastModified < Oldest Then
            Oldest = f.DateLastModified 
            OldestFile = f.Name
            End If
    Next

    ''''
    '''' Now that you have the oldest file name, pull up that file and delete it:
    ''''

    Set fso = CreateObject(" Scripting.FileSystemObject")
    Set oFile = fso.GetFile(DiskToCheck & PathToCheck & OldestFile)
        
    Wscript.echo "Deleting oldest file:" &_
         vbcrlf &_
        "Name: "     &         oFile.Name &_
        ", Size: "     & FormatNumber (oFile.Size, 0, 0, 0, GroupDigits)  &_
        ", ModDate: "     &         oFile.DateLastModified
        
    fso.DeleteFile (DiskToCheck & PathToCheck & OldestFile)

    FreeSpace = FindFreeDiskSpace (DiskToCheck) ''''' Find free space again after deletion. See function code below.

    OutputDiagnostic  ''''' Output diagnostic info as to whether we are going to continue or quit. See function code below. 
    

Loop ''''''''''''''END OF LOOP''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'''
''' ...and the end of the main program!
'''

'========================================================================================== 
Function FindFreeDiskSpace (Disk)

'''''
''''' Returns a NUMBER, the bytes of free space on the given disk
'''''
'''''   This is in a function because it is run both before and within the main loop.
'''''

    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Set colDisks = objWMIService.ExecQuery ("Select * from Win32_LogicalDisk Where DeviceID = '" & Disk & "'") 
    For Each objDisk in colDisks  ''''''''''' A one-iteration "loop"!  Don't really need this, only checking 1 disk.
        FindFreeDiskSpace = objDisk.FreeSpace
    Next

End Function


'==========================================================================================
sub OutputDiagnostic 

'''''
''''' Just outputs some diagnostic info about whether we're going to need to clean up or not. 
'''''
'''''   This is in a subroutine because it's called both inside and outside the main loop.
'''''
    
    wscript.echo _
        vbcrlf & "Need: " & FormatNumber (NeedFree, 0, 0, 0, GroupDigits) &_ 
        vbcrlf & "Free: " & FormatNumber (FreeSpace, 0, 0, 0, GroupDigits)

    If (FreeSpace/1 >= NeedFree/1) then
        ''''
        '''' Note: for some reason we need to divide these numbers by 1, or else the comparisons don't work on large numbers. 
        ''''       Remove the "/1" at your own risk.
        ''''
        wscript.echo "Free >= Need.  Don't do anything."
    else
        wscript.echo "Need > Free.  CLEAN UP!" 
    End If
    
    wscript.echo vbcrlf

End Sub