#Requires -Version 5.1 <# .SYNOPSIS Generates a full idempotent EF Core migration SQL script and drops it into Y:\pcc\deployment. .DESCRIPTION Runs `dotnet ef migrations script --idempotent` against the PowderCoating database and writes the output to Y:\pcc\deployment\migrations_YYYYMMDD_HHmmss.sql. The script is safe to run on any database state: EF wraps each migration in an IF NOT EXISTS check against __EFMigrationsHistory, so already-applied migrations are skipped. .NOTES Run from any directory — paths are resolved relative to this script's location. Requires: .NET 8 SDK, dotnet-ef tool (dotnet tool install --global dotnet-ef) #> [CmdletBinding()] param ( [string]$OutputDir = "Y:\pcc\Deployments" ) $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $displayStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $outputFile = "migrations_$timestamp.sql" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $repoRoot = Split-Path -Parent $scriptDir $webProject = Join-Path $repoRoot "src\PowderCoating.Web" $infraProject = Join-Path $repoRoot "src\PowderCoating.Infrastructure" $outputPath = Join-Path $OutputDir $outputFile Write-Host "" Write-Host "=== EF Migration Script Generator ===" -ForegroundColor Cyan Write-Host " Web project : $webProject" Write-Host " Output : $outputPath" Write-Host "" # ── Preflight checks ────────────────────────────────────────────────────────── if (!(Test-Path $webProject)) { Write-Host "ERROR: Web project not found at: $webProject" -ForegroundColor Red exit 1 } if (!(Test-Path $OutputDir)) { Write-Host "Creating output directory: $OutputDir" -ForegroundColor Yellow New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } $efVersion = dotnet ef --version 2>$null if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: dotnet-ef tool not found. Install with: dotnet tool install --global dotnet-ef" -ForegroundColor Red exit 1 } Write-Host "dotnet-ef : $($efVersion | Select-Object -First 1)" -ForegroundColor DarkGray # ── Generate script ─────────────────────────────────────────────────────────── Write-Host "Generating idempotent migration script..." -ForegroundColor Cyan $savedLocation = Get-Location Set-Location $webProject # Capture stderr to a temp file so EF's structured log noise (INF/WRN lines and # the "Ignoring added logger provider" design-time message) don't trigger # PowerShell 5.1's NativeCommandError handling. $tempErr = [System.IO.Path]::GetTempFileName() try { # Temporarily silence $ErrorActionPreference so PS 5.1 doesn't surface EF's # design-time stderr lines (structured log noise) as NativeCommandError objects. $prevEAP = $ErrorActionPreference $ErrorActionPreference = "SilentlyContinue" $null = dotnet ef migrations script ` --idempotent ` --context ApplicationDbContext ` --project $infraProject ` --output $outputPath ` --no-build 2>$tempErr $exitCode = $LASTEXITCODE $ErrorActionPreference = $prevEAP # Surface any genuine errors — filter out EF's routine log/diagnostic lines if (Test-Path $tempErr) { Get-Content $tempErr | Where-Object { $_ -notmatch "^\s*$" -and $_ -notmatch "\[.*\]\s+(INF|WRN)" -and $_ -notmatch "Ignoring added logger provider" -and $_ -notmatch "NativeCommandError" } | ForEach-Object { Write-Host " $_" -ForegroundColor DarkYellow } } } finally { Set-Location $savedLocation if (Test-Path $tempErr) { Remove-Item $tempErr -Force } } if ($exitCode -ne 0) { Write-Host "ERROR: dotnet ef migrations script failed (exit code $exitCode)" -ForegroundColor Red exit $exitCode } if (!(Test-Path $outputPath)) { Write-Host "ERROR: Output file was not created: $outputPath" -ForegroundColor Red exit 1 } # ── Stamp header ────────────────────────────────────────────────────────────── $header = @" -- ============================================================================= -- Idempotent EF Core migration script -- Project : PowderCoating.Web -- Generated: $displayStamp -- Safe to run on any database state (checks __EFMigrationsHistory per migration) -- ============================================================================= "@ $existing = Get-Content $outputPath -Raw Set-Content -Path $outputPath -Value ($header + $existing) -Encoding UTF8 # ── Report ──────────────────────────────────────────────────────────────────── $size = [math]::Round((Get-Item $outputPath).Length / 1KB, 1) $lineCount = (Get-Content $outputPath).Count Write-Host "" Write-Host "Done." -ForegroundColor Green Write-Host " File : $outputPath" Write-Host " Size : $size KB ($lineCount lines)" Write-Host " Stamp : $displayStamp" Write-Host ""