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
