Skip to content

Commit

Permalink
Beta of v1.0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
rhymeswithmogul committed Jun 5, 2019
1 parent 5a79539 commit d1ecde3
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 51 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# PSTimeMachine Change Log

## Version 1.0.3 (in progress)
- If a file is in use and can't be copied, PSTimeMachine will now keep running instead of terminating.
- If a copy-only backup is performed, file names will now be written to the log file.
- Resolve-Path has replaced -Replace for calculating relative paths.

## Version 1.0.2 (2019-06-03)
- Fixed a bug where an initial or -NoHardLinks backup would not show verbose errors when -Verbose was supplied.
- Fixed a bug where the script would terminate before completion if transcription were not enabled.
Expand Down
112 changes: 61 additions & 51 deletions PSTimeMachine.ps1
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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}

0 comments on commit d1ecde3

Please sign in to comment.