How-To: Microsoft SQL Server 2025 Installation with Best Practices

AI Preview

Is this content worth your time? Use the quick preview to decide.

Welcome to Techaptic!

In today’s guide, we dive deep into the installation and enterprise-grade configuration of Microsoft SQL Server 2025.

While a standard installation might seem straightforward, a robust production environment requires detailed attention to prerequisites, disk optimizations, and post-installation configurations. In this post, we cover the entire process: from configuring optimized disk layouts for Data, Log, TempDB, and Backup files, to managing Active Directory service accounts, TempDB sizing, and memory limits. Follow along to ensure your database infrastructure is optimized for performance and security from day one.

🔗 Helpful Links

Video Tutorial

Used Commands


Displays SQL Server version.

SELECT @@VERSION

Checks post-installation SQL configurations for Default Instance along with TCP 1433 port.

<#
.SYNOPSIS
SQL Server 2025 Post-Install Network & Service Configuration Script

.DESCRIPTION
This script performs essential post-installation checks for a newly installed
SQL Server Default Instance.

It checks SQL Server services, enables TCP/IP, configures a static TCP port,
validates or creates a local Windows Firewall inbound rule, and verifies that
SQL Server is listening on the configured TCP port.

.NOTES
Author : Techaptic
Warning: This script must be run as Administrator on the SQL Server.
Scope : Default Instance only.

Customize before using with:
- Named Instance
- Failover Cluster
- Always On Availability Groups
- Non-standard SQL Server ports
- Environments where firewall rules are managed by GPO
#>

# Variables
$InstanceName = "MSSQLSERVER"
$ServiceName = "MSSQLSERVER"
$AgentServiceName = "SQLSERVERAGENT"
$TcpPort = "1433"
$FirewallRuleName = "SQL Server Database Engine - TCP $TcpPort"

# Admin Check
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "[ERROR] Please run this script as Administrator." -ForegroundColor Red
exit 1
}

Write-Host "Techaptic - SQL Server 2025 Post-Install Configuration Initiated..." -ForegroundColor Cyan
Write-Host "------------------------------------------------------------------" -ForegroundColor Cyan

function Start-SqlServiceIfNeeded {
param (
[Parameter(Mandatory = $true)]
[string]$Name
)

$Service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$Name'" -ErrorAction SilentlyContinue

if (-not $Service) {
return $null
}

if ($Service.State -ne "Running") {
Start-Service -Name $Name -ErrorAction Stop
Start-Sleep -Seconds 3
$Service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$Name'" -ErrorAction SilentlyContinue
}

return $Service
}

# 1. Check SQL Services & Service Accounts
Write-Host "Processing: SQL Server Services & Accounts... " -NoNewline

try {
$EngineService = Start-SqlServiceIfNeeded -Name $ServiceName
$AgentService = Get-CimInstance -ClassName Win32_Service -Filter "Name='$AgentServiceName'" -ErrorAction SilentlyContinue

if ($EngineService) {
$Msg = "Engine: $($EngineService.State) (Acct: $($EngineService.StartName))"

if ($AgentService) {
if ($AgentService.State -ne "Running" -and $AgentService.StartMode -eq "Auto") {
Start-Service -Name $AgentServiceName -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
$AgentService = Get-CimInstance -ClassName Win32_Service -Filter "Name='$AgentServiceName'" -ErrorAction SilentlyContinue
}

$Msg += " | Agent: $($AgentService.State) (Acct: $($AgentService.StartName))"
} else {
$Msg += " | Agent: Not found"
}

Write-Host "[SUCCESS] ($Msg)" -ForegroundColor Green
} else {
Write-Host "[ERROR] (SQL Server service '$ServiceName' not found)" -ForegroundColor Red
exit 1
}
} catch {
Write-Host "[ERROR] ($($_.Exception.Message))" -ForegroundColor Red
exit 1
}

# 2. Configure TCP/IP Protocol & Static Port
Write-Host "Processing: TCP/IP Protocol & Static Port ($TcpPort)... " -NoNewline

try {
$InstanceNamesRegPath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL"
$InstanceId = (Get-ItemProperty -Path $InstanceNamesRegPath -ErrorAction Stop).$InstanceName

if (-not $InstanceId) {
throw "Instance '$InstanceName' was not found in registry."
}

$TcpRegPath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceId\MSSQLServer\SuperSocketNetLib\Tcp"
$IpAllRegPath = Join-Path $TcpRegPath "IPAll"

$RestartRequired = $false

$CurrentTcp = Get-ItemProperty -Path $TcpRegPath -ErrorAction Stop
$CurrentIpAll = Get-ItemProperty -Path $IpAllRegPath -ErrorAction Stop

if ($CurrentTcp.Enabled -ne 1) {
Set-ItemProperty -Path $TcpRegPath -Name "Enabled" -Value 1 -ErrorAction Stop
$RestartRequired = $true
}

if ($CurrentTcp.ListenOnAllIPs -ne 1) {
Set-ItemProperty -Path $TcpRegPath -Name "ListenOnAllIPs" -Value 1 -ErrorAction Stop
$RestartRequired = $true
}

$CurrentDynamicPorts = [string]$CurrentIpAll.TcpDynamicPorts
$CurrentStaticPort = [string]$CurrentIpAll.TcpPort

if (-not [string]::IsNullOrWhiteSpace($CurrentDynamicPorts) -or $CurrentStaticPort -ne $TcpPort) {
Set-ItemProperty -Path $IpAllRegPath -Name "TcpDynamicPorts" -Value "" -ErrorAction Stop
Set-ItemProperty -Path $IpAllRegPath -Name "TcpPort" -Value $TcpPort -ErrorAction Stop
$RestartRequired = $true
}

if ($RestartRequired) {
Restart-Service -Name $ServiceName -Force -ErrorAction Stop
Start-Sleep -Seconds 5

$EngineService = Get-CimInstance -ClassName Win32_Service -Filter "Name='$ServiceName'" -ErrorAction SilentlyContinue

if ($EngineService -and $EngineService.State -eq "Running") {
$AgentService = Get-CimInstance -ClassName Win32_Service -Filter "Name='$AgentServiceName'" -ErrorAction SilentlyContinue

if ($AgentService -and $AgentService.StartMode -eq "Auto" -and $AgentService.State -ne "Running") {
Start-Service -Name $AgentServiceName -ErrorAction SilentlyContinue
}

Write-Host "[SUCCESS] (Enabled & configured. SQL Server service restarted)" -ForegroundColor Green
} else {
Write-Host "[WARNING] (Configuration changed, but SQL Server service state could not be confirmed)" -ForegroundColor Yellow
}
} else {
Write-Host "[SKIPPED] (Already configured)" -ForegroundColor Yellow
}
} catch {
Write-Host "[ERROR] ($($_.Exception.Message))" -ForegroundColor Red
}

# 3. Configure Local Windows Firewall Inbound Rule
Write-Host "Processing: Local Windows Firewall Inbound Rule... " -NoNewline

try {
$ExistingRules = Get-NetFirewallRule -DisplayName $FirewallRuleName -ErrorAction SilentlyContinue
$ValidRuleFound = $false

if ($ExistingRules) {
foreach ($Rule in $ExistingRules) {
$PortFilters = $Rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue

foreach ($PortFilter in $PortFilters) {
$RuleProfile = $Rule.Profile.ToString()

if (
$Rule.Enabled -eq "True" -and
$Rule.Direction -eq "Inbound" -and
$Rule.Action -eq "Allow" -and
$RuleProfile.Contains("Domain") -and
$RuleProfile.Contains("Private") -and
$PortFilter.Protocol -eq "TCP" -and
$PortFilter.LocalPort -eq $TcpPort
) {
$ValidRuleFound = $true
break
}
}

if ($ValidRuleFound) {
break
}
}
}

if ($ValidRuleFound) {
Write-Host "[SKIPPED] (Existing local firewall rule already allows TCP $TcpPort for Domain and Private profiles)" -ForegroundColor Yellow
} else {
if ($ExistingRules) {
$ExistingRules | Remove-NetFirewallRule -ErrorAction Stop
}

New-NetFirewallRule `
-DisplayName $FirewallRuleName `
-Direction Inbound `
-Protocol TCP `
-LocalPort $TcpPort `
-Action Allow `
-Profile Domain,Private `
-Description "Allows inbound SQL Server Database Engine traffic on TCP $TcpPort." `
-ErrorAction Stop | Out-Null

if ($ExistingRules) {
Write-Host "[SUCCESS] (Existing local firewall rule was incorrect and recreated for TCP $TcpPort)" -ForegroundColor Green
} else {
Write-Host "[SUCCESS] (Port $TcpPort allowed via new local firewall rule)" -ForegroundColor Green
}
}
} catch {
Write-Host "[ERROR] ($($_.Exception.Message))" -ForegroundColor Red
}

# 4. Verify TCP Listener
Write-Host "Processing: SQL Server TCP Listener Verification... " -NoNewline

try {
Start-Sleep -Seconds 2

$Listener = Get-NetTCPConnection -LocalPort $TcpPort -State Listen -ErrorAction SilentlyContinue |
Where-Object { $_.LocalAddress -eq "0.0.0.0" -or $_.LocalAddress -eq "::" -or $_.LocalAddress -eq "127.0.0.1" }

if ($Listener) {
Write-Host "[SUCCESS] (SQL Server appears to be listening on TCP $TcpPort)" -ForegroundColor Green
} else {
Write-Host "[WARNING] (No listening TCP connection detected on port $TcpPort. Check SQL Server Configuration Manager and service logs if remote connection fails.)" -ForegroundColor Yellow
}
} catch {
Write-Host "[WARNING] (Listener verification could not be completed: $($_.Exception.Message))" -ForegroundColor Yellow
}

Write-Host "------------------------------------------------------------------" -ForegroundColor Cyan
Write-Host "Process completed. SQL Server basic network configuration is ready." -ForegroundColor Green

Quiz


QUIZ-EN-How-To-Installation-Windows-SQL-Server-2025-with-Best-Practices-10
  • Question
  • Question
  • Question
  • Question
  • Question
  • Question
  • Question
  • Question
  • Question
  • Question

Full Transcript

Rating

Post Rating (EN)
Scroll to Top