SQL Service Not Starting After Windows Updates using NT SERVICE\MSSQLSERVER , had to switch to Local System

I have created two scripts to detect file permissions and LogOn Security Permissions for NT SERVICE\MSSQLSERVER

# SQL Server File Permissions Checker - Updated with Auto-Install
# Run as Administrator
# Dynamically queries SQL for log file (.ldf) paths and checks permissions on the actual files

# Account to check
$EngineAccount = "NT SERVICE\MSSQLSERVER"

# SQL Instance name (default; for named, use "ServerName\InstanceName")
$SqlInstance = "."

# Auto-install SqlServer module if missing
if (-not (Get-Module -ListAvailable -Name SqlServer)) {
    Write-Host "Installing SqlServer module with -AllowClobber..." -ForegroundColor Yellow
    Install-Module -Name SqlServer -AllowClobber -Force -Scope CurrentUser
}
# Import the module
Import-Module SqlServer -ErrorAction Stop

# Function to query SQL log file paths (.ldf)
function Get-SqlLogFiles {
    # Query for all log file paths (type = 1 for logs)
    $filesQuery = "SELECT DISTINCT physical_name FROM sys.master_files WHERE type = 1;"
    $filesResult = Invoke-Sqlcmd -ServerInstance $SqlInstance -Query $filesQuery -TrustServerCertificate
    $logFiles = $filesResult | ForEach-Object { $_.physical_name } | Where-Object { $_ -like "*.ldf" }

    return $logFiles
}

# Get .ldf files dynamically
$LogFiles = Get-SqlLogFiles

if ($LogFiles.Count -eq 0) {
    Write-Host "No .ldf files retrieved from SQL. Check SQL connection/module." -ForegroundColor Red
    return
}

# Check permissions for the engine account on each .ldf file
$Accounts = @($EngineAccount)
foreach ($file in $LogFiles) {
    if (Test-Path $file) {
        $acl = Get-Acl $file

        Write-Host "File: $file" -ForegroundColor Green
        foreach ($acct in $Accounts) {
            $access = $acl.Access | Where-Object { $_.IdentityReference -eq $acct }

            Write-Host "  Account: $acct"
            if ($access) {
                Write-Host "    Permissions: $($access.FileSystemRights)" -ForegroundColor Green
                if ($access.FileSystemRights -match "FullControl|Modify") {
                    Write-Host "    Status: Good (has write access)" -ForegroundColor Green
                } else {
                    Write-Host "    Status: Insufficient (needs Modify or Full Control)" -ForegroundColor Red
                }
            } else {
                Write-Host "    NO access - Grant if needed" -ForegroundColor Yellow
            }
            Write-Host ""
        }
        Write-Host "-----"
    } else {
        Write-Host "File not found: $file" -ForegroundColor Yellow
    }
}

Write-Host "Check complete! Checked permissions on actual .ldf log files." -ForegroundColor Cyan
# Ultimate SQL Virtual Account Permissions Checker - Correct SIDs
# Run as Administrator
# Uses correct standard SIDs for default instance services

Write-Host "SQL Server Virtual Account Permissions Checker (Correct SIDs)" -ForegroundColor Cyan
Write-Host "==============================================================" -ForegroundColor Cyan
Write-Host ""

# SQL services to check (default instance)
$SqlServices = @(
    @{
        ServiceName    = "MSSQLSERVER"
        Display        = "SQL Server Engine (MSSQLSERVER)"
        VirtualAccount = "NT SERVICE\MSSQLSERVER"
        SID            = "S-1-5-80-3880718306-3832830129-1677859214-2598158968-1052248003"
    },
    @{
        ServiceName    = "SQLSERVERAGENT"
        Display        = "SQL Server Agent (SQLSERVERAGENT)"
        VirtualAccount = "NT SERVICE\SQLSERVERAGENT"
        SID            = "S-1-5-80-344959196-2060754871-2302487193-2804545603-1466107430"
    }
)

# Check current logon accounts
foreach ($svc in $SqlServices) {
    $service = Get-Service -Name $svc.ServiceName -ErrorAction SilentlyContinue
    if (-not $service) {
        Write-Host "$($svc.Display): Service not installed" -ForegroundColor Yellow
        continue
    }

    $wmi = Get-WmiObject Win32_Service -Filter "Name='$($svc.ServiceName)'"
    $account = $wmi.StartName

    Write-Host "$($svc.Display)" -ForegroundColor Green
    Write-Host "  Status: $($service.Status)"
    if ($account -eq $svc.VirtualAccount) {
        Write-Host "  Logon : $account (Recommended virtual account)" -ForegroundColor Green
    } else {
        Write-Host "  Logon : $account" -ForegroundColor Yellow
    }
    Write-Host ""
}

# Export local security policy
$tempFile = [IO.Path]::GetTempFileName()
secedit /export /cfg $tempFile /quiet | Out-Null
$content = Get-Content $tempFile
Remove-Item $tempFile -Force

# Define privileges
$Privileges = @(
    @{ Name = "SeServiceLogonRight";           Display = "Log on as a service";                  GroupGrant = $true },
    @{ Name = "SeAssignPrimaryTokenPrivilege"; Display = "Replace a process-level token";       GroupGrant = $false },
    @{ Name = "SeIncreaseQuotaPrivilege";      Display = "Adjust memory quotas for a process";  GroupGrant = $false },
    @{ Name = "SeChangeNotifyPrivilege";       Display = "Bypass traverse checking";            GroupGrant = $false }
)

# Check each privilege
foreach ($priv in $Privileges) {
    Write-Host "Checking $($priv.Display) ($($priv.Name))..." -ForegroundColor Cyan

    $line = $content | Where-Object { $_ -match "^$($priv.Name)\s*=" }
    if (-not $line) {
        Write-Host "  Privilege not found in policy export." -ForegroundColor Yellow
        Write-Host ""
        continue
    }

    $assignments = ($line -split "=", 2)[1].Trim()
    $entries = $assignments -split "," | ForEach-Object { ($_.Trim() -replace '^\*', '').Trim().ToLower() } | Where-Object { $_ }

    $hasAllServicesGroup = $entries -contains "s-1-5-80-0"
    $coveredServices = @()

    foreach ($svc in $SqlServices) {
        $lowerSid = $svc.SID.ToLower()
        $lowerAccount = $svc.VirtualAccount.ToLower()
        $lowerShort = $svc.ServiceName.ToLower()
        $lowerDoubleSlash = "nt service\\$($svc.ServiceName.ToLower())"

        if ($entries -contains $lowerSid -or $entries -contains $lowerAccount -or $entries -contains $lowerShort -or $entries -contains $lowerDoubleSlash) {
            $coveredServices += $svc.Display
        }
    }

    if ($priv.GroupGrant) {
        if ($hasAllServicesGroup) {
            Write-Host "  Granted via NT SERVICE\ALL SERVICES (S-1-5-80-0) – covers Engine AND Agent" -ForegroundColor Green
        } else {
            Write-Host "  NT SERVICE\ALL SERVICES group not present" -ForegroundColor Yellow
        }
    }

    if ($coveredServices.Count -eq $SqlServices.Count) {
        Write-Host "  Granted to: SQL Server Engine AND SQL Server Agent" -ForegroundColor Green
    } elseif ($coveredServices.Count -eq 1) {
        Write-Host "  Granted to: $($coveredServices[0]) only" -ForegroundColor Yellow
    } elseif ($coveredServices.Count -eq 0) {
        Write-Host "  No grant found for Engine or Agent" -ForegroundColor Red
    } else {
        Write-Host "  Granted to: $($coveredServices -join ', ')" -ForegroundColor Green
    }

    Write-Host ""
}

# Instant File Initialization
Write-Host "Instant File Initialization (SeManageVolumePrivilege):" -ForegroundColor Cyan
$ifiLine = $content | Where-Object { $_ -match "^SeManageVolumePrivilege\s*=" }
if ($ifiLine) {
    $ifiAssign = ($ifiLine -split "=", 2)[1].Trim().ToLower()
    if ($ifiAssign -match "mssqlserver|sqlserveragent|s-1-5-80-|all services|localsystem") {
        Write-Host "  Granted (good for performance)" -ForegroundColor Green
    } else {
        Write-Host "  Not granted to SQL services" -ForegroundColor Yellow
    }
} else {
    Write-Host "  Not configured" -ForegroundColor Yellow
}

Write-Host ""
Write-Host "Check complete! Using standard SIDs for accuracy." -ForegroundColor Cyan
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...