An Intelligent File Backup

Sunday, July 13, 2014
<#
Purpose:    To create an intelligent backup system for large directories.
Notes:        I wrote this to perform a renditional backup of a large and complex directory.
            I've found that (for whatever reason) files keep getting removed from the
            diectory, so I've added a feature to keep track of deleted items as well.
            I know that there are applications to do this, but I wanted to see if I
            could do it myself!  I'm please with the overall outcome, but would appreciate
            any feedback!
Issues:        No known issues.  Use at your own peril!
#>

#Set Directory Paths
$SourceDirectory = "C:\SourceDirectory\"
$BackupLocation = "C:\BackupDirectory\"

#Get all files contained in Source Folder for processing
$SourceFiles = Get-ChildItem -Path $SourceDirectory -File -Recurse

#Create an array to store the output
$MoveStats = New-Object System.Collections.ArrayList

#Iterate through all of the files in SourceDirectory
$MoveStats = ForEach($File in $SourceFiles){
    $OldPath = ($File.FullName)
    $NewPath = $OldPath.Replace($SourceDirectory,$BackupLocation)
    #Create new object to store output
    $FileObject = New-Object -TypeName PSCustomObject -Property @{
        File = $File.Name
        OriginalPath = $File.FullName
        BackupPath = $null
        Action = $null
        RenditionPath = "N/A"
        }
    #Check for existing file in Backup Location
    if(Test-Path $NewPath){
        
        #File exists.  Check to see if needs updating
        if(($File.LastWriteTime) -gt ((Get-Item $NewPath).LastWriteTime)){
            
            #Rename existing backup, appending date/time to extention
            $NewName = (-join(($NewPath),"-",(Get-Date -Format "yyyyMMdd.HHmmss"),".BACKUP"))
            Get-Item -Path $NewPath | Rename-Item -NewName $NewName
            
            #Copy item to backup location
            Copy-Item -Path $File.FullName -Destination $NewPath
            
            #Update FileObject properties
            $FileObject.BackupPath = $NewPath
            $FileObject.Action = "Rendition Saved."
            $FileObject.RenditionPath = $NewName
            }
            
        else{
            #No action taken
            $FileObject.BackupPath = $NewPath
            $FileObject.Action = "No action taken."
            }
        }
    else{
        #File does not exist.  Copy file.
        New-Item -ItemType File -Path $NewPath -Force | Out-Null
        Copy-Item -Path $OldPath -Destination $NewPath
        $FileObject.BackupPath = $NewPath
        $FileObject.Action = "New File Copied."
        }
    
    #Returning Object
    $FileObject
    }
    
#Gather BackupFile inventory in order to mark deletions, ignoring Backup and Deleted Folders
$BackupDirectory = Get-ChildItem $BackupLocation -File -Recurse 
$BackupFiles = $BackupDirectory | Where {$_.name -notmatch ".BACKUP" -and $_.name -notmatch ".DELETED"}
ForEach($BackupFile in $BackupFiles){
    #Build FileName for checking against SourceFiles
    $BackupFileName = ($BackupFile.FullName).replace($BackupLocation,$SourceDirectory)
    #Check for missing BackupFile in SourceFile Directory
    if($SourceFiles.FullName -notcontains $BackupFileName){
        #File does not exist.  Rename it, appending Date/Time and "-DELETED"
        $DeletedName = (-join($BackupFile.FullName,"-",(Get-Date -Format "yyyyMMdd.HHmmss"),".DELETED"))
        Rename-Item -Path ($BackupFile.FullName) -NewName $DeletedName
        #Add New Object to MoveStats
        $MoveStats += New-Object -TypeName PSCustomObject -Property @{
            File = $BackupFile.Name
            OriginalPath = "N/A"
            BackupPath = $BackupFile.FullName
            Action = "Deleted"
            RenditionPath = "N/A"
            }
        }
    }
    
#Display Output
$MoveStats | Select File,OriginalPath,BackupPath,Action,RenditionPath | Out-GridView

No comments:

Post a Comment

Please keep all comments clean!