-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5a79539
commit d1ecde3
Showing
2 changed files
with
66 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
<# | ||
.NOTES | ||
PSTimeMachine.ps1 - Version 1.0.2 | ||
PSTimeMachine.ps1 - Version 1.0.3-beta6 | ||
(c) 2019 Colin Cogle <[email protected]> | ||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | ||
|
@@ -91,16 +91,19 @@ Param( | |
[Switch]$NoStatistics = $false | ||
) | ||
|
||
# Save the old error preference. It's rude to clobber the user's environment. | ||
# Save the old error preference and location. It's rude to clobber the user's environment. | ||
New-Variable -Option Constant -Name OldErrorActionPreference -Value $ErrorActionPreference | ||
New-Variable -Option Constant -Name OldLocation -Value (Get-Location) | ||
$ErrorActionPreference = "Stop" | ||
Set-Location -Path $SourcePath | ||
|
||
# We're going to create a folder to hold the backup, named for the current date and time. | ||
# Format everything except the year with leading zeroes. | ||
New-Variable -Option Constant -Name Today -Value (Get-Date) | ||
New-Variable -Option Constant -Name FolderName -Value (("{0:yyyy}-{0:MM}-{0:dd}T{0:hh}-{0:mm}-{0:ss}" -f $Today) + ".inProgress") | ||
|
||
# Start logging? | ||
$DoVerboseCopy = $VerbosePreference -eq "Continue" | ||
If (-Not $NoLogging) { | ||
$script:LogFile = (New-TemporaryFile) | ||
Start-Transcript -Path (($script:LogFile).Name) | ||
|
@@ -131,63 +134,69 @@ $bytesCopied = 0 | |
$bytesTotal = 0 | ||
|
||
Try { | ||
# Has hardlinking support been disabled? If so, just do a copy. | ||
If ($NoHardLinks) { | ||
Write-Verbose "Hard-linking is disabled at user request. Copying all files." | ||
Copy-Item -Path (Join-Path -Path $SourcePath "*") -Destination (Join-Path -Path $DestinationPath $FolderName) -Recurse | ||
$DoCopyOnlyBackup = $NoHardLinks | ||
|
||
# Look for old backups in the same destination. | ||
$PreviousBackups = (Get-ChildItem -Attributes Directory -Path $DestinationPath -Exclude "*.inProgress" -ErrorAction SilentlyContinue ` | ||
| Where-Object {$_.Name -CMatch "\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(\.inProgress)?"} ` | ||
| Sort-Object -Descending CreationTime | ||
) | ||
If ($PreviousBackups.Count -gt 0) { | ||
Write-Verbose "Previous backup found. Doing an incremental backup." | ||
$DoCopyOnlyBackup = $false | ||
$PreviousBackup = $PreviousBackups[0].Name | ||
} | ||
Else { | ||
# Look for old backups in the same destination. | ||
$PreviousBackups = (Get-ChildItem -Attributes Directory -Path $DestinationPath -Exclude "*.inProgress" -ErrorAction SilentlyContinue ` | ||
| Where-Object {$_.Name -CMatch "\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(\.inProgress)?"} ` | ||
| Sort-Object -Descending CreationTime | ||
) | ||
If ($PreviousBackups.Count -eq 0) { | ||
If ($FailIfOldBackupsAreMissing) { | ||
Throw [System.Management.Automation.ItemNotFoundException] "No previous backups were found. Exiting at user request." | ||
} | ||
Write-Verbose "No previous backups exist. Creating an initial backup." | ||
|
||
$DoVerboseCopy = $VerbosePreference -eq "Continue" | ||
Copy-Item -Path (Join-Path -Path $SourcePath "*") -Destination (Join-Path -Path $DestinationPath $FolderName) -Recurse -Verbose:$DoVerboseCopy | ||
If ($FailIfOldBackupsAreMissing) { | ||
Throw [System.Management.Automation.ItemNotFoundException] "No previous backups were found. Exiting at user request." | ||
} | ||
Else { | ||
# Get the most recent backup name. | ||
$PreviousBackup = $PreviousBackups[0].Name | ||
Write-Verbose "Previous backups not found. Doing a copy-only backup." | ||
$DoCopyOnlyBackup = $true | ||
} | ||
|
||
Get-ChildItem -Path "$SourcePath\" -Recurse -ErrorAction Stop | ForEach-Object { | ||
$RelativeSourceItemPath = (($_.FullName) -Replace [regex]::Escape("$((Get-Item $SourcePath).FullName)"),"") | ||
Get-ChildItem -Path "$SourcePath\" -Recurse -FollowSymLink | ForEach-Object { | ||
$RelativeSourceItemPath = $_.FullName | Resolve-Path -Relative | ||
Write-Debug "Analyzing $_" | ||
|
||
# Create directories, but compare files. | ||
If ($_.Attributes -CMatch "Directory") { | ||
Write-Debug "Creating folder $(Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath)" | ||
New-Item -Type Directory -Path (Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath) | Out-Null | ||
# Don't copy the log file. | ||
If ($_.Name -eq (($script:LogFile).Name)) { | ||
Continue | ||
} | ||
|
||
# Create directories, but compare files. | ||
If ($_.Attributes -CMatch "Directory") { | ||
Write-Debug "Creating folder $(Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath)" | ||
New-Item -Type Directory -Path (Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath) | Out-Null | ||
} | ||
Else { | ||
# Compare file sizes and dates to determine if something has changed. | ||
If (-Not $DoCopyOnlyBackup) { | ||
$PreviousCopyOfFile = Get-Item -Path (Join-Path -Path $DestinationPath $PreviousBackup $RelativeSourceItemPath) | ||
If (($_.LastWriteTime -eq $PreviousCopyOfFile.LastWriteTime) -And ($_.Length -eq $PreviousCopyOfFile.Length)) { | ||
# The file has not changed since the last backup. Create a hard link. | ||
$DestinationHardlink = @{ | ||
ItemType = "HardLink" | ||
Target = ($PreviousCopyOfFile.FullName) | ||
Path = ($PreviousCopyOfFile | Split-Path -Parent) -Replace [regex]::Escape($PreviousBackup),$FolderName | ||
Name = ($PreviousCopyOfFile.Name) | ||
} | ||
Write-Verbose "Linking: $RelativeSourceItemPath" | ||
New-Item @DestinationHardlink | Out-Null | ||
} | ||
Else { | ||
# Compare file sizes and dates to determine if something has changed. | ||
$PreviousCopyOfFile = Get-Item -Path (Join-Path -Path $DestinationPath $PreviousBackup $RelativeSourceItemPath) | ||
If (($_.LastWriteTime -eq $PreviousCopyOfFile.LastWriteTime) -And ($_.Length -eq $PreviousCopyOfFile.Length)) { | ||
# The file has not changed since the last backup. Create a hard link. | ||
$DestinationHardlink = @{ | ||
ItemType = "HardLink" | ||
Target = ($PreviousCopyOfFile.FullName) | ||
Path = ($PreviousCopyOfFile | Split-Path -Parent) -Replace [regex]::Escape($PreviousBackup),$FolderName | ||
Name = ($PreviousCopyOfFile.Name) | ||
ErrorAction = "Stop" | ||
} | ||
Write-Verbose "Linking: $RelativeSourceItemPath" | ||
New-Item @DestinationHardlink | Out-Null | ||
} | ||
Else { | ||
Write-Verbose "Copying: $RelativeSourceItemPath" | ||
Copy-Item -Path $_.FullName -Destination (Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath) -ErrorAction Stop | ||
$bytesCopied += $_.Length | ||
} | ||
$bytesTotal += $_.Length | ||
Write-Verbose "Copying: $RelativeSourceItemPath" | ||
Copy-Item -Path $_.FullName -Destination (Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath) -Verbose:$DoVerboseCopy | ||
$bytesCopied += $_.Length | ||
} | ||
} Else { | ||
Write-Verbose "Copying: $RelativeSourceItemPath" | ||
Copy-Item -Path $_.FullName -Destination (Join-Path -Path $DestinationPath $FolderName $RelativeSourceItemPath) -Verbose:$DoVerboseCopy | ||
$bytesCopied += $_.Length | ||
} | ||
$bytesTotal += $_.Length | ||
} | ||
} | ||
|
||
Write-Output "Backup completed at $(Get-Date)." | ||
Rename-Item -Path (Join-Path -Path $DestinationPath $FolderName) -NewName ($FolderName -CReplace '\.inProgress') | ||
If (-Not $NoStatistics -And $bytesTotal -gt 0) { | ||
|
@@ -202,11 +211,12 @@ Catch { | |
Finally { | ||
If (-Not $NoLogging) { | ||
Write-Verbose "Moving log file to backup destination." | ||
Stop-Transcript -ErrorAction SilentlyContinue | ||
Stop-Transcript -ErrorAction SilentlyContinue | Out-Null | ||
Write-Debug "Moving $($_.FullName) to $(Join-Path -Path $DestinationPath 'PSTimeMachine.log')" | ||
Move-Item -Path (($script:LogFile).Name) -Destination (Join-Path -Path $DestinationPath $FolderName "PSTimeMachine.log") -ErrorAction Continue | ||
} | ||
|
||
# Restore the user's preferred error action preference. | ||
# Restore the user's environment. | ||
$ErrorActionPreference = $OldErrorActionPreference | ||
} | ||
Set-Location -Path $OldLocation | ||
} |