Use SQL PS module
This commit is contained in:
118
backup.ps1
118
backup.ps1
@@ -9,11 +9,36 @@ param(
|
|||||||
[switch]$Force
|
[switch]$Force
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
|
||||||
# backup.ps1
|
# backup.ps1
|
||||||
#
|
#
|
||||||
# TODO: Parallelize backups for multiple DBs in the instance
|
# TODO: Parallelize backups for multiple DBs in the instance
|
||||||
# TODO: Use PowerShell SQL module instead of sqlcmd
|
|
||||||
|
# Import SQL Server PowerShell module
|
||||||
|
try {
|
||||||
|
# Try to import the newer SqlServer module first
|
||||||
|
if (Get-Module -ListAvailable -Name SqlServer) {
|
||||||
|
Import-Module SqlServer -ErrorAction Stop
|
||||||
|
Write-Host "INFO: SqlServer PowerShell module loaded successfully."
|
||||||
|
}
|
||||||
|
# Fall back to older SQLPS module if available
|
||||||
|
elseif (Get-Module -ListAvailable -Name SQLPS) {
|
||||||
|
Import-Module SQLPS -ErrorAction Stop
|
||||||
|
Write-Host "INFO: SQLPS PowerShell module loaded successfully."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw "No SQL Server PowerShell module found"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify Invoke-Sqlcmd is available
|
||||||
|
if (-not (Get-Command Invoke-Sqlcmd -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "Invoke-Sqlcmd command not available"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "ERROR: Failed to import SQL Server PowerShell module. Please install it using: Install-Module -Name SqlServer -AllowClobber"
|
||||||
|
Write-Host "ERROR: $($_.Exception.Message)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
$instanceName = $SqlInstance.Split('\')[1]
|
$instanceName = $SqlInstance.Split('\')[1]
|
||||||
|
|
||||||
@@ -158,16 +183,89 @@ if ((Get-Date).DayOfWeek -eq $fullBackupDay) {
|
|||||||
|
|
||||||
$query = "EXECUTE [dbo].[DatabaseBackup] @Databases = 'ALL_DATABASES', @Directory = '$directory', @BackupType = '$backupType', @Verify = 'N', @CleanupTime = $cleanupTime, @CheckSum = 'Y', @LogToTable = 'Y'"
|
$query = "EXECUTE [dbo].[DatabaseBackup] @Databases = 'ALL_DATABASES', @Directory = '$directory', @BackupType = '$backupType', @Verify = 'N', @CleanupTime = $cleanupTime, @CheckSum = 'Y', @LogToTable = 'Y'"
|
||||||
Write-Log "Executing backup type: $backupType"
|
Write-Log "Executing backup type: $backupType"
|
||||||
|
Write-Log "SQL Query: $query"
|
||||||
|
|
||||||
$sqlcmdOutput = & sqlcmd -S $SqlInstance -Q $query 2>&1
|
try {
|
||||||
$sqlcmdExitCode = $LASTEXITCODE
|
# Execute the backup using PowerShell SQL module with better error handling
|
||||||
|
# Capture verbose output from Ola H scripts
|
||||||
|
$infoMessages = @()
|
||||||
|
|
||||||
if ($sqlcmdExitCode -eq 0) {
|
# Create event handlers to capture SQL Server messages
|
||||||
foreach ($line in $sqlcmdOutput) {
|
$connection = New-Object System.Data.SqlClient.SqlConnection
|
||||||
Write-Log $line
|
$connection.ConnectionString = "Server=$SqlInstance;Integrated Security=true;Connection Timeout=30"
|
||||||
|
|
||||||
|
# Event handler for informational messages (PRINT statements)
|
||||||
|
$connection.add_InfoMessage({
|
||||||
|
param($sqlSender, $e)
|
||||||
|
$message = $e.Message
|
||||||
|
if ($message -and $message.Trim() -ne "") {
|
||||||
|
$script:infoMessages += $message
|
||||||
|
Write-Log "SQL INFO: $message"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
$connection.Open()
|
||||||
|
|
||||||
|
$command = New-Object System.Data.SqlClient.SqlCommand
|
||||||
|
$command.Connection = $connection
|
||||||
|
$command.CommandText = $query
|
||||||
|
$command.CommandTimeout = 0 # No timeout for backup operations
|
||||||
|
|
||||||
|
Write-Log "Executing SQL command with message capture..."
|
||||||
|
|
||||||
|
# Execute and capture any result sets
|
||||||
|
$reader = $command.ExecuteReader()
|
||||||
|
|
||||||
|
# Process any result sets
|
||||||
|
while ($reader.Read()) {
|
||||||
|
$rowData = @()
|
||||||
|
for ($i = 0; $i -lt $reader.FieldCount; $i++) {
|
||||||
|
$rowData += "$($reader.GetName($i)): $($reader.GetValue($i))"
|
||||||
|
}
|
||||||
|
if ($rowData.Count -gt 0) {
|
||||||
|
Write-Log "SQL RESULT: $($rowData -join ', ')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$reader.Close()
|
||||||
}
|
}
|
||||||
Write-Log "$backupType Backup execution completed."
|
finally {
|
||||||
} else {
|
if ($connection.State -eq [System.Data.ConnectionState]::Open) {
|
||||||
Write-Log "ERROR: Backup execution failed. Exit code: $sqlcmdExitCode. Output: $sqlcmdOutput"
|
$connection.Close()
|
||||||
|
}
|
||||||
|
$connection.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log "$backupType Backup execution completed successfully."
|
||||||
|
Write-Log "Total informational messages captured: $($infoMessages.Count)"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log "ERROR: Backup execution failed with exception: $($_.Exception.Message)"
|
||||||
|
|
||||||
|
# Log additional SQL Server error details if available
|
||||||
|
if ($_.Exception.InnerException) {
|
||||||
|
Write-Log "ERROR: Inner Exception: $($_.Exception.InnerException.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for SQL Server specific errors
|
||||||
|
if ($_.Exception -is [System.Data.SqlClient.SqlException]) {
|
||||||
|
Write-Log "ERROR: SQL Server Error Details:"
|
||||||
|
foreach ($sqlError in $_.Exception.Errors) {
|
||||||
|
Write-Log "ERROR: Severity: $($sqlError.Class), State: $($sqlError.State), Number: $($sqlError.Number)"
|
||||||
|
Write-Log "ERROR: Message: $($sqlError.Message)"
|
||||||
|
if ($sqlError.Procedure) {
|
||||||
|
Write-Log "ERROR: Procedure: $($sqlError.Procedure), Line: $($sqlError.LineNumber)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean up connection if it exists
|
||||||
|
if ($connection -and $connection.State -eq [System.Data.ConnectionState]::Open) {
|
||||||
|
$connection.Close()
|
||||||
|
$connection.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user