# RMAN Restore Database FROM ZERO - Clean State (PowerShell) # Backups are on F:\ (NFS mount from Proxmox host) # Run as: Administrator # Location: D:\oracle\scripts\rman_restore_from_zero.ps1 # # Parameters: # -TestMode: Skip service reconfiguration and Listener startup (for weekly DR tests) param( [switch]$TestMode ) $ErrorActionPreference = "Continue" $env:ORACLE_HOME = "C:\Users\Administrator\Downloads\WINDOWS.X64_193000_db_home" $env:ORACLE_SID = "ROA" $env:PATH = "$env:ORACLE_HOME\bin;$env:PATH" Write-Host "============================================" Write-Host "RMAN Database Restore FROM ZERO" Write-Host "============================================" Write-Host "" Write-Host "Database: ROA" Write-Host "DBID: 1363569330" Write-Host "Backups: F:\ROA\autobackup (NFS mount from Proxmox)" Write-Host "" Write-Host "This script will:" Write-Host " 1. CLEANUP: Delete any existing database files" Write-Host " 2. RESTORE: Restore from F:\ backups" Write-Host " 3. VERIFY: Check database is working" Write-Host "" # Verify F:\ mount is accessible if (-not (Test-Path "F:\ROA\autobackup")) { Write-Host "ERROR: F:\ROA\autobackup not accessible!" -ForegroundColor Red Write-Host "" Write-Host "Please verify:" Write-Host " 1. F:\ drive is mounted: dir F:\" Write-Host " 2. NFS mount command: mount -o rw,nolock,mtype=hard,timeout=60 10.0.20.202:/mnt/pve/oracle-backups F:" Write-Host " 3. Proxmox host is reachable: ping 10.0.20.202" Write-Host "" exit 1 } Write-Host "[OK] F:\ROA\autobackup is accessible" Write-Host "" # Create directories with proper permissions try { New-Item -ItemType Directory -Path "D:\oracle\temp" -Force -ErrorAction Stop | Out-Null New-Item -ItemType Directory -Path "D:\oracle\logs" -Force -ErrorAction Stop | Out-Null Write-Host "[OK] Created required directories" } catch { Write-Host "ERROR: Failed to create directories: $_" -ForegroundColor Red exit 1 } Write-Host "============================================" Write-Host "STEP 1: CLEANUP - Delete existing database" Write-Host "============================================" Write-Host "" Write-Host "Calling cleanup_database.ps1..." Write-Host "" # Call cleanup script with /SILENT flag & "D:\oracle\scripts\cleanup_database.ps1" /SILENT if ($LASTEXITCODE -ne 0) { Write-Host "" Write-Host "ERROR: Cleanup failed!" -ForegroundColor Red exit 1 } Write-Host "" Write-Host "[OK] Cleanup complete - VM is in clean state" Write-Host "" Write-Host "Starting restore in 2 seconds..." Start-Sleep -Seconds 2 Write-Host "============================================" Write-Host "STEP 2: RESTORE - Restore from F:\ backups" Write-Host "============================================" Write-Host "" # Step 2.1: Check Oracle service (create only if missing) Write-Host "[2.1] Checking Oracle service..." $service = Get-Service -Name "OracleServiceROA" -ErrorAction SilentlyContinue if ($service) { Write-Host "[OK] Oracle service already exists, skipping creation (15s saved!)" -ForegroundColor Green Write-Host " Service will be reused for this restore" # Ensure service is running (required for SQL*Plus connection) if ($service.Status -ne "Running") { Write-Host " Service is stopped, starting it (may take 30-60 seconds)..." # Start service in background job to avoid blocking $startJob = Start-Job -ScriptBlock { Start-Service -Name "OracleServiceROA" -ErrorAction SilentlyContinue } # Poll for service status with timeout $maxWait = 60 $elapsed = 0 $pollInterval = 3 $serviceStarted = $false while ($elapsed -lt $maxWait) { Start-Sleep -Seconds $pollInterval $elapsed += $pollInterval # Refresh service status $currentService = Get-Service -Name "OracleServiceROA" -ErrorAction SilentlyContinue if ($currentService -and $currentService.Status -eq "Running") { $serviceStarted = $true Write-Host " [OK] Service started successfully after $elapsed seconds" break } if ($elapsed % 15 -eq 0) { Write-Host " Still waiting for service to start... ($elapsed/$maxWait seconds)" } } # Cleanup background job Stop-Job -Job $startJob -ErrorAction SilentlyContinue Remove-Job -Job $startJob -ErrorAction SilentlyContinue if (-not $serviceStarted) { Write-Host " WARNING: Service did not start within $maxWait seconds" -ForegroundColor Yellow Write-Host " This may cause SQL*Plus connection issues (ORA-12560)" Write-Host " Attempting to continue anyway..." } } else { Write-Host " Service is already running" } } else { Write-Host " Oracle service not found, creating from PFILE..." # Check if PFILE exists, create if missing $pfilePath = "C:\Users\oracle\admin\ROA\pfile\initROA.ora" if (-not (Test-Path $pfilePath)) { Write-Host " PFILE not found, creating default initROA.ora..." -ForegroundColor Yellow # Create directory if needed $pfileDir = Split-Path $pfilePath -Parent if (-not (Test-Path $pfileDir)) { New-Item -ItemType Directory -Path $pfileDir -Force | Out-Null } # Create PFILE with tested configuration $pfileContent = @" # Initialization Parameters for ROA Database - DR VM # Auto-generated by rman_restore_from_zero.ps1 - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') # Database Identification db_name=ROA db_unique_name=ROA # Memory Configuration memory_target=1024M memory_max_target=1024M # File Locations control_files=('C:\Users\oracle\oradata\ROA\control01.ctl', 'C:\Users\oracle\recovery_area\ROA\control02.ctl') db_recovery_file_dest='C:\Users\oracle\recovery_area' db_recovery_file_dest_size=50G audit_file_dest='C:\Users\oracle\admin\ROA\adump' # Redo and Archive Log log_archive_format=%t_%s_%r.dbf # Compatibility compatible=19.0.0 # Character Set nls_language=AMERICAN nls_territory=AMERICA # Processes and Sessions processes=300 sessions=472 # Miscellaneous diagnostic_dest='C:\Users\oracle' _allow_resetlogs_corruption=TRUE "@ try { $pfileContent | Out-File -FilePath $pfilePath -Encoding ASCII -ErrorAction Stop Write-Host " [OK] Created PFILE: $pfilePath" -ForegroundColor Green } catch { Write-Host "ERROR: Failed to create PFILE: $_" -ForegroundColor Red exit 1 } } & oradim -new -sid ROA -startmode auto -pfile $pfilePath 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: Failed to create Oracle service" -ForegroundColor Red exit 1 } Write-Host "[OK] Oracle service created successfully (AUTOMATIC startup)" Start-Sleep -Seconds 2 } # Step 2.2: Startup NOMOUNT Write-Host "[2.2] Starting database in NOMOUNT mode..." # First, ensure any partially started instance is shut down # (Service auto-start may have started instance in error state without control files) Write-Host " Ensuring clean state - shutting down any existing instance..." $cleanupSQL = @" WHENEVER SQLERROR CONTINUE SHUTDOWN ABORT; EXIT; "@ $cleanupSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null # Now start cleanly in NOMOUNT Write-Host " Starting fresh instance in NOMOUNT mode..." $nomountSQL = @" STARTUP NOMOUNT PFILE='C:\Users\oracle\admin\ROA\pfile\initROA.ora'; EXIT; "@ $nomountSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: Failed to startup NOMOUNT" -ForegroundColor Red exit 1 } Write-Host "[OK] Database started in NOMOUNT mode" Start-Sleep -Seconds 3 # Step 2.3: Copy backups and create RMAN script Write-Host "[2.3] Preparing RMAN restore..." $rmanScript = "D:\oracle\temp\restore_from_zero.rman" $logFile = "D:\oracle\logs\restore_from_zero.log" # Copy backups from F:\ to recovery area (mode-dependent) New-Item -ItemType Directory -Path "C:\Users\oracle\recovery_area\ROA\autobackup" -Force | Out-Null if ($TestMode) { Write-Host "[INFO] Copying selected backups from F:\ROA\autobackup to recovery area..." Write-Host " TEST MODE: Only latest backup set (faster for weekly tests)" } else { Write-Host "[INFO] Copying all backups from F:\ROA\autobackup to recovery area..." Write-Host " STANDALONE MODE: All backups for maximum DR safety" } # Select backup files based on mode (TestMode vs Standalone) try { if ($TestMode) { # TEST MODE: Copy latest L0 backup set + all incrementals/archives Write-Host "[INFO] TEST MODE: Selecting latest backup set using naming convention..." -ForegroundColor Cyan # Check if new naming convention is in use (L0_*, L1_*, etc.) $l0Backups = Get-ChildItem "F:\ROA\autobackup\L0_*.BKP" -ErrorAction Continue | Sort-Object LastWriteTime -Descending if ($l0Backups.Count -gt 0) { # New naming convention detected - use smart selection Write-Host "[INFO] Using naming convention for optimized backup selection" -ForegroundColor Cyan $latestL0 = $l0Backups[0] # Extract date from filename: L0_ROA_20251011_123_1.BKP -> 20251011 if ($latestL0.Name -match 'L0_\w+_(\d{8})_') { $backupDate = $Matches[1] Write-Host "[INFO] Latest Level 0 backup date: $backupDate" -ForegroundColor Cyan Write-Host " Base file: $($latestL0.Name)" -ForegroundColor Cyan # Select all files from this backup set: # - All L0_*__* (all pieces of Level 0) # - All L1_*__* or later (incrementals from same day or after) # - All ARC_*__* or later (archive logs) # - All SPFILE_* and CF_* (needed for restore) $backupFiles = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction Continue | Where-Object { $_.Name -match "^L0_\w+_${backupDate}_" -or # Level 0 pieces $_.Name -match "^L1_\w+_\d{8}_" -or # All Level 1 incrementals $_.Name -match "^ARC_\w+_\d{8}_" -or # All archive logs $_.Name -match "^SPFILE_\w+_${backupDate}_" -or # SPFILE from same day $_.Name -match "^CF_\w+_${backupDate}_" -or # Controlfile from same day $_.Name -match "^O1_MF_S_" # Autobackup control files (always needed) } Write-Host "[INFO] Selected $($backupFiles.Count) files for restore:" -ForegroundColor Cyan Write-Host " - Level 0 pieces for date $backupDate" -ForegroundColor Cyan Write-Host " - All Level 1 incrementals" -ForegroundColor Cyan Write-Host " - All archive logs" -ForegroundColor Cyan Write-Host " - SPFILE and Control file backups" -ForegroundColor Cyan } else { Write-Host "WARNING: Cannot parse date from L0 filename, using ALL L0/L1/ARC files" -ForegroundColor Yellow $backupFiles = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction Continue | Where-Object { $_.Name -match "^(L0_|L1_|ARC_|SPFILE_|CF_)" } } } else { # Old naming convention (autobackup format) - fallback to copying all Write-Host "[INFO] Old naming convention detected - copying ALL backups for safety" -ForegroundColor Yellow Write-Host " (New naming convention will be used after next backup runs)" -ForegroundColor Yellow $backupFiles = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction Continue } Write-Host "[INFO] Total files selected: $($backupFiles.Count)" -ForegroundColor Cyan } else { # STANDALONE MODE: Copy ALL backups (disaster recovery - maximum safety with fallback) Write-Host "[INFO] STANDALONE MODE: Copying ALL backups for maximum DR safety..." -ForegroundColor Yellow $backupFiles = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction Continue Write-Host "[INFO] Full DR restore - will copy all available backups (includes redundancy)" -ForegroundColor Yellow } } catch { Write-Host "WARNING: Cannot enumerate backup files on F: drive - $_" -ForegroundColor Yellow $backupFiles = @() } # Validate backup count $minRequired = 2 if ($backupFiles.Count -lt $minRequired) { Write-Host "ERROR: Insufficient backup files found on F: drive (found: $($backupFiles.Count))" -ForegroundColor Red Write-Host " At least $minRequired backup files required for successful restore" Write-Host " Checking F:\ROA\autobackup directory..." try { $dirCheck = Get-ChildItem "F:\ROA\autobackup" -ErrorAction Continue Write-Host " Directory contents: $($dirCheck.Count) files" foreach ($file in $dirCheck) { Write-Host " $($file.Name) - $([math]::Round($file.Length / 1GB, 2)) GB" -ForegroundColor Gray } } catch { Write-Host " Cannot access directory: $_" -ForegroundColor Red } exit 1 } Write-Host "[INFO] Found $($backupFiles.Count) backup files, total size: $([math]::Round(($backupFiles | Measure-Object -Property Length -Sum).Sum / 1GB, 2)) GB" # Copy backups with better error handling Write-Host "[INFO] Starting backup copy operation..." $copyErrors = @() foreach ($backupFile in $backupFiles) { try { Write-Host "[INFO] Copying $($backupFile.Name)..." Copy-Item $backupFile.FullName "C:\Users\oracle\recovery_area\ROA\autobackup\" -Force -ErrorAction Stop Write-Host "[OK] Copied $($backupFile.Name)" -ForegroundColor Green } catch { Write-Host "ERROR: Failed to copy $($backupFile.Name) - $_" -ForegroundColor Red $copyErrors += "$($backupFile.Name): $_" } } if ($copyErrors.Count -gt 0) { Write-Host "ERROR: Backup copy failed for $($copyErrors.Count) files" -ForegroundColor Red foreach ($error in $copyErrors) { Write-Host " $error" -ForegroundColor Red } exit 1 } # Verify copied backups try { $copiedFiles = Get-ChildItem "C:\Users\oracle\recovery_area\ROA\autobackup\*.BKP" -ErrorAction Continue } catch { Write-Host "ERROR: Cannot verify copied backups - $_" -ForegroundColor Red exit 1 } if ($copiedFiles.Count -ne $backupFiles.Count) { Write-Host "ERROR: Backup copy verification failed - file count mismatch" -ForegroundColor Red Write-Host " Expected: $($backupFiles.Count), Copied: $($copiedFiles.Count)" exit 1 } Write-Host "[OK] All $($copiedFiles.Count) backups copied and verified to recovery area" # Create RMAN script $rmanContent = @" SET DBID 1363569330; RUN { ALLOCATE CHANNEL ch1 DEVICE TYPE DISK; RESTORE CONTROLFILE FROM AUTOBACKUP; RELEASE CHANNEL ch1; } ALTER DATABASE MOUNT; CATALOG START WITH 'C:/USERS/ORACLE/RECOVERY_AREA/ROA/AUTOBACKUP' NOPROMPT; CROSSCHECK BACKUP; DELETE NOPROMPT EXPIRED BACKUP; RUN { ALLOCATE CHANNEL ch1 DEVICE TYPE DISK; ALLOCATE CHANNEL ch2 DEVICE TYPE DISK; RESTORE DATABASE; RELEASE CHANNEL ch1; RELEASE CHANNEL ch2; } RUN { ALLOCATE CHANNEL ch1 DEVICE TYPE DISK; RECOVER DATABASE NOREDO; RELEASE CHANNEL ch1; } ALTER DATABASE OPEN RESETLOGS; DELETE NOPROMPT OBSOLETE; EXIT; "@ $rmanContent | Out-File -FilePath $rmanScript -Encoding ASCII Write-Host "[OK] RMAN script created: $rmanScript" # Step 2.4: Run RMAN restore Write-Host "[2.4] Running RMAN restore (this will take 10-20 minutes)..." Write-Host " Log file: $logFile" Write-Host "" & rman target / cmdfile=$rmanScript log=$logFile if ($LASTEXITCODE -ne 0) { Write-Host "" Write-Host "ERROR: RMAN restore failed!" -ForegroundColor Red Write-Host "Check log: $logFile" exit 1 } Write-Host "" Write-Host "[OK] RMAN restore completed successfully!" Write-Host "" Write-Host "============================================" Write-Host "STEP 3: VERIFY - Check database status" Write-Host "============================================" Write-Host "" Write-Host "[3.1] Verifying database..." $verifySQL = @" SET PAGESIZE 100 LINESIZE 200 COLUMN info FORMAT A80 SELECT 'DB_NAME: ' || NAME || ', OPEN_MODE: ' || OPEN_MODE AS info FROM V`$DATABASE; SELECT 'INSTANCE: ' || INSTANCE_NAME || ', STATUS: ' || STATUS AS info FROM V`$INSTANCE; SELECT 'TABLESPACES: ' || COUNT(*) AS info FROM DBA_TABLESPACES; SELECT 'DATAFILES: ' || COUNT(*) AS info FROM DBA_DATA_FILES; SELECT 'TABLES: ' || COUNT(*) AS info FROM DBA_TABLES WHERE OWNER NOT IN ('SYS','SYSTEM'); EXIT; "@ $verifySQL | & sqlplus -S / as sysdba Write-Host "" Write-Host "[3.2] Creating SPFILE for database persistence..." $spfileSQL = @" CREATE SPFILE FROM PFILE='C:\Users\oracle\admin\ROA\pfile\initROA.ora'; EXIT; "@ $spfileSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { Write-Host "WARNING: Failed to create SPFILE - database may not persist after connections close" -ForegroundColor Yellow } else { Write-Host "[OK] SPFILE created successfully" # Check if running in TestMode (weekly DR test) if ($TestMode) { Write-Host "[3.3] Running in TEST MODE - skipping service reconfiguration" Write-Host " Database is OPEN and ready for verification" Write-Host " Service will remain configured with PFILE (OK for testing)" } else { # Full configuration for standalone/production use Write-Host "[3.3] Reconfiguring Oracle service to use SPFILE..." # Shutdown database cleanly Write-Host " Shutting down database temporarily..." $shutdownSQL = @" SHUTDOWN IMMEDIATE; EXIT; "@ $shutdownSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null Start-Sleep -Seconds 3 # Delete and recreate service with SPFILE Write-Host " Recreating service with SPFILE..." & oradim -delete -sid ROA 2>&1 | Out-Null Start-Sleep -Seconds 2 & oradim -new -sid ROA -startmode auto -spfile 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { Write-Host " WARNING: Failed to recreate service with SPFILE" -ForegroundColor Yellow } else { Write-Host " [OK] Service now configured with SPFILE and AUTOMATIC startup" } # Restart database Write-Host " Starting database with SPFILE..." $startupSQL = @" STARTUP; EXIT; "@ $startupSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null Start-Sleep -Seconds 3 Write-Host "[OK] Database restarted with SPFILE configuration" # Start Oracle Listener Write-Host "[3.4] Starting Oracle Listener..." # Set Listener service to AUTOMATIC and start it Set-Service -Name "OracleOraDB19Home1TNSListener" -StartupType Automatic -ErrorAction SilentlyContinue Start-Service -Name "OracleOraDB19Home1TNSListener" -ErrorAction SilentlyContinue if ((Get-Service -Name "OracleOraDB19Home1TNSListener" -ErrorAction SilentlyContinue).Status -eq "Running") { Write-Host "[OK] Listener started successfully" } else { Write-Host "WARNING: Failed to start Listener automatically, trying lsnrctl..." -ForegroundColor Yellow & lsnrctl start 2>&1 | Out-Null } Start-Sleep -Seconds 2 # Register database with listener $registerSQL = @" ALTER SYSTEM REGISTER; EXIT; "@ $registerSQL | & sqlplus -S / as sysdba 2>&1 | Out-Null Write-Host "[OK] Database registered with Listener" } } Write-Host "" Write-Host "============================================" Write-Host "Database Restore FROM ZERO Complete!" Write-Host "============================================" Write-Host "" Write-Host "Restore log: $logFile" Write-Host "" Write-Host "Database is OPEN and ready for testing!" -ForegroundColor Green Write-Host "" Write-Host "Next steps:" Write-Host " 1. Test application connectivity" Write-Host " 2. Verify data integrity" Write-Host " 3. Run cleanup_database.ps1 to remove database after test" Write-Host " 4. Shutdown DR VM to conserve resources" Write-Host "" exit 0