Files
Cloud-20Engineering/Powershell/Lists/SQL/SQLUserCheck.ps1
Jurjen Ladenius a226ca97ac added documetation
2025-11-03 08:12:01 +01:00

318 lines
15 KiB
PowerShell
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
Comprehensive SQL Server database user audit across multiple Azure SQL servers.
.DESCRIPTION
This script connects to multiple Azure SQL servers and databases to generate a comprehensive audit
report of all database users, including their authentication types, creation dates, and permissions.
It provides essential information for security auditing, compliance reporting, and user access management.
Features:
• Multi-server database user enumeration across Azure SQL instances
• Authentication type detection (SQL, Windows, Azure AD)
• User creation and modification date tracking
• Comprehensive CSV reporting with timestamped output files
• Azure AD authentication using access tokens
• Automatic database discovery per server
.PARAMETER ServerList
Array of Azure SQL server FQDNs to audit. If not specified, uses a default list of common servers.
Each server should be provided as a fully qualified domain name (e.g., 'servername.database.windows.net').
.EXAMPLE
.\SQLUserCheck.ps1
Executes a complete user audit across all default Azure SQL servers and databases.
.EXAMPLE
.\SQLUserCheck.ps1 -ServerList @('signin-effectory.database.windows.net', 'c0m7f8nybr.database.windows.net')
Audits users on specific Azure SQL servers instead of using the default server list.
.EXAMPLE
Connect-AzAccount
.\SQLUserCheck.ps1
Ensures Azure authentication is established before running the SQL user audit.
.INPUTS
None. This script does not accept pipeline input.
.OUTPUTS
System.IO.FileInfo
Generates a timestamped CSV file containing user audit results with the following columns:
- ServerName: Azure SQL server name
- DatabaseName: Database name within the server
- UserName: Database user account name
- CreateDate: User account creation timestamp
- ModifyDate: Last modification timestamp
- Type: User principal type (User, Role, etc.)
- AuthenticationType: Authentication method (SQL_USER, WINDOWS_USER, EXTERNAL_USER)
.NOTES
Requires PowerShell 5.1 or later
Requires SqlServer PowerShell module
Requires Az.Accounts PowerShell module for Azure authentication
Prerequisites:
- Must be connected to Azure (Connect-AzAccount)
- Requires appropriate SQL Server permissions on target databases
- Network connectivity to Azure SQL servers
Security Considerations:
- Uses Azure AD authentication with access tokens
- Does not store or transmit SQL credentials
- Audit trail is maintained in timestamped CSV files
.LINK
https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-principals-transact-sql
https://docs.microsoft.com/en-us/azure/azure-sql/database/authentication-aad-overview
.COMPONENT
SqlServer PowerShell Module, Azure PowerShell Module
.ROLE
Database Administration, Security Auditing, Compliance Reporting
.FUNCTIONALITY
Azure SQL Server user auditing, database security assessment, access management reporting
#>
param(
[Parameter(Mandatory = $false, HelpMessage = "Array of Azure SQL server FQDNs to audit")]
[string[]]$ServerList = @(
'c0m7f8nybr.database.windows.net',
'calculations.database.windows.net',
'effectory.database.windows.net',
'effectorycore.database.windows.net',
'logit-backup.database.windows.net',
'mhpfktialk.database.windows.net',
'participants.database.windows.net',
'signin-effectory.database.windows.net',
'sqlserver01prod.6a1f4aa9f43a.database.windows.net'
)
)
Import-Module SqlServer
# Ensure Azure authentication is available
# Uncomment the following lines if not already authenticated to Azure
#Clear-AzContext
#Connect-AzAccount
Write-Host "======================================================================================================================================================================"
Write-Host "Creating comprehensive SQL user audit across Azure SQL servers."
Write-Host "===================================================================================================================================================================="
# Generate timestamped output filename
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
$filename = ".\$date SQL User check.csv"
Write-Host "📄 Output will be saved to: $filename" -ForegroundColor Cyan
<#
.SYNOPSIS
Data structure for SQL Server database user information.
.DESCRIPTION
This class represents a database user record containing essential information
for security auditing and access management. Each instance captures user
details from a specific database on a specific server.
.NOTES
Properties align with sys.database_principals system catalog view columns
for consistent data representation across different SQL Server versions.
#>
class UserItem {
[string] $ServerName = "" # Azure SQL server name
[string] $DatabaseName = "" # Database name where user exists
[string] $UserName = "" # Database user principal name
[string] $CreateDate = "" # User creation timestamp
[string] $ModifyDate = "" # Last modification timestamp
[string] $Type = "" # Principal type (SQL_USER, WINDOWS_USER, etc.)
[string] $AuthenticationType = "" # Authentication method (SQL, Windows, Azure AD)
}
Write-Host "🎯 Configured to audit $($ServerList.Count) Azure SQL servers" -ForegroundColor Green
# SQL query to discover all databases on each server
# Excludes system databases that are not relevant for user auditing
$databaseListQuery = @'
SELECT name, database_id, create_date
FROM sys.databases
WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')
ORDER BY name;
'@
# SQL query to retrieve database user information
# Filters out roles ('R' type) and focuses on actual user principals
# Excludes 'guest' user which exists by default in all databases
$userListQuery = @'
SELECT @@SERVERNAME as serverName,
DB_NAME() as databaseName,
name as username,
create_date,
modify_date,
type_desc as type,
authentication_type_desc as authentication_type
FROM sys.database_principals
WHERE type NOT IN ('R') -- Exclude database roles
AND sid IS NOT NULL -- Exclude built-in principals without SIDs
AND name NOT IN ('dbo', 'guest') -- Exclude default dbo and guest user
AND name NOT LIKE '##%' -- Exclude system-generated users
ORDER BY name;
'@
# Initialize audit counters
$totalServersProcessed = 0
$totalDatabasesProcessed = 0
$totalUsersFound = 0
# Main server processing loop
foreach ($server in $ServerList) {
$totalServersProcessed++
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
Write-Host "🖥️ Processing Server [$server] ($totalServersProcessed of $($ServerList.Count))" -ForegroundColor Cyan
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
try {
# Get Azure AD access token for SQL Database authentication
# This provides secure, passwordless authentication to Azure SQL
Write-Host "🔐 Obtaining Azure AD access token for SQL authentication..." -ForegroundColor Yellow
$access_token_secure = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
$access_token = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($access_token_secure))
# Configure secure connection string for Azure SQL
$connectionString = "Data Source=$server;Initial Catalog=master;Persist Security Info=False;Encrypt=True;TrustServerCertificate=False;Application Name=CloudEngineering-UserAudit"
# Discover all user databases on the current server
Write-Host "📋 Discovering databases on server..." -ForegroundColor Gray
$databases = Invoke-Sqlcmd -Query $databaseListQuery -ConnectionString $connectionString -AccessToken $access_token -ErrorAction Stop
Write-Host "✅ Found $($databases.Count) user databases to audit" -ForegroundColor Green
# Process each database on the current server
foreach ($database in $databases) {
$totalDatabasesProcessed++
Write-Host " 📊 Auditing Database [$($database.name)]" -ForegroundColor White
try {
[UserItem[]]$Result = @()
# Configure database-specific connection string
$databaseName = $database.name
$databaseConnectionString = "Data Source=$server;Initial Catalog=$databaseName;Persist Security Info=False;Encrypt=True;TrustServerCertificate=False;Application Name=CloudEngineering-UserAudit"
# Query database users and their authentication details
$users = Invoke-Sqlcmd -Query $userListQuery -ConnectionString $databaseConnectionString -AccessToken $access_token -ErrorAction Stop
# Process each user found in the database
foreach ($user in $users) {
$totalUsersFound++
[UserItem] $userItem = [UserItem]::new()
$userItem.ServerName = $server
$userItem.DatabaseName = $database.name
$userItem.UserName = $user.username
$userItem.CreateDate = $user.create_date
$userItem.ModifyDate = $user.modify_date
$userItem.Type = $user.type
$userItem.AuthenticationType = $user.authentication_type
$Result += $userItem
}
# Export results for this database to CSV
if ($Result.Count -gt 0) {
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
Write-Host " ✅ Found $($Result.Count) users in database [$($database.name)]" -ForegroundColor Green
} else {
Write-Host " No users found in database [$($database.name)]" -ForegroundColor Gray
}
}
catch {
Write-Warning " ❌ Failed to audit database [$($database.name)]: $($_.Exception.Message)"
}
}
}
catch {
Write-Warning "❌ Failed to process server [$server]: $($_.Exception.Message)"
Write-Warning " This may be due to connectivity issues or insufficient permissions"
}
}
# Generate comprehensive audit summary
Write-Host "======================================================================================================================================================================"
Write-Host "📊 SQL User Audit Summary" -ForegroundColor Green
Write-Host "======================================================================================================================================================================"
Write-Host ""
Write-Host "Audit Results:" -ForegroundColor Cyan
Write-Host "=============="
Write-Host "• Servers Processed: $totalServersProcessed of $($ServerList.Count)" -ForegroundColor White
Write-Host "• Databases Audited: $totalDatabasesProcessed" -ForegroundColor White
Write-Host "• Total Users Found: $totalUsersFound" -ForegroundColor White
# Analyze authentication types if CSV file exists
if (Test-Path $fileName) {
try {
$csvData = Import-Csv $fileName
$sqlAuthUsers = ($csvData | Where-Object { $_.type -eq "SQL_USER" }).Count
$azureADUsers = ($csvData | Where-Object { $_.type -eq "EXTERNAL_USER" }).Count
$windowsUsers = ($csvData | Where-Object { $_.type -eq "WINDOWS_USER" }).Count
$otherUsers = $csvData.Count - $sqlAuthUsers - $azureADUsers - $windowsUsers
Write-Host ""
Write-Host "Authentication Type Breakdown:" -ForegroundColor Yellow
Write-Host "=============================="
Write-Host "• SQL Authentication Users: $sqlAuthUsers" -ForegroundColor $(if($sqlAuthUsers -gt 0) {'Red'} else {'Green'})
Write-Host "• Azure AD Users: $azureADUsers" -ForegroundColor Green
Write-Host "• Windows Authentication Users: $windowsUsers" -ForegroundColor White
if ($otherUsers -gt 0) {
Write-Host "• Other Authentication Types: $otherUsers" -ForegroundColor Gray
}
# Security recommendation if SQL users found
if ($sqlAuthUsers -gt 0) {
Write-Host ""
Write-Host "⚠️ Security Notice:" -ForegroundColor Red
Write-Host " $sqlAuthUsers SQL Authentication users detected." -ForegroundColor Yellow
Write-Host " Consider migrating to Azure AD authentication for enhanced security." -ForegroundColor Yellow
}
}
catch {
Write-Warning "Could not analyze authentication types: $($_.Exception.Message)"
}
}
Write-Host ""
if (Test-Path $fileName) {
$fileSize = (Get-Item $fileName).Length
Write-Host "📄 Results Export:" -ForegroundColor Cyan
Write-Host "=================="
Write-Host "• Output File: $fileName" -ForegroundColor White
Write-Host "• File Size: $([math]::Round($fileSize/1KB, 2)) KB" -ForegroundColor White
Write-Host ""
# Display sample of results if file exists and has content
try {
$sampleData = Import-Csv $fileName | Select-Object -First 5
if ($sampleData) {
Write-Host "📋 Sample Results (First 5 Users):" -ForegroundColor Cyan
Write-Host "===================================="
$sampleData | Format-Table -AutoSize
}
}
catch {
Write-Warning "Could not display sample results: $($_.Exception.Message)"
}
}
Write-Host "✅ SQL User audit completed successfully!" -ForegroundColor Green
Write-Host ""
Write-Host "📝 Next Steps:" -ForegroundColor Yellow
Write-Host "=============="
Write-Host "• Review the CSV file for user access patterns" -ForegroundColor White
Write-Host "• Identify users with inappropriate authentication types" -ForegroundColor White
Write-Host "• Validate user access against business requirements" -ForegroundColor White
Write-Host "• Consider implementing Azure AD authentication where applicable" -ForegroundColor White
Write-Host "======================================================================================================================================================================"
Write-Host "🏁 Audit process completed." -ForegroundColor Green