SQL Powershell: Remove-SqlAvailabilityDatabase

Я пишу сценарий Powershell для резервного копирования и восстановления базы данных в среде высокой доступности (все нужно делать с помощью SMO). Это включает в себя пару шагов (более или менее: удалить базу данных из группы доступности на первичном сервере, удалить базу данных на вторичном сервере, создать резервные копии, восстановить резервные копии, снова добавить базу данных).

Сценарий работал нормально, хотя выполнялся на одном из серверов баз данных. Но теперь мне нужно запустить его на сервере управления/приложений. Это дает мне теперь пару новых проблем...

Подключение к серверу работает нормально. Затем я читаю все базы данных из группы доступности:

$Global:ProdKopieDatabases = $server.AvailabilityGroups[$Global:ProdKopieAvailabailityGroup].AvailabilityDatabases

Если я проверю $ProdKopieDatabases, он покажет мне точное количество баз данных, которые я ожидаю. Это также объект типа Microsoft.SqlServer.Management.Smo.AvailabilityDatabase.

Далее по сценарию мне нужно удалить базу данных из группы доступности

foreach($DatabaseToRemove in $Global:ProdKopieDatabases)
    {
        try
        {
            Remove-SqlAvailabilityDatabase -InputObject $Global:ProdKopieDatabases[$DatabaseToRemove.Name.ToString()] -ErrorAction Stop
            #Remove-SqlAvailabilityDatabase -Path $($Private:MyAgPrimaryPath + "\AvailabilityDatabases\" + $DatabaseToRemove.Name.ToString()) -ErrorAction Stop
            Start-Sleep -Seconds 5
            Write-Host .. OK.
        }
        catch
        {
            Log-Write ($Error[0].ToString())
            Return 1
        }
    }

Если я проверю переменную $Global:ProdKopieDatabases перед первым foreach, я увижу все базы данных (т.е. 3). Но после Remove-SqlAvailabilityDatabase база данных, которая была удалена из группы, также была удалена из переменной $Global:ProdKopieDatabases. Поэтому, когда foreach доходит до второго раунда, я получаю ошибку:

Error: Collection was modified; enumeration operation may not execute.

Я не понимаю, почему? Как будто переменная "по ссылке" связана с базой данных доступности. Если причина в этом, как я могу это изменить?

Это даже происходит, если я пытаюсь добавить его в другую переменную и работать только с $c:

$c = New-Object Microsoft.SqlServer.Management.Smo.AvailabilityDatabase #$Global:ProdKopieDatabases
$c = $Global:ProdKopieDatabases | Select *

Пока я запускал скрипт непосредственно на SQL Server, я смог сделать это следующим образом.

$Private:MyAgPrimaryPath = "SQLSERVER:\SQL\$PrimaryServer\DEFAULT\AvailabilityGroups\$Global:ProdKopieAvailabailityGroup"

$Global:ProdKopieDatabases = dir $Private:MyAgPrimaryPath\AvailabilityDatabases

foreach был таким же, но удаление было другим:

Remove-SqlAvailabilityDatabase -Path $($Private:MyAgPrimaryPath + "\AvailabilityDatabases\" + $DatabaseToRemove.Name.ToString()) -ErrorAction Stop

После этой команды Remove-SqlAvailabilityDatabase переменная $Global:ProdKopieDatabases по-прежнему содержит все базы данных...

Я больше ничего не знаю. Я понимаю сообщение об ошибке, но я не понимаю, почему переменная также изменяется.

Любая помощь высоко ценится!

заранее спасибо


person Dan Stef    schedule 14.10.2015    source источник
comment
Мне удалось сузить проблему до того, как я заполняю переменную $Global:ProdKopieDatabases . Если я заполню его dir $Private:MyAgPrimaryPath\AvailabilityDatabases, Remove-SqlAvailabilityDatabase -InputObject будет работать отлично... Если я заполню его $server.AvailabilityGroups[$Global:ProdKopieAvailabailityGroup].AvailabilityDatabases, он будет вести себя по-другому... Есть идеи? Что я могу проверить? Есть ли что-то вроде byValue вместо byReference?   -  person Dan Stef    schedule 15.10.2015
comment
Теперь я сравнил два результата (один с dir $Privat..., а другой с $server.Avail) и обнаружил, что переменная, которая работает, имеет 7 записей NoteProperty (DisplayName, PSChildName, PSDrive, PSIsContainer, PSParentPath, PSPath и PSProvider)... Откуда они берутся? из??? Почему? Смущенный.... :-(   -  person Dan Stef    schedule 15.10.2015


Ответы (1)


Я нашел решение/обходной путь... (это уродливо)

Сначала я заполняю переменную:

$Global:ProdKopieDatabases = $server.AvailabilityGroups[$Global:ProdKopieAvailabailityGroup].AvailabilityDatabases

Затем перед foreach я создаю новую переменную только с именами в ней:

$c = $Global:ProdKopieDatabases | Select Name

Я позволяю foreach запускать вновь созданную переменную, а для -InputObject я определяю объект каждый раз, когда он снова создается...

foreach($DatabaseToRemove in $c)
    {
        try
        {
            Remove-SqlAvailabilityDatabase -InputObject $server.AvailabilityGroups[$Global:ProdKopieAvailabailityGroup].AvailabilityDatabases[$DatabaseToRemove.Name.ToString()] -ErrorAction Stop

            Start-Sleep -Seconds 2
        }
        catch
        {                
            $Error[0] | Format-List -Force
            Return 1
        }
    }

Дальше по сценарию я работаю только с переменной $c, а не с $Global: больше...

Может быть, когда-нибудь я пойму, почему моя переменная $Global: вела себя так. До сих пор я понятия не имею...

Надеюсь, этот пост когда-нибудь поможет кому-нибудь ;-)

person Dan Stef    schedule 15.10.2015