mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 05:30:46 +08:00
Choose bundled or external PostgreSQL in the Setup wizard with connection validation; optional NETX_CREDENTIAL_SECRET_KEY; single desktop shortcut; faster uninstall and tray startup for offline Windows packages. Co-authored-by: Cursor <cursoragent@cursor.com>
104 lines
3.1 KiB
PowerShell
104 lines
3.1 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)][string]$PgHost,
|
|
[int]$Port = 5432,
|
|
[Parameter(Mandatory = $true)][string]$User,
|
|
[string]$Password = "",
|
|
[string]$PasswordFile = "",
|
|
[Parameter(Mandatory = $true)][string]$Database,
|
|
[Parameter(Mandatory = $true)][string]$PsqlPath,
|
|
[string]$OutUrlFile = "",
|
|
[string]$OutErrFile = ""
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Write-ErrFile([string]$Message) {
|
|
if ($OutErrFile) {
|
|
Set-Content -LiteralPath $OutErrFile -Value $Message -Encoding utf8
|
|
}
|
|
[Console]::Error.WriteLine($Message)
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $PsqlPath)) {
|
|
Write-ErrFile "psql_not_found: $PsqlPath"
|
|
exit 2
|
|
}
|
|
if ($PasswordFile) {
|
|
if (-not (Test-Path -LiteralPath $PasswordFile)) {
|
|
Write-ErrFile "password_file_missing"
|
|
exit 3
|
|
}
|
|
$Password = [IO.File]::ReadAllText($PasswordFile).TrimEnd("`r", "`n")
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($PgHost)) {
|
|
Write-ErrFile "host_required"
|
|
exit 3
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($User) -or [string]::IsNullOrWhiteSpace($Database)) {
|
|
Write-ErrFile "user_and_database_required"
|
|
exit 3
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($Password)) {
|
|
Write-ErrFile "password_required"
|
|
exit 3
|
|
}
|
|
if ($Port -lt 1 -or $Port -gt 65535) {
|
|
Write-ErrFile "invalid_port: $Port"
|
|
exit 3
|
|
}
|
|
|
|
$encUser = [uri]::EscapeDataString($User)
|
|
$encPw = [uri]::EscapeDataString($Password)
|
|
$encDb = [uri]::EscapeDataString($Database)
|
|
$url = "postgresql+psycopg://${encUser}:${encPw}@${PgHost}:${Port}/${encDb}"
|
|
|
|
$psqlDir = Split-Path -Parent $PsqlPath
|
|
$prevPath = $env:PATH
|
|
$prevPw = $env:PGPASSWORD
|
|
try {
|
|
$env:PATH = "$psqlDir;$env:PATH"
|
|
$env:PGPASSWORD = $Password
|
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
|
$psi.FileName = $PsqlPath
|
|
$psi.Arguments = "-h `"$PgHost`" -p $Port -U `"$User`" -d `"$Database`" -v ON_ERROR_STOP=1 -t -A -c `"SELECT 1`""
|
|
$psi.UseShellExecute = $false
|
|
$psi.RedirectStandardOutput = $true
|
|
$psi.RedirectStandardError = $true
|
|
$psi.CreateNoWindow = $true
|
|
$psi.WorkingDirectory = $psqlDir
|
|
$p = [Diagnostics.Process]::Start($psi)
|
|
$stdout = $p.StandardOutput.ReadToEnd()
|
|
$stderr = $p.StandardError.ReadToEnd()
|
|
$p.WaitForExit()
|
|
if ($p.ExitCode -ne 0) {
|
|
$msg = (($stderr + "`n" + $stdout).Trim())
|
|
if (-not $msg) { $msg = "psql_exit_$($p.ExitCode)" }
|
|
Write-ErrFile "connection_failed: $msg"
|
|
exit 1
|
|
}
|
|
if (($stdout.Trim()) -notmatch '1') {
|
|
Write-ErrFile "unexpected_result: $($stdout.Trim())"
|
|
exit 1
|
|
}
|
|
} catch {
|
|
Write-ErrFile ("connection_failed: " + $_.Exception.Message)
|
|
exit 1
|
|
} finally {
|
|
$env:PATH = $prevPath
|
|
if ($null -eq $prevPw) {
|
|
Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue
|
|
} else {
|
|
$env:PGPASSWORD = $prevPw
|
|
}
|
|
}
|
|
|
|
if ($OutUrlFile) {
|
|
$dir = Split-Path -Parent $OutUrlFile
|
|
if ($dir -and -not (Test-Path -LiteralPath $dir)) {
|
|
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
|
}
|
|
Set-Content -LiteralPath $OutUrlFile -Value $url -Encoding ascii -NoNewline
|
|
}
|
|
|
|
Write-Output "ok"
|
|
exit 0
|