mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
318 lines
15 KiB
PowerShell
318 lines
15 KiB
PowerShell
<#
|
||
.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 |