Files
2026-04-23 21:38:24 -04:00

152 lines
5.3 KiB
PowerShell

# Fix-Passwords.ps1
# Resets password hashes for both SuperAdmin users in the Azure SQL database.
# Runs directly via sqlcmd to avoid copy-paste corruption of Base64 characters.
#
# Usage (interactive - will prompt for connection details):
# .\Fix-Passwords.ps1
#
# Usage (non-interactive):
# .\Fix-Passwords.ps1 -Server "yourserver.database.windows.net" -Database "PowderCoatingDb" -User "sqladmin" -Password "yourpassword"
param(
[string]$Server,
[string]$Database = "PowderCoatingapp",
[string]$User,
[string]$Password
)
function New-IdentityPasswordHash {
param([string]$Password)
$salt = [byte[]]::new(16)
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rng.GetBytes($salt)
$rng.Dispose()
$pbkdf2 = [System.Security.Cryptography.Rfc2898DeriveBytes]::new(
$Password, $salt, 100000,
[System.Security.Cryptography.HashAlgorithmName]::SHA256)
$subkey = $pbkdf2.GetBytes(32)
$pbkdf2.Dispose()
# ASP.NET Core Identity v3 format
$buf = [byte[]]::new(61)
$buf[0] = 0x01
$buf[1] = 0x00; $buf[2] = 0x00; $buf[3] = 0x00; $buf[4] = 0x01 # PRF = HMACSHA256
$buf[5] = 0x00; $buf[6] = 0x01; $buf[7] = 0x86; $buf[8] = 0xA0 # 100000 iterations
$buf[9] = 0x00; $buf[10] = 0x00; $buf[11] = 0x00; $buf[12] = 0x10 # salt length = 16
[Array]::Copy($salt, 0, $buf, 13, 16)
[Array]::Copy($subkey, 0, $buf, 29, 32)
return [Convert]::ToBase64String($buf)
}
# ---- Prompt for connection details if not provided ----------------------------
if (-not $Server) {
$Server = Read-Host "Azure SQL Server (e.g. yourserver.database.windows.net)"
}
if (-not $User) {
$User = Read-Host "SQL Username"
}
if (-not $Password) {
$securePass = Read-Host "SQL Password" -AsSecureString
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePass))
}
# ---- Check sqlcmd is available -----------------------------------------------
$sqlcmd = Get-Command sqlcmd -ErrorAction SilentlyContinue
if (-not $sqlcmd) {
Write-Host ""
Write-Host "ERROR: sqlcmd not found on PATH." -ForegroundColor Red
Write-Host "Install it from: https://learn.microsoft.com/en-us/sql/tools/sqlcmd/sqlcmd-utility" -ForegroundColor Yellow
Write-Host ""
Write-Host "Alternatively, copy fix_passwords.sql to the Azure Portal Query Editor manually." -ForegroundColor Yellow
Write-Host "(Be careful that + and / characters are not changed during copy-paste.)" -ForegroundColor Yellow
$useSqlCmd = $false
} else {
$useSqlCmd = $true
}
# ---- Generate hashes ---------------------------------------------------------
Write-Host ""
Write-Host "Generating password hashes..." -ForegroundColor Cyan
$hash1 = New-IdentityPasswordHash "SuperAdmin123!"
$hash2 = New-IdentityPasswordHash "CompanyAdmin123!"
$stamp1 = [Guid]::NewGuid().ToString()
$stamp2 = [Guid]::NewGuid().ToString()
Write-Host "Done." -ForegroundColor Cyan
# ---- Build SQL ---------------------------------------------------------------
$sql = @"
SET QUOTED_IDENTIFIER ON;
SET NOCOUNT ON;
-- Reset password hash for superadmin@powdercoating.com / SuperAdmin123!
UPDATE AspNetUsers
SET
PasswordHash = '$hash1',
SecurityStamp = '$stamp1'
WHERE NormalizedEmail = 'SUPERADMIN@POWDERCOATING.COM';
PRINT 'Updated: superadmin@powdercoating.com';
-- Reset password hash for admin@demo.com / CompanyAdmin123!
UPDATE AspNetUsers
SET
PasswordHash = '$hash2',
SecurityStamp = '$stamp2'
WHERE NormalizedEmail = 'ADMIN@DEMO.COM';
PRINT 'Updated: admin@demo.com';
-- Verify both users exist and have non-null hashes
SELECT Email, LEN(PasswordHash) AS HashLength, IsActive
FROM AspNetUsers
WHERE NormalizedEmail IN ('SUPERADMIN@POWDERCOATING.COM', 'ADMIN@DEMO.COM');
"@
# ---- Write SQL file (always, as backup) --------------------------------------
$sqlFile = Join-Path $PSScriptRoot "fix_passwords.sql"
$sql | Set-Content -Path $sqlFile -Encoding UTF8
Write-Host "SQL written to: $sqlFile" -ForegroundColor Gray
# ---- Execute via sqlcmd (avoids copy-paste corruption) -----------------------
if ($useSqlCmd) {
Write-Host ""
Write-Host "Running via sqlcmd (no copy-paste, Base64 characters preserved)..." -ForegroundColor Cyan
$result = & sqlcmd `
-S $Server `
-d $Database `
-U $User `
-P $Password `
-Q $sql `
-l 30 2>&1
Write-Host ""
$result | ForEach-Object { Write-Host $_ }
if ($LASTEXITCODE -eq 0) {
Write-Host ""
Write-Host "SUCCESS. Try logging in now:" -ForegroundColor Green
Write-Host " superadmin@powdercoating.com / SuperAdmin123!" -ForegroundColor White
Write-Host " admin@demo.com / CompanyAdmin123!" -ForegroundColor White
} else {
Write-Host ""
Write-Host "sqlcmd returned exit code $LASTEXITCODE. Check the output above." -ForegroundColor Red
Write-Host "You can also run fix_passwords.sql manually in the Azure Portal Query Editor." -ForegroundColor Yellow
}
} else {
Write-Host ""
Write-Host "Run fix_passwords.sql in Azure Portal > SQL Database > Query Editor." -ForegroundColor Yellow
Write-Host "TIP: If + or / appear as spaces after pasting, the hash will be corrupted again." -ForegroundColor Yellow
Write-Host " Use sqlcmd instead to be safe." -ForegroundColor Yellow
}