Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- Live File Backup Script (for PowerShell) v1.1
- Written by Aaron Loessberg-Zahl
- Last modified 10 October 2012
- Copies files from a source directory (or a single source file)
- to a backup destination as they are changed in the source.
- Run 'Get-Help .\Backup-Files-Live.ps1' to get more information.
- For comments/questions/bugs, please contact
- <[email protected]> or <[email protected]>.
- ----------------------------------------------------------------------------
- "THE BEER-WARE LICENSE" (Revision 2659):
- <[email protected]> wrote this file. As long as you retain this
- notice, you can do whatever you want with this stuff. If we meet some day,
- and you think this stuff is worth it, you can buy me a beer in return.
- ----------------------------------------------------------------------------
- Changelog:
- v1.0 10-04-2012 amloessb Re-written in PowerShell from the original, broken liveBackup.vbs
- v1.1 10-10-2012 amloessb Debugged to a working state
- #>
- <#
- .SYNOPSIS
- Performs live backup of files.
- .DESCRIPTION
- Checks the source at a specified interval for changes and copies changed files to the destination. Folder hierarchies are preserved.
- This script runs indefinitely until:
- 1. ^C is pressed,
- 2. the top-level source disappears, or
- 3. the script's process is otherwise ended
- The script will continue to run even if files or directories within the source tree disappear.
- .PARAMETER Source
- The location of the source file or directory to be backed up.
- .PARAMETER Destination
- The destination directory where the backup will be saved.
- .PARAMETER Interval
- The frequency (in seconds) at which the script will check for changes in the source (default: 5).
- .INPUTS
- None. You cannot pipe objects to this script.
- .OUTPUTS
- None. This script does not produce any pipeable output.
- .EXAMPLE
- .\Backup-Files-Live -Source C:\Scripts -Destination C:\ScriptsBackup -Interval 10
- Backs up the contents of C:\Scripts to C:\ScriptsBackup, and checks for and backs up changes every 10 seconds.
- .LINK
- None.
- #>
- Param(
- [Parameter(Mandatory = $TRUE,
- Position = 0,
- HelpMessage = "The source file or directory.")]
- [ValidateNotNullOrEmpty()]
- [String] $Source,
- [Parameter(Mandatory = $TRUE,
- Position = 1,
- HelpMessage = "The destination directory.")]
- [ValidateNotNullOrEmpty()]
- [String] $Destination,
- [Int] $Interval = 5
- )
- Set-PSDebug -Strict
- $ErrorActionPreference = "Stop"
- # Request-YNAnswer [-Question] <String>
- # Purpose: Asks a question and waits for the user to either answer "y" or "n".
- # If the user does not answer either, the script will loop until a valid answer is given.
- # Returns: $true if "y", $false if "n"
- Function Request-YNAnswer {
- Param (
- [Parameter(
- Mandatory = $TRUE,
- HelpMessage = "The question to be asked of the user"
- )]
- [string] $Question
- )
- Process {
- $strAnswer = Read-Host "$Question [y/n] "
- Do {
- Switch ($strAnswer.ToLower()) {
- "y" {
- $BadAnswer = $False
- $Result = $True
- }
- "n" {
- $BadAnswer = $False
- $Result = $False
- }
- Default {
- $BadAnswer = $True
- $strAnswer = Read-Host "Please answer y or n "
- }
- }
- } While ($BadAnswer)
- Return $Result
- }
- }
- # Pause [[-Message] <String>]
- # Purpose: Pauses execution until a key is pressed.
- # Returns: N/A
- Function Pause {
- Param (
- [string] $Message="Press any key to continue..."
- )
- Process {
- Write-Host -NoNewLine $Message
- $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
- Write-Host ""
- }
- }
- Function CrashAndBurn ($strProblem) {
- $Host.UI.WriteErrorLine($strProblem)
- $Host.UI.WriteErrorLine("The script will now terminate.")
- Pause
- Exit 1
- }
- # Compare-DateModified -src <String> -dest <String>
- # Purpose: If $src is a folder, it calls its children recursively. If $src is a file, it
- # compares the modification times of $src and $dest, and writes the information to
- # $strNewFileList if $dest is newer.
- # Returns: N/A
- Function Compare-DateModified {
- Param (
- [String] $src,
- [String] $dest
- )
- Process {
- $objSrc = Get-Item $src
- If (Test-Path $dest) { # If the file/directory doesn't exist at the destination, we don't care
- If ($objSrc.PSIsContainer) {
- # Recursion case
- ForEach ($obj In Get-ChildItem $objSrc) {
- Compare-DateModified -src $obj.FullName -dest (Join-Path $dest -ChildPath $obj.Name)
- }
- } Else {
- # Base case
- $objDest = Get-Item $dest
- If ($objDest.LastWriteTime -gt $objSrc.LastWriteTime) {
- $Script:strNewFileList += "$($objSrc.Name) $DTab $($objSrc.LastWriteTime) $DTab $($objDest.LastWriteTime)`r`n"
- }
- }
- }
- }
- }
- # Confirm-Operation -src <Srting> -dest <String>
- # Purpose: Asks the user to confirm the backup settings
- # Returns: $true if the user accepts, $false if the user rejects
- Function Confirm-Operation {
- Param (
- [String] $src,
- [String] $dest
- )
- Process {
- Write-Host "The script will now back up " -NoNewline
- If (!$FileMode) {
- Write-Host "the contents of"
- } Else {
- Write-Host ""
- }
- Write-Host $src
- Write-Host "to"
- Write-Host $dest
- Write-Host ""
- Return (Request-YNAnswer "Is this correct?")
- }
- }
- # Write-CopyInfo -objSrc <System.IO.FileInfo>
- # Purpose: Prints the time, name, and size of the given file or folder
- # Returns: N/A
- Function Write-CopyInfo {
- Param (
- [System.IO.FileInfo] $objSrc
- )
- Process {
- $WriteTime = $objSrc.LastWriteTime
- $FileName = $objSrc.Name
- $strSize = "{0:N2}K" -f ($objSrc.Length / 1024.0)
- Write-Host "$WriteTime`t$FileName`t$strSize"
- }
- }
- # CompareAndCopy -src <String> -dest <String>
- # Purpose: If $src is a folder, it calls its children recursively and creates directories
- # in $dest (if they don't exist) as it goes. If $src is a file, it copies $src
- # over $dest if $src is newer or if $dest doesn't exist.
- # Returns: N/A
- Function CompareAndCopy {
- Param (
- [String] $src,
- [String] $dest
- )
- Process {
- # Failsafe: source and destination names must match
- If ($src.split("\")[-1] -eq $dest.split("\")[-1]) {
- $objSrc = Get-Item $src
- If ($objSrc.PSIsContainer) {
- # Recursion case
- If (!(Test-Path $dest)) { # Create the destination directory if it doesn't exist
- New-Item $dest -ItemType Directory
- }
- ForEach ($obj In Get-ChildItem $objSrc) {
- CompareAndCopy -src $obj.FullName -dest (Join-Path $dest -ChildPath $obj.Name)
- }
- } Else {
- # Base case
- If (Test-Path $dest) { # Check modification times, copy if source is newer
- $objDest = Get-Item $dest
- If ($objSrc.LastWriteTime -gt $objDest.LastWriteTime) {
- Copy-Item -Path $src -Destination $dest -Force
- Write-CopyInfo $objSrc
- }
- } Else { # If the file is not in the destination, copy regardless
- Copy-Item -Path $src -Destination $dest -Force
- Write-CopyInfo $objSrc
- }
- }
- } Else {
- CrashAndBurn "Failsafe: $src vs. $dest"
- }
- }
- }
- # ===== MAIN FUNCTION START =====
- $DTab = "`t`t"
- $TTab = "`t`t`t"
- $strHeader = "Name $TTab Source Date $TTab Destination Date"
- [String] $strNewFileList = ""
- If (Test-Path $Destination -PathType Container) {
- If (Test-Path $Source) {
- $objSource = Get-Item $Source
- # Check if the source is a file or directory
- If ($objSource.PSIsContainer) {
- $FileMode = $false
- } Else {
- $FileMode = $true
- }
- # Check that there are not newer file(s) in the source
- If ($FileMode) {
- Compare-DateModified -src $Source -dest (Join-Path $Destination -ChildPath $objSource.Name)
- } Else {
- Compare-DateModified -src $Source -dest $Destination
- }
- If ($strNewFileList) {
- Write-Host $strHeader
- Write-Host $strNewFileList
- Write-Host "The above files are newer at the destination then at the source."
- Write-Host "You will lose any changes you have made to the destination files"
- Write-Host "if you choose to continue."
- Write-Host ""
- $continue = Request-YNAnswer "Would you like to continue anyway?"
- If (!$continue) {
- CrashAndBurn "User abort."
- }
- }
- If (Confirm-Operation -src $Source -dest $Destination) {
- # Do the initial copy
- If ($FileMode) {
- Copy-Item -Path $Source -Destination $Destination -Force
- } Else {
- ForEach ($obj In Get-ChildItem $objSource) {
- Copy-Item -Path $obj.FullName -Destination $Destination -Recurse -Force
- }
- }
- Write-Host ""
- Write-Host "The script is now actively backing up your files."
- Write-Host "Press ^C to stop."
- Write-Host ""
- # === MAIN BACKUP LOOP ===
- While (Test-Path $Source) {
- If ($FileMode) {
- CompareAndCopy -src $Source -dest (Join-Path $Destination -ChildPath $objSource.Name)
- } Else {
- ForEach ($obj In Get-ChildItem $objSource) { # Copy each individual thing inside the source into the destination
- CompareAndCopy -src $obj.FullName -dest (Join-Path $Destination -ChildPath $obj.Name)
- }
- }
- Sleep -Seconds $Interval
- }
- CrashAndBurn "Source $Source disappeared!"
- } Else {
- CrashAndBurn "User abort."
- }
- } Else {
- CrashAndBurn "Source $Source does not exist."
- }
- } Else {
- CrashAndBurn "Destination $Destination does not exist or is not a directory."
- }
Add Comment
Please, Sign In to add comment