diff --git a/backup.ps1 b/backup.ps1 index abe7f20..6a38d7f 100644 --- a/backup.ps1 +++ b/backup.ps1 @@ -1,19 +1,36 @@ param( [Parameter(Mandatory=$true)] - [string]$SqlInstance + [string]$SqlInstance, + + [Parameter(Mandatory=$false)] + [string]$Directory, + + [Parameter(Mandatory=$false)] + [switch]$Force ) # # backup.ps1 # -# TODO: Update cleanup time based on backup type +# TODO: Parallelize backups for multiple DBs in the instance +# TODO: Use PowerShell SQL module instead of sqlcmd $instanceName = $SqlInstance.Split('\')[1] -$directory = "C:\Rubrik\$instanceName" +# Use provided directory parameter or default to instance-based path +if ($Directory) { + $directory = $Directory + Write-Host "INFO: Using provided directory: $directory" +} else { + $directory = "C:\Rubrik\$instanceName" + Write-Host "INFO: Using default directory: $directory" +} + $fullBackupDay = 'Thursday' +$fullBackupOverdueDays = 7 # Force full backup if last full backup is older than this many days $checkCluster = $false -$logFile = "C:\Rubrik\backup-$instanceName.log" +#$logFile = "C:\Rubrik\backup-$instanceName.log" +$logFile = "H:\Backup\backup-$instanceName.log" $fullFlag = $directory + "\last_full.flag" $diffFlag = $directory + "\last_diff.flag" @@ -27,6 +44,35 @@ function FlagTakenToday($flagPath) { return $false } +function GetLastFullBackupDate($flagPath) { + if (Test-Path $flagPath) { + $flagDate = (Get-Content $flagPath | Out-String).Trim() + try { + return [DateTime]::ParseExact($flagDate, "yyyy-MM-dd", $null) + } + catch { + Write-Log "WARNING: Could not parse last full backup date from flag file: $flagDate" + return $null + } + } + return $null +} + +function IsFullBackupOverdue($flagPath, $overdueDays) { + $lastFullDate = GetLastFullBackupDate $flagPath + if ($null -eq $lastFullDate) { + Write-Log "WARNING: No last full backup date found. Full backup is considered overdue." + return $true + } + + $daysSinceLastFull = ($today - $lastFullDate).Days + $isOverdue = $daysSinceLastFull -gt $overdueDays + + Write-Log "INFO: Last full backup was $daysSinceLastFull days ago on $($lastFullDate.ToString('yyyy-MM-dd')). Overdue threshold: $overdueDays days." + + return $isOverdue +} + function Write-Log($message) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "$timestamp $message" @@ -34,20 +80,23 @@ function Write-Log($message) { Write-Host $logEntry } -# Check if directory exists and is a symbolic link +# Check if directory exists and is a symbolic link (unless -Force is specified) if (-not (Test-Path $directory)) { Write-Log "ERROR: Directory '$directory' does not exist. Exiting script." exit 1 } -$directoryInfo = Get-Item $directory -if (-not ($directoryInfo.Attributes -band [System.IO.FileAttributes]::ReparsePoint)) { - Write-Log "ERROR: Directory '$directory' is not a symbolic link. Exiting script." - exit 1 +if (-not $Force) { + $directoryInfo = Get-Item $directory + if (-not ($directoryInfo.Attributes -band [System.IO.FileAttributes]::ReparsePoint)) { + Write-Log "ERROR: Directory '$directory' is not a symbolic link. Exiting script." + exit 1 + } + Write-Log "INFO: Directory '$directory' exists and is a symbolic link. Target: $($directoryInfo.Target). Proceeding." +} else { + Write-Log "INFO: Force parameter specified. Skipping symbolic link check for directory '$directory'." } -Write-Log "INFO: Directory '$directory' exists and is a symbolic link. Target: $($directoryInfo.Target). Proceeding." - if ($checkCluster) { # Check if SQL instance is running locally $localNode = $env:COMPUTERNAME @@ -69,17 +118,31 @@ if ($checkCluster) { Write-Log "INFO: Cluster check is disabled. Proceeding without verification." } +# Check if full backup is overdue regardless of the day +$isFullBackupOverdue = IsFullBackupOverdue $fullFlag $fullBackupOverdueDays + if ((Get-Date).DayOfWeek -eq $fullBackupDay) { if (-not (FlagTakenToday $fullFlag)) { $backupType = "FULL" $cleanupTime = 168 Set-Content $fullFlag $today.ToString("yyyy-MM-dd") - Write-Log "Selected FULL backup. Flag updated." + Write-Log "Selected FULL backup (scheduled day). Flag updated." } else { $backupType = "LOG" $cleanupTime = 24 Write-Log "FULL backup already taken today. Selected LOG backup." } +} elseif ($isFullBackupOverdue) { + if (-not (FlagTakenToday $fullFlag)) { + $backupType = "FULL" + $cleanupTime = 168 + Set-Content $fullFlag $today.ToString("yyyy-MM-dd") + Write-Log "Selected FULL backup (overdue - forcing full backup). Flag updated." + } else { + $backupType = "LOG" + $cleanupTime = 24 + Write-Log "FULL backup already taken today (was overdue). Selected LOG backup." + } } else { if (-not (FlagTakenToday $diffFlag)) { $backupType = "DIFF"