added documetation

This commit is contained in:
Jurjen Ladenius
2025-11-03 08:12:01 +01:00
parent 8840b0e300
commit a226ca97ac
37 changed files with 8315 additions and 1481 deletions

View File

@@ -1,90 +1,318 @@
<#
.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 SQL user list."
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 = ""
[string] $DatabaseName = ""
[string] $UserName = ""
[string] $CreateDate = ""
[string] $ModifyDate = ""
[string] $Type = ""
[string] $AuthenticationType = ""
[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)
}
$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')
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
order by name;
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,
SELECT @@SERVERNAME as serverName,
DB_NAME() as databaseName,
name as username,
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')
and sid is not null
and name != 'guest'
order by name;
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;
'@
foreach ($server in $serverlist) {
# Initialize audit counters
$totalServersProcessed = 0
$totalDatabasesProcessed = 0
$totalUsersFound = 0
# Main server processing loop
foreach ($server in $ServerList) {
$totalServersProcessed++
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
Write-Host "Server [$server)]"
Write-Host "🖥️ Processing Server [$server] ($totalServersProcessed of $($ServerList.Count))" -ForegroundColor Cyan
Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
$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))
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))
$connectionString = "Data Source=$server;Initial Catalog=master;Persist Security Info=False;Encrypt=True;TrustServerCertificate=False;Application Name=CloudEngineering";
# 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"
$databases = Invoke-Sqlcmd -Query $databaseListQuery -ConnectionString $connectionString -AccessToken $access_token
# 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
foreach ($database in $databases) {
# Process each database on the current server
foreach ($database in $databases) {
$totalDatabasesProcessed++
Write-Host " 📊 Auditing Database [$($database.name)]" -ForegroundColor White
Write-Host "Database [$($database.name)]"
try {
[UserItem[]]$Result = @()
[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"
$databaseName = $database.name
$databaseConnectionString = "Data Source=$server;Initial Catalog=$databaseName;Persist Security Info=False;Encrypt=True;TrustServerCertificate=False;Application Name=CloudEngineering";
# Query database users and their authentication details
$users = Invoke-Sqlcmd -Query $userListQuery -ConnectionString $databaseConnectionString -AccessToken $access_token -ErrorAction Stop
$users = Invoke-Sqlcmd -Query $userListQuery -ConnectionString $databaseConnectionString -AccessToken $access_token
# 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
}
foreach ($user in $users) {
[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)"
}
}
$Result | Export-Csv -Path $fileName -Append -NoTypeInformation
}
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 "Done."
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