diff --git a/backupmult.ps1 b/backupmult.ps1 index e7ec63e..02e2128 100644 --- a/backupmult.ps1 +++ b/backupmult.ps1 @@ -16,13 +16,12 @@ param( # Each job will automatically share the database load using DatabasesInParallel=Y # TODO: Log file management (don't just overwrite existing logs) -# TODO: Dynmically figure out MV channels and paths using Rubrik API # TODO: See if there is way to query QueueDatabase during backup to monitor progress $fullBackupDay = 'Thursday' $fullBackupOverdueDays = 7 $instanceName = $SqlInstance.Split('\')[1] -$logFile = "C:\Rubrik\backup-multi-$instanceName.log" +$logFile = "C:\Rubrik\logs\backup_$instanceName.log" $SAFile = "C:\Rubrik\scripts\rbksql.xml" function Write-Log($message, $jobId = "") { @@ -101,7 +100,13 @@ if ($clusterInstance) { $query.var.filter = @(Get-RscType -Name Filter) $query.var.filter[0].field = "NAME_EXACT_MATCH" $query.var.filter[0].Texts = $mvName - $mvDetail = $query.Invoke().nodes[0] + $mvResult = $query.Invoke() + if (-not $mvResult.nodes -or $mvResult.nodes.Count -eq 0) { + Write-Log "ERROR: Managed Volume '$mvName' not found. This may be due to insufficient permissions or the volume not existing." + Disconnect-Rsc + exit 1 + } + $mvDetail = $mvResult.nodes[0] Write-Log "Found Managed Volume: $($mvDetail.Name) (ID: $($mvDetail.Id), Status: $($mvDetail.hostDetail.Status), HostDetail Name: $($mvDetail.hostDetail.Name))" @@ -119,12 +124,19 @@ if ($clusterInstance) { $query.Var.input.update.slaClientConfig.clientHostId = $newHost.Id $query.Var.input.update.slaClientConfig.channelHostMountPaths = $mvDetail.ClientConfig.ChannelHostMountPaths $query.Var.input.update.slaClientConfig.backupScriptCommand = $mvDetail.ClientConfig.BackupScript.ScriptCommand - $query.Var.input.update.slaClientConfig.preBackupScriptCommand = $mvDetail.ClientConfig.PreBackupScript.ScriptCommand - $query.Var.input.update.slaClientConfig.preBackupScriptTimeout = $mvDetail.ClientConfig.PreBackupScript.Timeout + + # Only set pre-backup script fields if a pre-backup script was configured + if ($mvDetail.ClientConfig.PreBackupScript.ScriptCommand) { + $query.Var.input.update.slaClientConfig.preBackupScriptCommand = $mvDetail.ClientConfig.PreBackupScript.ScriptCommand + $query.Var.input.update.slaClientConfig.preBackupScriptTimeout = $mvDetail.ClientConfig.PreBackupScript.Timeout + $query.Var.input.update.slaClientConfig.shouldCancelBackupOnPreBackupScriptFailure = $mvDetail.ClientConfig.ShouldCancelBackupOnPreBackupScriptFailure + $query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $false + } else { + $query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $true + } + $query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupFailure = $true $query.Var.input.update.slaClientConfig.shouldDisablePostBackupScriptOnBackupSuccess = $true - $query.Var.input.update.slaClientConfig.shouldDisablePreBackupScript = $false - $query.Var.input.update.slaClientConfig.shouldCancelBackupOnPreBackupScriptFailure = $mvDetail.ClientConfig.ShouldCancelBackupOnPreBackupScriptFailure $query.gqlRequest().Variables @@ -155,9 +167,14 @@ try { $query.var.filter = @(Get-RscType -Name Filter) $query.var.filter[0].field = "NAME_EXACT_MATCH" $query.var.filter[0].Texts = $MvName - $mvDetail = $query.Invoke().nodes[0] + $mvDetail = $query.Invoke() - $paths = $mvDetail.ClientConfig.ChannelHostMountPaths + if (-not $mvDetail.nodes -or $mvDetail.nodes.Count -eq 0) { + Write-Log "ERROR: Managed Volume '$MvName' not found. This may be due to insufficient permissions or the volume not existing." + exit 1 + } + + $paths = $mvDetail.nodes[0].ClientConfig.ChannelHostMountPaths Write-Log "INFO: Retrieved paths: $($paths -join ', ')" } catch { Write-Log "ERROR: Failed to retrieve paths from Rubrik. $($_.Exception.Message)" @@ -208,7 +225,13 @@ function Get-BackupType($directoryParam) { if (-not (Test-Path $flagDir)) { New-Item -ItemType Directory -Path $flagDir -Force | Out-Null } - Set-Content $fullFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 + try { + Set-Content $fullFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 + Write-Log "INFO: Created full backup flag file: $fullFlag" + } catch { + Write-Log "ERROR: Failed to create full backup flag file: $fullFlag. $($_.Exception.Message)" + # Continue with backup but flag won't be set + } $reason = if($isFullBackupOverdue) { "overdue" } else { "scheduled" } return @{ Type = "FULL"; CleanupTime = 168; Reason = $reason } } else { @@ -221,7 +244,13 @@ function Get-BackupType($directoryParam) { if (-not (Test-Path $flagDir)) { New-Item -ItemType Directory -Path $flagDir -Force | Out-Null } - Set-Content $diffFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 + try { + Set-Content $diffFlag $today.ToString("yyyy-MM-dd") -Encoding UTF8 + Write-Log "INFO: Created diff backup flag file: $diffFlag" + } catch { + Write-Log "ERROR: Failed to create diff backup flag file: $diffFlag. $($_.Exception.Message)" + # Continue with backup but flag won't be set + } return @{ Type = "DIFF"; CleanupTime = 168; Reason = "differential scheduled" } } else { return @{ Type = "LOG"; CleanupTime = 24; Reason = "diff already taken today" } @@ -425,7 +454,7 @@ for ($i = 1; $i -le $Jobs; $i++) { $job = Start-BackupJob -jobId $i -sqlInstance $SqlInstance -query $query -baseLogFile $logFile $null = $jobList.Add($job) Write-Log "Started backup job $i (Job ID: $($job.Id))" - Start-Sleep -Milliseconds 100 # Small delay to stagger job starts + Start-Sleep -Milliseconds 4000 # Delay to stagger job starts } # Monitor jobs and capture output @@ -520,26 +549,26 @@ foreach ($job in $jobList) { } # Consolidate job logs into main log file -Write-Log "Consolidating job logs..." -for ($i = 1; $i -le $Jobs; $i++) { - $jobLogFile = $logFile -replace '\.log$', "-job$i.log" - Write-Log "Checking for job log file: $jobLogFile" - if (Test-Path $jobLogFile) { - try { - $jobContent = Get-Content $jobLogFile -ErrorAction Stop - Write-Log "Found $($jobContent.Count) lines in job $i log" - foreach ($line in $jobContent) { - Add-Content -Path $logFile -Value $line -Encoding UTF8 - } - Remove-Item $jobLogFile -Force - Write-Log "Consolidated log from job $i" - } catch { - Write-Log "WARNING: Could not consolidate log from job $i : $($_.Exception.Message)" - } - } else { - Write-Log "WARNING: Job log file not found for job $i" - } -} +#Write-Log "Consolidating job logs..." +#for ($i = 1; $i -le $Jobs; $i++) { +# $jobLogFile = $logFile -replace '\.log$', "-job$i.log" +# Write-Log "Checking for job log file: $jobLogFile" +# if (Test-Path $jobLogFile) { +# try { +# $jobContent = Get-Content $jobLogFile -ErrorAction Stop +# Write-Log "Found $($jobContent.Count) lines in job $i log" +# foreach ($line in $jobContent) { +# Add-Content -Path $logFile -Value $line -Encoding UTF8 +# } +# # Remove-Item $jobLogFile -Force +# Write-Log "Consolidated log from job $i" +# } catch { +# Write-Log "WARNING: Could not consolidate log from job $i : $($_.Exception.Message)" +# } +# } else { +# Write-Log "WARNING: Job log file not found for job $i" +# } +#} # Final status check using job output analysis $failedJobIds = $jobResults.Keys | Where-Object { $jobResults[$_].Failed -eq $true }