Initial commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# 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
|
||||
}
|
||||
Reference in New Issue
Block a user