From 5a26b80bb6723e564d7184f0cadd5c0ac229d00c Mon Sep 17 00:00:00 2001 From: James Pattinson Date: Wed, 22 Oct 2025 13:19:32 +0100 Subject: [PATCH] Use SQL PS module --- backup.ps1 | 120 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/backup.ps1 b/backup.ps1 index 6a38d7f..615d110 100644 --- a/backup.ps1 +++ b/backup.ps1 @@ -9,11 +9,36 @@ param( [switch]$Force ) -# # backup.ps1 # # 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] @@ -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'" Write-Log "Executing backup type: $backupType" +Write-Log "SQL Query: $query" -$sqlcmdOutput = & sqlcmd -S $SqlInstance -Q $query 2>&1 -$sqlcmdExitCode = $LASTEXITCODE - -if ($sqlcmdExitCode -eq 0) { - foreach ($line in $sqlcmdOutput) { - Write-Log $line +try { + # Execute the backup using PowerShell SQL module with better error handling + # Capture verbose output from Ola H scripts + $infoMessages = @() + + # Create event handlers to capture SQL Server messages + $connection = New-Object System.Data.SqlClient.SqlConnection + $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." -} else { - Write-Log "ERROR: Backup execution failed. Exit code: $sqlcmdExitCode. Output: $sqlcmdOutput" + finally { + if ($connection.State -eq [System.Data.ConnectionState]::Open) { + $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 }