Public/Invoke-mssAddDatabaseToAvailabilityGroup.TempPoint.ps1
|
<#
.SYNOPSIS Fügt eine oder mehrere Datenbanken zu einer Always On-Verfügbarkeitsgruppe hinzu (AutoSeed). .DESCRIPTION - Prüft, ob die Datenbank bereits in einer AG ist. - Stellt den Recovery-Modus auf Full (falls nötig). - Löscht vorhandene Datenbanken auf allen sekundären Replikaten. - Fügt die Datenbank mit Automatic Seeding zur AG hinzu. - Bei -All werden die Datenbanken sequentiell hinzugefügt, um Last zu vermeiden. .PARAMETER SqlInstance Primäre SQL-Instanz (Standard: Computername). .PARAMETER SqlCredential Anmeldeinformationen. .PARAMETER AvailabilityGroup Name der Ziel-Verfügbarkeitsgruppe (Pflicht). .PARAMETER Database Name oder Array von Datenbanken. Wird ignoriert, wenn -All gesetzt ist. .PARAMETER All Alle Benutzerdatenbanken (die noch nicht in einer AG sind) hinzufügen. .PARAMETER EnableException Ausnahmen durchlassen. .PARAMETER Confirm Bestätigung anfordern. .PARAMETER WhatIf Nur testen. .EXAMPLE Add-mssDatabaseToAvailabilityGroup -AvailabilityGroup "AG1" -Database "SalesDB" .EXAMPLE Add-mssDatabaseToAvailabilityGroup -AvailabilityGroup "AG1" -All .NOTES Setzt Automatic Seeding auf allen Replikaten voraus (kann separat mit Invoke-mssSqlAlwaysOnAutoseeding aktiviert werden). #> function Invoke-mssAddDatabaseToAvailabilityGroup { [CmdletBinding(DefaultParameterSetName = 'Specific', SupportsShouldProcess = $true, ConfirmImpact = 'None')] param ( [Parameter(Mandatory = $false, Position = 0)] [string]$SqlInstance, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential]$SqlCredential, [Parameter(Mandatory = $true)] [string]$AvailabilityGroup, [Parameter(Mandatory = $false, ParameterSetName = 'Specific')] [string[]]$Database, [Parameter(Mandatory = $false, ParameterSetName = 'All')] [switch]$All, [Parameter(Mandatory = $false)] [switch]$EnableException ) begin { $functionName = $MyInvocation.MyCommand.Name if (-not $PSBoundParameters.ContainsKey('SqlInstance') -or [string]::IsNullOrWhiteSpace($SqlInstance)) { $SqlInstance = $env:COMPUTERNAME } if (-not (Get-Module -ListAvailable -Name dbatools)) { throw "dbatools-Modul nicht gefunden." } Invoke-mssLogging -Message "Starte $functionName auf $SqlInstance, AG: $AvailabilityGroup" -FunctionName $functionName -Level "INFO" $results = @() } process { try { # Verfügbarkeitsgruppe validieren und sekundäre Replikate ermitteln $ag = Get-DbaAvailabilityGroup -SqlInstance $SqlInstance -SqlCredential $SqlCredential -AvailabilityGroup $AvailabilityGroup -ErrorAction Stop if (-not $ag) { throw "AG '$AvailabilityGroup' nicht gefunden." } $replicas = Get-DbaAgReplica -SqlInstance $SqlInstance -SqlCredential $SqlCredential -AvailabilityGroup $AvailabilityGroup $secondaryInstances = $replicas | Where-Object { $_.Role -eq 'Secondary' } | Select-Object -ExpandProperty Name # Datenbanken ermitteln $dbParams = @{ SqlInstance = $SqlInstance; SqlCredential = $SqlCredential; ExcludeSystem = $true; ErrorAction = 'Stop' } if ($EnableException) { $dbParams.EnableException = $true } if ($All) { $allDbs = Get-DbaDatabase @dbParams | Where-Object { $_.IsAccessible } $databases = @() foreach ($db in $allDbs) { $inAG = Get-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $db.Name -ErrorAction SilentlyContinue if (-not $inAG) { $databases += $db } } Invoke-mssLogging -Message "$($databases.Count) Datenbanken wurden für Hinzufügung ausgewählt." -FunctionName $functionName -Level "INFO" } elseif ($Database) { $dbParams.Database = $Database $databases = Get-DbaDatabase @dbParams | Where-Object { $_.IsAccessible } $missing = $Database | Where-Object { $_ -notin ($databases.Name) } if ($missing) { $msg = "Nicht gefunden: $($missing -join ', ')" Invoke-mssLogging -Message $msg -FunctionName $functionName -Level "WARNING" $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $missing -join ','; Status = "NotFound"; Message = $msg } } } else { throw "Weder -All noch -Database angegeben." } if (-not $databases) { Invoke-mssLogging -Message "Keine Datenbanken zum Hinzufügen." -FunctionName $functionName -Level "WARNING" return } # Sequentiell verarbeiten (bei -All wichtig für Last) $counter = 0 foreach ($db in $databases) { $counter++ $dbName = $db.Name Invoke-mssLogging -Message "Verarbeite Datenbank $counter von $($databases.Count): $dbName" -FunctionName $functionName -Level "INFO" # Prüfung ob bereits in AG (sicherheitshalber) $existingAg = Get-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $dbName -ErrorAction SilentlyContinue if ($existingAg) { $msg = "Datenbank '$dbName' ist bereits in AG '$($existingAg.AvailabilityGroupName)'. Überspringe." Invoke-mssLogging -Message $msg -FunctionName $functionName -Level "WARNING" $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "AlreadyInAG"; Message = $msg } continue } # Recovery-Modus auf Full setzen if ($db.RecoveryModel -ne 'Full') { $setRecoveryAction = "Setze Recovery-Modus für '$dbName' auf Full" if ($PSCmdlet.ShouldProcess($dbName, $setRecoveryAction)) { try { Invoke-mssLogging -Message $setRecoveryAction -FunctionName $functionName -Level "INFO" Set-DbaDbRecoveryModel -SqlInstance $SqlInstance -SqlCredential $SqlCredential -Database $dbName -RecoveryModel Full -ErrorAction Stop } catch { $errMsg = "Fehler beim Setzen des Recovery-Modus: $($_.Exception.Message)" Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw } $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "SetRecoveryFailed"; Message = $errMsg } continue } } else { $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "RecoverySkipped"; Message = "WhatIf: Recovery-Modus nicht geändert." } continue } } # Vorhandene Datenbank auf Secondaries löschen foreach ($secondary in $secondaryInstances) { $secDb = Get-DbaDatabase -SqlInstance $secondary -SqlCredential $SqlCredential -Database $dbName -ErrorAction SilentlyContinue if ($secDb) { $dropAction = "Lösche vorhandene Datenbank '$dbName' auf Secondary '$secondary'" if ($PSCmdlet.ShouldProcess($dbName, $dropAction)) { try { Invoke-mssLogging -Message $dropAction -FunctionName $functionName -Level "INFO" Remove-DbaDatabase -SqlInstance $secondary -SqlCredential $SqlCredential -Database $dbName -Confirm:$false -ErrorAction Stop } catch { $errMsg = "Fehler beim Löschen auf '$secondary': $($_.Exception.Message)" Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw } $results += [PSCustomObject]@{ SqlInstance = $secondary; DatabaseName = $dbName; Status = "DropOnSecondaryFailed"; Message = $errMsg } # Nicht abbrechen, versuchen trotzdem hinzuzufügen? } } else { $results += [PSCustomObject]@{ SqlInstance = $secondary; DatabaseName = $dbName; Status = "DropSkipped"; Message = "WhatIf: Löschen übersprungen." } } } } # Zur AG hinzufügen (mit Automatic Seeding) $addAction = "Füge Datenbank '$dbName' zur AG '$AvailabilityGroup' hinzu (AutoSeed)" if ($PSCmdlet.ShouldProcess($dbName, $addAction)) { try { Invoke-mssLogging -Message $addAction -FunctionName $functionName -Level "INFO" Add-DbaAgDatabase -SqlInstance $SqlInstance -SqlCredential $SqlCredential -AvailabilityGroup $AvailabilityGroup -Database $dbName -SeedingMode Automatic -ErrorAction Stop $results += [PSCustomObject]@{ SqlInstance = $SqlInstance DatabaseName = $dbName Status = "Success" Message = "Erfolgreich zur AG hinzugefügt." } } catch { $errMsg = "Fehler beim Hinzufügen: $($_.Exception.Message)" Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw } $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "AddFailed"; Message = $errMsg } } } else { $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $dbName; Status = "AddSkipped"; Message = "WhatIf: Hinzufügen übersprungen." } } } } catch { $errMsg = "Allgemeiner Fehler: $($_.Exception.Message)" Invoke-mssLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw } $results += [PSCustomObject]@{ SqlInstance = $SqlInstance; DatabaseName = $null; Status = "GlobalError"; Message = $errMsg } } } end { Invoke-mssLogging -Message "$functionName abgeschlossen." -FunctionName $functionName -Level "INFO" return $results } } |