Files
DBAdmin/toolbox/Modules/SQLManager.psm1
T
2026-06-12 06:29:37 +00:00

214 lines
8.0 KiB
PowerShell

try {
Add-Type -AssemblyName System.Data
} catch {
# Ignore if already loaded or not available in some environments
}
function Import-DBAToolBoxDependencies {
<#
.SYNOPSIS
Ensures the dbatools module is available and imported.
#>
if (-not (Get-Module -ListAvailable dbatools)) {
throw "The 'dbatools' module is not installed. Please install it using 'Install-Module dbatools'."
}
if (-not (Get-Module dbatools)) {
Import-Module dbatools -ErrorAction Stop
}
# Configure dbatools to trust server certificates to prevent SSL/TLS certificate name mismatch / untrusted chain issues
try {
if (Get-Command Set-DbatoolsConfig -ErrorAction SilentlyContinue) {
Set-DbatoolsConfig -FullName 'sql.connection.trustcert' -Value $true -ErrorAction SilentlyContinue
}
} catch {
# Fallback if configuration cmdlet is not available
}
}
function Test-SQLConnection {
<#
.SYNOPSIS
Tests connection to a SQL Server instance and returns basic info using native ADO.NET.
#>
param(
[Parameter(Mandatory=$true)]
[string]$ServerInstance
)
$connString = "Server=$ServerInstance;Database=master;Integrated Security=True;Connection Timeout=5;TrustServerCertificate=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection($connString)
try {
$connection.Open()
# Query basic server properties
$cmd = $connection.CreateCommand()
$cmd.CommandText = "SELECT @@VERSION as Version, SERVERPROPERTY('Edition') as Edition, SERVERPROPERTY('MachineName') as Instance, SERVERPROPERTY('ProductVersion') as VerString"
$reader = $cmd.ExecuteReader()
if ($reader.Read()) {
$ver = if ($reader["VerString"] -ne [System.DBNull]::Value -and $reader["VerString"] -ne $null) { $reader["VerString"].ToString() } else { "Unknown" }
$edition = if ($reader["Edition"] -ne [System.DBNull]::Value -and $reader["Edition"] -ne $null) { $reader["Edition"].ToString() } else { "Unknown" }
$instance = if ($reader["Instance"] -ne [System.DBNull]::Value -and $reader["Instance"] -ne $null) { $reader["Instance"].ToString() } else { "" }
return @{
Success = $true
Instance = if ([string]::IsNullOrEmpty($instance)) { $ServerInstance } else { $instance }
Version = $ver
Edition = $edition
Status = "Online"
}
} else {
return @{ Success = $false; Error = "Failed to read server properties." }
}
} catch {
return @{ Success = $false; Error = $_.Exception.Message }
} finally {
if ($null -ne $connection -and $connection.State.ToString() -eq "Open") {
$connection.Close()
}
}
}
function Get-SQLDatabases {
<#
.SYNOPSIS
Gets database information for a SQL Server instance using native ADO.NET.
#>
param(
[Parameter(Mandatory=$true)]
[string]$ServerInstance
)
$connString = "Server=$ServerInstance;Database=master;Integrated Security=True;Connection Timeout=5;TrustServerCertificate=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection($connString)
try {
$connection.Open()
$cmd = $connection.CreateCommand()
# Primary query including backups
$cmd.CommandText = @"
SELECT
d.name,
d.state_desc,
COALESCE(SUM(CAST(f.size AS FLOAT) * 8.0 / 1024.0), 0.0) as size_mb,
d.recovery_model_desc,
(
SELECT MAX(b.backup_finish_date)
FROM msdb.dbo.backupset b
WHERE b.database_name = d.name AND b.type = 'D'
) AS last_full_backup,
(
SELECT MAX(b.backup_finish_date)
FROM msdb.dbo.backupset b
WHERE b.database_name = d.name AND b.type = 'L'
) AS last_log_backup
FROM sys.databases d
LEFT JOIN sys.master_files f ON d.database_id = f.database_id
GROUP BY d.name, d.state_desc, d.recovery_model_desc
"@
$adapter = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
$table = New-Object System.Data.DataTable
try {
$null = $adapter.Fill($table)
$hasBackups = $true
} catch {
# Fallback to query without backups if we don't have access to msdb or backupset table
$cmd.CommandText = @"
SELECT
d.name,
d.state_desc,
COALESCE(SUM(CAST(f.size AS FLOAT) * 8.0 / 1024.0), 0.0) as size_mb,
d.recovery_model_desc
FROM sys.databases d
LEFT JOIN sys.master_files f ON d.database_id = f.database_id
GROUP BY d.name, d.state_desc, d.recovery_model_desc
"@
$table.Clear()
$null = $adapter.Fill($table)
$hasBackups = $false
}
$dbList = @()
foreach ($row in $table.Rows) {
$sizeVal = 0.0
if ($row.size_mb -ne [System.DBNull]::Value -and $row.size_mb -ne $null) {
$sizeVal = [double]$row.size_mb
}
$dbName = if ($row.name -ne [System.DBNull]::Value -and $row.name -ne $null) { $row.name.ToString() } else { "Unknown" }
$dbStatus = if ($row.state_desc -ne [System.DBNull]::Value -and $row.state_desc -ne $null) { $row.state_desc.ToString() } else { "Unknown" }
$dbRecovery = if ($row.recovery_model_desc -ne [System.DBNull]::Value -and $row.recovery_model_desc -ne $null) { $row.recovery_model_desc.ToString() } else { "Simple" }
$fullBackup = "Unknown"
$logBackup = "Unknown"
if ($hasBackups) {
$fullBackup = "Never"
if ($row.Table.Columns.Contains("last_full_backup") -and $row.last_full_backup -ne [System.DBNull]::Value -and $row.last_full_backup -ne $null) {
$fullBackup = ([datetime]$row.last_full_backup).ToString("yyyy-MM-dd HH:mm:ss")
}
$logBackup = "Never"
if ($dbRecovery -eq "SIMPLE") {
$logBackup = "N/A (Simple)"
} elseif ($row.Table.Columns.Contains("last_log_backup") -and $row.last_log_backup -ne [System.DBNull]::Value -and $row.last_log_backup -ne $null) {
$logBackup = ([datetime]$row.last_log_backup).ToString("yyyy-MM-dd HH:mm:ss")
}
} else {
$fullBackup = "N/A (No Access)"
if ($dbRecovery -eq "SIMPLE") {
$logBackup = "N/A (Simple)"
} else {
$logBackup = "N/A (No Access)"
}
}
$dbList += [pscustomobject]@{
Name = $dbName
Status = $dbStatus
Size = "$([Math]::Round($sizeVal, 2)) MB"
RecoveryModel = $dbRecovery
LastFullBackup = $fullBackup
LastLogBackup = $logBackup
}
}
return $dbList
} catch {
throw "Failed to get databases: $($_.Exception.Message)"
} finally {
if ($null -ne $connection -and $connection.State.ToString() -eq "Open") {
$connection.Close()
}
}
}
function Get-SQLErrors {
<#
.SYNOPSIS
Gets SQL Server error log entries for the last hour using Get-DbaErrorLog.
#>
param(
[Parameter(Mandatory=$true)]
[string]$ServerInstance
)
try {
# Calculate time (1 hour ago)
$afterTime = (Get-Date).AddHours(-1)
$afterString = $afterTime.ToString("yyyy-MM-dd HH:mm:ss")
# Call dbatools cmdlet to fetch log entries
$logs = Get-DbaErrorLog -SqlInstance $ServerInstance -After $afterString -LogNumber 0 -ErrorAction Stop
# Clean select properties
$result = $logs | Select-Object LogDate, Source, Text
return $result
} catch {
throw "Failed to fetch SQL error log: $($_.Exception.Message)"
}
}
Export-ModuleMember -Function Import-DBAToolBoxDependencies, Test-SQLConnection, Get-SQLDatabases, Get-SQLErrors