sqmSQLTool · Security & Compliance · 2026
Audit-ready in one hour.
Login audit, sysadmin accounts, SA hardening, TLS status, AD reconciliation — every security check in one module. Documented, reproducible, automatable.
Uwe Janke · Senior SQL Server DBA · dtcSoftware
Motivation
The SA account is always named "sa", always has sysadmin rights, and is still active on many systems. An attacker only has to guess the password — or it was never changed.
Employees leave the company, their AD account is disabled — but the SQL login stays active. Without regular reconciliation, ghost accounts pile up.
TLS 1.0 and 1.1 are classified as insecure (RFC 8996). Still active on many systems because turning it off is complex and automation is missing.
Sysadmin accounts, certificate expiry dates, TLS configuration, SQL-auth logins — every audit question means manual research, server by server.
Overview
Login audit, sysadmin accounts, SA hardening, AD reconciliation.
TLS protocol versions, encryption status, certificate assignment.
Create, import, and request certificates — the full lifecycle.
SQL Server policy management, password rotation, SA obfuscation.
Access rights
A full login audit: every login, roles, last login, SQL auth vs. Windows auth, status.
| 👤 Every login | Name, type (SQL / Windows / group), status |
| 🛡 Server roles | Sysadmin, SecurityAdmin, ServerAdmin, etc. |
| 📅 Last login | When did this login last connect? |
| ⚠ SQL auth | Every SQL login flagged — less secure than Windows auth |
| ❌ Disabled | Logins that are disabled but still exist |
| 💻 Database access | Which databases the login can access |
# Full login audit
Invoke-sqmLoginAudit `
-SqlInstance "SQL01"
# Only SQL-auth logins with sysadmin
Invoke-sqmLoginAudit `
-SqlInstance "SQL01" `
-Filter SqlAuthSysadmin
# Inactive for more than 90 days
Invoke-sqmLoginAudit `
-SqlInstance "SQL01" `
-InactiveDays 90
# Every instance, CSV for the audit
Get-Content "instances.txt" |
Invoke-sqmLoginAudit |
Export-Csv "login_audit.csv" `
-NoTypeInformation
Sysadmin control
Every account with the sysadmin role — Windows groups are expanded, so every indirect member becomes visible.
A Windows group as sysadmin looks tidy — but who's actually a member of that group? Get-sqmSysadminAccounts expands every group and lists each individual user.
# Every sysadmin account, groups included
Get-sqmSysadminAccounts `
-SqlInstance "SQL01"
# With AD group expansion
Get-sqmSysadminAccounts `
-SqlInstance "SQL01" `
-ExpandGroups
# Only unexpected accounts
Get-sqmSysadminAccounts `
-SqlInstance "SQL01" |
Where-Object {
$_.Name -notmatch "^sa$|svc_|sql_"
}
# Every instance, as CSV
Get-Content "instances.txt" |
Get-sqmSysadminAccounts `
-ExpandGroups |
Export-Csv "sysadmins.csv" `
-NoTypeInformation
SA hardening
Harden the SA account: rename it, disable it, or both — across every instance in one operation.
# Rename SA + disable it
Invoke-sqmSaObfuscation `
-SqlInstance "SQL01" `
-NewName "disabled_sa" `
-Disable
# Every instance
Get-Content "instances.txt" |
Invoke-sqmSaObfuscation `
-NewName "sa_disabled" `
-Disable
Sets a cryptographically random password for SA — worth doing as brute-force protection even when SA is disabled.
# Set a random password
New-sqmRandomSaPassword `
-SqlInstance "SQL01"
# Store the password in a vault
New-sqmRandomSaPassword `
-SqlInstance "SQL01" `
-SaveToVault `
-VaultPath "\\share\SecureVault"
# Every instance
Get-Content "instances.txt" |
New-sqmRandomSaPassword `
-SaveToVault
AD reconciliation
Checks the current AD status for every Windows login — disabled, locked, or expired accounts that are still active as a SQL login.
| Disabled | AD account disabled, SQL login still active |
| Locked | Account locked out in AD, but SQL access still possible |
| Expired | Password or account expired per AD |
| Not found | Account no longer exists in AD |
| Active | AD account is fine |
# AD status for every Windows login
Get-sqmADAccountStatus `
-SqlInstance "SQL01"
# Only problem accounts
Get-sqmADAccountStatus `
-SqlInstance "SQL01" `
-ShowProblemsOnly
# Every instance, CSV export
Get-Content "instances.txt" |
Get-sqmADAccountStatus `
-ShowProblemsOnly |
Export-Csv "orphaned_logins.csv" `
-NoTypeInformation
# Remove disabled ones directly (WhatIf!)
Get-sqmADAccountStatus `
-SqlInstance "SQL01" `
-RemoveDisabled -WhatIf
Network security
TLS protocol versions and encryption status across every SQL Server instance — which systems can still fall back to TLS 1.0 / 1.1?
| TLS version | 1.0 (insecure), 1.1 (outdated), 1.2 (ok), 1.3 (optimal) |
| SQL encryption | Is ForceEncryption enabled? |
| Certificate | Self-signed vs. CA-signed, expiry date |
| Cipher suites | Any weak encryption algorithms enabled? |
# TLS status for one instance
Get-sqmTlsStatus `
-ComputerName "SQL01"
# Every server, problems only
Get-Content "servers.txt" |
Get-sqmTlsStatus `
-ShowProblemsOnly
# CSV for the compliance report
Get-Content "servers.txt" |
Get-sqmTlsStatus |
Export-Csv "tls_compliance.csv" `
-NoTypeInformation
Certificate management
Assigns a certificate to a SQL Server service (registry entry + optional service restart).
# Assign a certificate (by thumbprint)
Set-sqmSqlTlsCertificate `
-ComputerName "SQL01" `
-Thumbprint "A1B2C3D4..." `
-RestartService
# Remove the certificate
Set-sqmSqlTlsCertificate `
-ComputerName "SQL01" `
-RemoveCertificate
New-sqmCertificateRequest — self-signed for dev/test only.Creates a self-signed certificate directly for SQL Server — correct EKU (Server Authentication), in the right store.
# Create a self-signed cert
New-sqmSqlCertificate `
-ComputerName "SQL01" `
-ValidYears 3
# Create + assign immediately
New-sqmSqlCertificate `
-ComputerName "SQL01" `
-ValidYears 3 `
-AssignToSqlService `
-RestartService
Certificate lifecycle
The full certificate lifecycle: create a CSR, get it signed, import it, assign it.
New-sqmCertificateRequest — generates a .req file with the correct SAN (FQDN, NetBIOS, cluster VNN).
Send the CSR to an internal or external CA — get a signed certificate back as .cer or .pfx.
Install-sqmCertificate — imports it into the correct store, sets permissions for the SQL Server service account.
Set-sqmSqlTlsCertificate — assign the certificate to the SQL Server service + restart.
# Step 1: create the CSR
New-sqmCertificateRequest `
-ComputerName "SQL01" `
-OutputPath "\\share\Certs" `
-AdditionalSAN "sql01-vnn","sql01.corp.local"
# Step 3: import the signed cert
Install-sqmCertificate `
-ComputerName "SQL01" `
-CertFile "\\share\Certs\SQL01.cer" `
-SetPermissions
# Step 4: assign + restart
Set-sqmSqlTlsCertificate `
-ComputerName "SQL01" `
-CertFile "\\share\Certs\SQL01.cer" `
-RestartService
Reference
| Task | Function | Output |
|---|---|---|
| Login audit | Invoke-sqmLoginAudit | Console + CSV |
| Sysadmin accounts | Get-sqmSysadminAccounts | Console + CSV |
| Rename/lock SA | Invoke-sqmSaObfuscation | Console |
| SA random password | New-sqmRandomSaPassword | Console |
| AD account reconciliation | Get-sqmADAccountStatus | Console + CSV |
| TLS status | Get-sqmTlsStatus | Console + CSV |
| Assign TLS certificate | Set-sqmSqlTlsCertificate | Console |
| Self-signed cert | New-sqmSqlCertificate | Certificate |
| Create a CSR | New-sqmCertificateRequest | .req file |
| Import a certificate | Install-sqmCertificate | Console |
Every instance, export to CSV, compare against last month
Escalate any new sysadmin immediately
Remove disabled accounts that still have a SQL login
Renew expiring certificates (90-day warning) ahead of time
Summary
Login audit CSV, sysadmin report, TLS status — every piece of audit evidence produced in one run.
Monthly runs always come back in the same format — compare against the prior period at the push of a button.
No instance gets forgotten — the pipeline processes every server from a list.
Rename + disable + random password, in one maintenance window, across every system.
Status of every system at a glance — targeted shutdown without manual registry digging.
Automatic warning 90 days ahead — never an expired SQL certificate in production again.