Files
windows_exporter/tools/setup-sql-server.ps1
2026-10-07 13:45:35 +00:00

111 lines
5.0 KiB
PowerShell

# Install a real Database Engine instance; LocalDB does not expose server counters.
# CI runs -DownloadOnly before installing the DNS Server role, which breaks
# downloads, and the installation after all Windows features are installed.
param([switch]$DownloadOnly)
$ErrorActionPreference = "Stop"
# Run an installer and fail instead of hanging when it does not finish in time.
function Invoke-Installer([string]$FilePath, [string[]]$ArgumentList, [int]$TimeoutMinutes) {
$process = Start-Process $FilePath -ArgumentList $ArgumentList -PassThru
# Windows PowerShell only reports ExitCode if the handle was read before exit.
$null = $process.Handle
if (-not $process.WaitForExit($TimeoutMinutes * 60 * 1000)) {
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
throw "$(Split-Path $FilePath -Leaf) did not finish within $TimeoutMinutes minutes"
}
return $process.ExitCode
}
$mediaDir = Join-Path $env:RUNNER_TEMP "sql-server"
New-Item -ItemType Directory -Force -Path $mediaDir | Out-Null
$setupDir = Join-Path $mediaDir "setup"
# CI caches the extracted setup files; download and extract only on a cache miss.
if (-not (Test-Path (Join-Path $setupDir "setup.exe"))) {
$installer = Join-Path $mediaDir "SQL2025-SSEI-Expr.exe"
# Microsoft download endpoints occasionally reset hosted runner connections.
curl.exe --fail --location --retry 5 --retry-all-errors --silent --show-error --output $installer `
"https://download.microsoft.com/download/ffd82b4c-9955-47c0-8efe-6290f7795cf6/SQL2025-SSEI-Expr.exe"
if ($LASTEXITCODE -ne 0) { throw "SQL Server bootstrapper download failed" }
$expectedHash = "fa7e1fabc9a2e9c9cdab0d1512bcb30d2949133147db057ac530f510e5270680"
if ((Get-FileHash $installer -Algorithm SHA256).Hash -ne $expectedHash) {
throw "SQL Server bootstrapper SHA256 mismatch"
}
$media = Join-Path $mediaDir "SQLEXPR_x64_ENU.exe"
foreach ($attempt in 1..3) {
$exitCode = Invoke-Installer $installer -TimeoutMinutes 10 `
-ArgumentList "/ACTION=Download", "/MEDIATYPE=Core", "/QUIET", "/MEDIAPATH=$mediaDir"
if ($exitCode -eq 0 -and (Test-Path $media)) { break }
if ($attempt -eq 3) { throw "SQL Server media download failed: $exitCode" }
Write-Warning "SQL Server media download attempt $attempt failed: $exitCode"
Start-Sleep -Seconds 10
}
$exitCode = Invoke-Installer $media -ArgumentList "/Q", "/X:$setupDir" -TimeoutMinutes 10
if ($exitCode -ne 0) {
throw "SQL Server media extraction failed: $exitCode"
}
}
if ($DownloadOnly) { return }
# Azure runners can expose sectors larger than SQL Server's supported 4 KB.
# Keep every instance file on a disk with a known, compatible sector size.
Import-Module Hyper-V
$diskPath = Join-Path $env:RUNNER_TEMP "sql-server.vhdx"
New-VHD -Path $diskPath -Dynamic -SizeBytes 8GB `
-LogicalSectorSizeBytes 512 -PhysicalSectorSizeBytes 4096 | Out-Null
. (Join-Path $PSScriptRoot "vhd-lock.ps1")
$volume = Invoke-WithVhdLock {
$disk = Mount-VHD -Path $diskPath -PassThru | Get-Disk
if ($disk.PhysicalSectorSize -gt 4096) {
throw "SQL Server fixture disk exposes unsupported physical sectors"
}
Format-NewDisk $disk CISQL
}
$instanceDir = "$($volume.DriveLetter):\SQLServer"
fsutil.exe fsinfo sectorinfo "$($volume.DriveLetter):"
$setup = Start-Process (Join-Path $setupDir "setup.exe") -Wait -PassThru -ArgumentList @(
"/Q"
"/IACCEPTSQLSERVERLICENSETERMS"
"/ACTION=Install"
"/FEATURES=SQLEngine"
"/INSTANCENAME=CISQL"
"/INSTANCEDIR=$instanceDir"
"/INSTALLSQLDATADIR=$instanceDir"
'/SQLSYSADMINACCOUNTS="BUILTIN\Administrators"'
"/UPDATEENABLED=False"
"/TCPENABLED=0"
"/NPENABLED=0"
)
$summaryLog = Join-Path $env:RUNNER_TEMP "sql-server-summary.txt"
Copy-Item "C:\Program Files\Microsoft SQL Server\170\Setup Bootstrap\Log\Summary.txt" `
$summaryLog -ErrorAction SilentlyContinue
if ($setup.ExitCode -ne 0) {
Get-Content $summaryLog -ErrorAction SilentlyContinue
throw "SQL Server setup failed or requires a restart: $($setup.ExitCode)"
}
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "Data Source=lpc:.\CISQL;Integrated Security=True;Connect Timeout=30"
try {
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = "CREATE DATABASE CIWindowsExporter"
$command.ExecuteNonQuery() | Out-Null
# Express can close idle databases and remove their performance counter instances.
$command.CommandText = "ALTER DATABASE CIWindowsExporter SET AUTO_CLOSE OFF"
$command.ExecuteNonQuery() | Out-Null
$connection.ChangeDatabase("CIWindowsExporter")
$command.CommandText = @'
CREATE TABLE dbo.Fixture (ID int NOT NULL, Data char(8000) NOT NULL);
INSERT INTO dbo.Fixture SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), 'fixture' FROM sys.all_objects;
CHECKPOINT;
'@
$command.ExecuteNonQuery() | Out-Null
} finally {
$connection.Dispose()
}
Get-Service 'MSSQL$CISQL' | Format-Table Name, Status