Skip to content

Instantly share code, notes, and snippets.

@sphinxid
Created June 3, 2026 23:02
Show Gist options
  • Select an option

  • Save sphinxid/9f434cc1ec5118854cc61f4714c8522b to your computer and use it in GitHub Desktop.

Select an option

Save sphinxid/9f434cc1ec5118854cc61f4714c8522b to your computer and use it in GitHub Desktop.
A power shell script that will help you identify what kind of Microsoft SQL Server installed on the device.
<#
.SYNOPSIS
Detect SQL Server Database Engine instances and SQL services.
.DESCRIPTION
Default:
- Output vertically to screen
- CSV only if -CsvPath is provided
- No SQL component/uninstall detection
- Detects SQL engine from services first:
MSSQLSERVER
MSSQL$INSTANCE
- Then tries to find version/edition from registry.
- If registry is missing and service is running, it tries SERVERPROPERTY() with short timeout.
.EXAMPLE
.\check_sql_version.ps1
.EXAMPLE
.\check_sql_version.ps1 -CsvPath "C:\Temp\SQL_Detection.csv"
.EXAMPLE
.\check_sql_version.ps1 -SkipSqlConnection
#>
param(
[string]$CsvPath,
[switch]$SkipSqlConnection,
[int]$ConnectionTimeoutSeconds = 3,
[switch]$DebugOutput
)
$ComputerName = $env:COMPUTERNAME
$Results = @()
function Write-DebugLine {
param([string]$Message)
if ($DebugOutput) {
Write-Output "[DEBUG] $Message"
}
}
function Test-IsBlank {
param([string]$Value)
return [string]::IsNullOrWhiteSpace($Value)
}
function Get-SqlVersionYear {
param([string]$ProductVersion)
if (Test-IsBlank $ProductVersion) {
return ""
}
$major = $ProductVersion.Split(".")[0]
switch ($major) {
"11" { return "SQL Server 2012" }
"12" { return "SQL Server 2014" }
"13" { return "SQL Server 2016" }
"14" { return "SQL Server 2017" }
"15" { return "SQL Server 2019" }
"16" { return "SQL Server 2022" }
"17" { return "SQL Server 2025" }
default { return "Unknown / Other" }
}
}
function Get-RiskClassification {
param(
[string]$Edition,
[bool]$HasSqlEngineService,
[bool]$HasRunningSqlEngineService
)
if (Test-IsBlank $Edition) {
if ($HasRunningSqlEngineService) {
return "SQL engine running, but edition not found"
}
elseif ($HasSqlEngineService) {
return "SQL engine service found but not running"
}
else {
return "No SQL Database Engine instance found"
}
}
if ($Edition -match "Express") {
return "Low - SQL Express detected"
}
elseif ($Edition -match "Developer") {
return "High if production - Developer Edition"
}
elseif ($Edition -match "Evaluation") {
return "High - Evaluation Edition"
}
elseif ($Edition -match "Standard|Enterprise|Web|Business Intelligence") {
return "Requires license evidence"
}
else {
return "Review"
}
}
function Get-AllSqlServices {
try {
return @(Get-Service *SQL* -ErrorAction SilentlyContinue | Select-Object Name, Status, DisplayName)
}
catch {
Write-DebugLine "Failed to get SQL services: $($_.Exception.Message)"
return @()
}
}
function Get-SqlEngineServices {
param($AllSqlServices)
if ($null -eq $AllSqlServices) {
return @()
}
return @(
$AllSqlServices |
Where-Object {
$_.Name -eq "MSSQLSERVER" -or
$_.Name -like 'MSSQL$*'
}
)
}
function Convert-ServiceListToText {
param($Services)
if ($null -eq $Services -or @($Services).Count -eq 0) {
return ""
}
$lines = @()
foreach ($svc in @($Services)) {
$lines += "$($svc.Name) [$($svc.Status)] - $($svc.DisplayName)"
}
return ($lines -join "; ")
}
function Get-InstanceNameFromServiceName {
param([string]$ServiceName)
if ($ServiceName -eq "MSSQLSERVER") {
return "MSSQLSERVER"
}
if ($ServiceName -like 'MSSQL$*') {
return $ServiceName.Substring(6)
}
return ""
}
function Get-ServerInstanceName {
param([string]$InstanceName)
if ($InstanceName -eq "MSSQLSERVER") {
return $ComputerName
}
return "$ComputerName\$InstanceName"
}
function Get-RegistryInstanceIdFromInstanceName {
param([string]$InstanceName)
$paths = @(
"HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\Instance Names\SQL"
)
foreach ($path in $paths) {
if (Test-Path $path) {
try {
$props = Get-ItemProperty -Path $path -ErrorAction Stop
$value = $props.$InstanceName
if (-not (Test-IsBlank $value)) {
return $value
}
}
catch {
Write-DebugLine "Failed reading instance mapping from $path : $($_.Exception.Message)"
}
}
}
return ""
}
function Find-SqlSetupInfoByInstanceName {
param([string]$InstanceName)
$basePaths = @(
"HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server"
)
foreach ($basePath in $basePaths) {
if (!(Test-Path $basePath)) {
continue
}
try {
$children = Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue
foreach ($child in $children) {
$instanceId = $child.PSChildName
# Match keys like MSSQL16.SQLEXPRESS, MSSQL15.MSSQLSERVER, etc.
$escapedInstance = [regex]::Escape($InstanceName)
if ($instanceId -notmatch "^MSSQL\d+\.$escapedInstance$") {
continue
}
$setupPath = Join-Path $child.PSPath "Setup"
if (Test-Path $setupPath) {
$setup = Get-ItemProperty -Path $setupPath -ErrorAction SilentlyContinue
if ($null -ne $setup) {
return [PSCustomObject]@{
InstanceId = $instanceId
RegistrySetupPath = $setupPath
Edition = $setup.Edition
Version = $setup.Version
PatchLevel = $setup.PatchLevel
SQLPath = $setup.SQLPath
SQLDataRoot = $setup.SQLDataRoot
}
}
}
}
}
catch {
Write-DebugLine "Failed enumerating $basePath : $($_.Exception.Message)"
}
}
return [PSCustomObject]@{
InstanceId = ""
RegistrySetupPath = ""
Edition = ""
Version = ""
PatchLevel = ""
SQLPath = ""
SQLDataRoot = ""
}
}
function Get-SqlSetupInfo {
param(
[string]$InstanceName,
[string]$InstanceId
)
if (-not (Test-IsBlank $InstanceId)) {
$setupPaths = @(
"HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceId\Setup",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SQL Server\$InstanceId\Setup"
)
foreach ($setupPath in $setupPaths) {
if (Test-Path $setupPath) {
try {
$setup = Get-ItemProperty -Path $setupPath -ErrorAction Stop
return [PSCustomObject]@{
InstanceId = $InstanceId
RegistrySetupPath = $setupPath
Edition = $setup.Edition
Version = $setup.Version
PatchLevel = $setup.PatchLevel
SQLPath = $setup.SQLPath
SQLDataRoot = $setup.SQLDataRoot
}
}
catch {
Write-DebugLine "Failed reading setup path $setupPath : $($_.Exception.Message)"
}
}
}
}
# Fallback: enumerate SQL Server registry keys and match MSSQLxx.InstanceName
return Find-SqlSetupInfoByInstanceName -InstanceName $InstanceName
}
function Get-SqlInfoByConnection {
param(
[string]$ServerInstance,
[int]$TimeoutSeconds
)
$query = @"
SELECT
CAST(SERVERPROPERTY('Edition') AS nvarchar(128)) AS Edition,
CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS ProductVersion,
CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)) AS ProductLevel,
CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)) AS ProductUpdateLevel,
CAST(SERVERPROPERTY('ProductUpdateReference') AS nvarchar(128)) AS ProductUpdateReference,
CAST(SERVERPROPERTY('EngineEdition') AS nvarchar(128)) AS EngineEdition;
"@
try {
$connectionString = "Server=$ServerInstance;Database=master;Integrated Security=True;TrustServerCertificate=True;Connection Timeout=$TimeoutSeconds;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$command = $connection.CreateCommand()
$command.CommandText = $query
$command.CommandTimeout = $TimeoutSeconds
$connection.Open()
$reader = $command.ExecuteReader()
$data = $null
while ($reader.Read()) {
$data = [PSCustomObject]@{
Edition = $reader["Edition"]
ProductVersion = $reader["ProductVersion"]
ProductLevel = $reader["ProductLevel"]
ProductUpdateLevel = $reader["ProductUpdateLevel"]
ProductUpdateReference = $reader["ProductUpdateReference"]
EngineEdition = $reader["EngineEdition"]
ConnectionStatus = "Success"
ConnectionError = ""
}
}
$reader.Close()
$connection.Close()
if ($null -eq $data) {
return [PSCustomObject]@{
Edition = ""
ProductVersion = ""
ProductLevel = ""
ProductUpdateLevel = ""
ProductUpdateReference = ""
EngineEdition = ""
ConnectionStatus = "NoDataReturned"
ConnectionError = ""
}
}
return $data
}
catch {
return [PSCustomObject]@{
Edition = ""
ProductVersion = ""
ProductLevel = ""
ProductUpdateLevel = ""
ProductUpdateReference = ""
EngineEdition = ""
ConnectionStatus = "Failed"
ConnectionError = $_.Exception.Message
}
}
}
Write-DebugLine "Starting SQL detection on $ComputerName"
Write-DebugLine "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
Write-DebugLine "64-bit process: $([Environment]::Is64BitProcess)"
$AllSqlServices = Get-AllSqlServices
$SqlEngineServices = Get-SqlEngineServices -AllSqlServices $AllSqlServices
$AllSqlServicesText = Convert-ServiceListToText -Services $AllSqlServices
$SqlEngineServicesText = Convert-ServiceListToText -Services $SqlEngineServices
$HasSqlService = (@($AllSqlServices).Count -gt 0)
$HasSqlEngineService = (@($SqlEngineServices).Count -gt 0)
$HasRunningSqlEngineService = (@($SqlEngineServices | Where-Object { $_.Status -eq "Running" }).Count -gt 0)
if ($HasSqlEngineService) {
foreach ($engineService in @($SqlEngineServices)) {
$instanceName = Get-InstanceNameFromServiceName -ServiceName $engineService.Name
$serverInstance = Get-ServerInstanceName -InstanceName $instanceName
$instanceId = Get-RegistryInstanceIdFromInstanceName -InstanceName $instanceName
$setupInfo = Get-SqlSetupInfo -InstanceName $instanceName -InstanceId $instanceId
if (Test-IsBlank $instanceId) {
$instanceId = $setupInfo.InstanceId
}
$edition = $setupInfo.Edition
$productVersion = $setupInfo.Version
$patchLevel = $setupInfo.PatchLevel
if (Test-IsBlank $productVersion) {
$productVersion = $patchLevel
}
$connectionStatus = "NotAttempted"
$connectionError = ""
# If registry did not return version/edition, try SQL connection when service is running.
if (
!$SkipSqlConnection -and
$engineService.Status -eq "Running" -and
((Test-IsBlank $edition) -or (Test-IsBlank $productVersion))
) {
$connectionData = Get-SqlInfoByConnection -ServerInstance $serverInstance -TimeoutSeconds $ConnectionTimeoutSeconds
$connectionStatus = $connectionData.ConnectionStatus
$connectionError = $connectionData.ConnectionError
if (-not (Test-IsBlank $connectionData.Edition)) {
$edition = $connectionData.Edition
}
if (-not (Test-IsBlank $connectionData.ProductVersion)) {
$productVersion = $connectionData.ProductVersion
}
if (Test-IsBlank $patchLevel) {
$patchLevel = $connectionData.ProductVersion
}
}
$sqlVersionYear = Get-SqlVersionYear -ProductVersion $productVersion
$risk = Get-RiskClassification `
-Edition $edition `
-HasSqlEngineService $HasSqlEngineService `
-HasRunningSqlEngineService $HasRunningSqlEngineService
$Results += [PSCustomObject]@{
DeviceName = $ComputerName
DetectionType = "Database Engine Service"
ServerInstance = $serverInstance
InstanceName = $instanceName
InstanceId = $instanceId
SqlVersionYear = $sqlVersionYear
Edition = $edition
ProductVersion = $productVersion
PatchLevel = $patchLevel
ServiceName = $engineService.Name
ServiceStatus = $engineService.Status.ToString()
HasSqlService = $HasSqlService
HasSqlEngineService = $HasSqlEngineService
HasRunningSqlEngineService = $HasRunningSqlEngineService
AllSqlServices = $AllSqlServicesText
SqlEngineServices = $SqlEngineServicesText
RegistryPath = $setupInfo.RegistrySetupPath
ConnectionStatus = $connectionStatus
ConnectionError = $connectionError
RiskClassification = $risk
CollectionStatus = "Success"
Notes = "SQL Database Engine detected from Windows service."
}
}
}
else {
$notes = ""
if ($HasSqlService) {
$notes = "SQL services found, but no SQL Database Engine service was found. Example: SQLBrowser/SQLWriter only."
}
else {
$notes = "No SQL services found."
}
$risk = Get-RiskClassification `
-Edition "" `
-HasSqlEngineService $HasSqlEngineService `
-HasRunningSqlEngineService $HasRunningSqlEngineService
$Results += [PSCustomObject]@{
DeviceName = $ComputerName
DetectionType = "No Database Engine Service"
ServerInstance = ""
InstanceName = ""
InstanceId = ""
SqlVersionYear = ""
Edition = ""
ProductVersion = ""
PatchLevel = ""
ServiceName = ""
ServiceStatus = ""
HasSqlService = $HasSqlService
HasSqlEngineService = $HasSqlEngineService
HasRunningSqlEngineService = $HasRunningSqlEngineService
AllSqlServices = $AllSqlServicesText
SqlEngineServices = $SqlEngineServicesText
RegistryPath = ""
ConnectionStatus = ""
ConnectionError = ""
RiskClassification = $risk
CollectionStatus = "NoInstanceFound"
Notes = $notes
}
}
# Output
if (-not (Test-IsBlank $CsvPath)) {
$folder = Split-Path $CsvPath -Parent
if (-not (Test-IsBlank $folder) -and !(Test-Path $folder)) {
New-Item -ItemType Directory -Path $folder -Force | Out-Null
}
$Results | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8
Write-Output "CSV exported to: $CsvPath"
}
else {
foreach ($item in $Results) {
Write-Output ""
Write-Output "============================================================"
Write-Output "SQL Server Detection Result"
Write-Output "============================================================"
$item |
Select-Object `
DeviceName,
DetectionType,
ServerInstance,
InstanceName,
InstanceId,
SqlVersionYear,
Edition,
ProductVersion,
PatchLevel,
ServiceName,
ServiceStatus,
HasSqlService,
HasSqlEngineService,
HasRunningSqlEngineService,
AllSqlServices,
SqlEngineServices,
RegistryPath,
ConnectionStatus,
ConnectionError,
RiskClassification,
CollectionStatus,
Notes |
Format-List |
Out-String -Width 4096 |
Write-Output
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment