# Transfer Oracle RMAN Backup towards DR Server # Rulează după backup RMAN (03:00 AM) # Copiază backup-uri de pe PRIMARY (10.0.20.36) către DR (10.0.20.37) param( [string]$SourceFRA = "C:\Users\Oracle\recovery_area\ROA", [string]$DRHost = "10.0.20.37", [int]$DRPort = 22122, [string]$DRUser = "romfast", [string]$DRPath = "D:/oracle/backups/primary", [string]$SSHKeyPath = "$env:USERPROFILE\.ssh\id_rsa", [int]$RetentionDays = 2, [string]$LogFile = "D:\rman_backup\logs\transfer_$(Get-Date -Format 'yyyyMMdd').log" ) $ErrorActionPreference = "Continue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logLine = "[$timestamp] [$Level] $Message" Write-Host $logLine Add-Content -Path $LogFile -Value $logLine -Encoding UTF8 -ErrorAction SilentlyContinue } function Test-SSHConnection { Write-Log "Testing SSH connection to $DRHost`:$DRPort..." try { # Folosește -n pentru a nu citi din stdin (fix pentru blocare) $null = & ssh -n -p $DRPort -i $SSHKeyPath -o StrictHostKeyChecking=no -o ConnectTimeout=10 "${DRUser}@${DRHost}" "exit 0" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "SSH connection successful" "SUCCESS" return $true } else { Write-Log "SSH connection failed with exit code: $LASTEXITCODE" "ERROR" return $false } } catch { Write-Log "SSH connection error: $_" "ERROR" return $false } } function Get-TodaysBackups { Write-Log "Searching for today's backup files..." $today = Get-Date $cutoffDate = $today.Date # Only today (after midnight) $backupFiles = @() $searchPaths = @( "$SourceFRA\BACKUPSET", "$SourceFRA\AUTOBACKUP" ) foreach ($path in $searchPaths) { if (Test-Path $path) { # Get files created TODAY only (exclude old backups) $files = Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt $cutoffDate -and $_.Name -notlike "*__TAG_*" # Exclude old uncompressed backups } | Sort-Object LastWriteTime -Descending $backupFiles += $files } } if ($backupFiles.Count -eq 0) { Write-Log "No backup files found for today!" "WARNING" return @() } $totalSizeGB = ($backupFiles | Measure-Object -Property Length -Sum).Sum / 1GB Write-Log "Found $($backupFiles.Count) files, total size: $([math]::Round($totalSizeGB, 2)) GB" return $backupFiles } function Transfer-FileToDR { param([System.IO.FileInfo]$File, [string]$DestPath) $fileName = $File.Name $fileSizeMB = [math]::Round($File.Length / 1MB, 2) try { # Check dacă fișierul există deja pe DR (skip duplicates) - Windows PowerShell command $checkCmd = "powershell -Command `"Test-Path '$DestPath/$fileName'`"" $checkResult = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" $checkCmd 2>&1 if ($checkResult -match "True") { Write-Log "Skipping (already on DR): $fileName" "INFO" return $true } Write-Log "Transferring: $fileName ($fileSizeMB MB)" # SCP transfer - NO compression (files already compressed by RMAN) # Use cipher aes128-gcm for better performance $null = & scp -P $DRPort -i $SSHKeyPath -o StrictHostKeyChecking=no -o Compression=no -o Cipher=aes128-gcm@openssh.com $File.FullName "${DRUser}@${DRHost}:${DestPath}/" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "Transferred: $fileName" "SUCCESS" return $true } else { Write-Log "Failed to transfer: $fileName (exit code: $LASTEXITCODE)" "ERROR" return $false } } catch { Write-Log "Transfer error for $fileName : $_" "ERROR" return $false } } function Cleanup-OldBackupsOnDR { Write-Log "Cleaning up old backups on DR (keeping last $RetentionDays days)..." try { # Cleanup: șterge fișiere mai vechi de $RetentionDays zile - Windows PowerShell command $retentionDate = (Get-Date).AddDays(-$RetentionDays).ToString("yyyy-MM-dd") $cleanupCmd = "powershell -Command `"Get-ChildItem -Path '$DRPath' -Recurse -File | Where-Object { `$_.LastWriteTime -lt '$retentionDate' } | Remove-Item -Force -ErrorAction SilentlyContinue`"" $result = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" $cleanupCmd 2>&1 Write-Log "Cleanup completed on DR (removed files older than $retentionDate)" } catch { Write-Log "Cleanup warning: $_" "WARNING" } } # ==================== MAIN ==================== try { Write-Log "=========================================" Write-Log "Oracle DR Backup Transfer Started" Write-Log "=========================================" Write-Log "Source FRA: $SourceFRA" Write-Log "DR Server: $DRHost" Write-Log "DR Path: $DRPath" # Verificare prerequisite if (-not (Test-Path $SourceFRA)) { throw "Source FRA path not found: $SourceFRA" } if (-not (Test-Path $SSHKeyPath)) { throw "SSH key not found: $SSHKeyPath" } # Test SSH connection if (-not (Test-SSHConnection)) { throw "Cannot connect to DR server via SSH" } # Creare director pe DR - Windows PowerShell command Write-Log "Ensuring DR directory exists..." $null = & ssh -n -p $DRPort -i $SSHKeyPath "${DRUser}@${DRHost}" "powershell -Command `"New-Item -ItemType Directory -Path '$DRPath' -Force | Out-Null`"" 2>&1 # Găsește backup-uri $backupFiles = Get-TodaysBackups if ($backupFiles.Count -eq 0) { throw "No backup files to transfer!" } # Transfer fișiere Write-Log "Starting file transfer..." $successCount = 0 $failCount = 0 foreach ($file in $backupFiles) { if (Transfer-FileToDR -File $file -DestPath $DRPath) { $successCount++ } else { $failCount++ } } Write-Log "Transfer summary: $successCount succeeded, $failCount failed" if ($failCount -gt 0) { Write-Log "Some transfers failed!" "WARNING" } # Cleanup old backups pe DR Cleanup-OldBackupsOnDR Write-Log "=========================================" Write-Log "DR Backup Transfer Completed Successfully" Write-Log "=========================================" Write-Log "Files transferred: $successCount/$($backupFiles.Count)" Write-Log "DR Server: ${DRHost}:${DRPath}" exit 0 } catch { Write-Log "CRITICAL ERROR: $($_.Exception.Message)" "ERROR" Write-Log "Stack trace: $($_.ScriptStackTrace)" "ERROR" exit 1 }