Я прочитал несколько похожих вопросов и ответов относительно PS и преобразования типов, но, насколько я понимаю, это разные ситуации.
Я пытаюсь использовать классы RMO в сценарии Powershell, но по какой-то причине он считает необходимым преобразование в тот же тип и не может этого сделать.
Рассматриваемый код в основном:
$conn = New-Object "Microsoft.SqlServer.Management.Common.ServerConnection" @($server, $dbUsernm, $dbPasswd);
$publicationDb = New-Object "Microsoft.SqlServer.Replication.ReplicationDatabase"
$publicationDb.Name = $dbName;
$publicationDb.ConnectionContext = $conn;
(Ошибка аналогичного типа возникает, если я пытаюсь использовать конструктор с двумя аргументами.)
Ошибка:
Exception setting "ConnectionContext": "Cannot convert the "(..snip..)" value of type
"Microsoft.SqlServer.Management.Common.ServerConnection" to type "Microsoft.SqlServer.Management.Common.ServerConnection"."
Так что же здесь происходит? Он явно пытается преобразовать в те же типы данных. Они не определены в сценариях PowerShell, поэтому не должен ли он отслеживать тип? Я также пытался привести переменную к [Microsoft.SqlServer.Management.Common.ServerConnection]
в ее объявлении и/или в наборе вызовов/членов, но безрезультатно.
Если это уместно, я загружаю классы RMO таким образом (это единственный рабочий метод, хотя, насколько я понимаю, LoadWithPartialName
устарел):
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.RMO")
в котором говорится:
GAC Version Location
--- ------- --------
True v4.0.30319 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.SqlServer.RMO\v4.0_14.0.0.0__89845dcd8080cc91\...
Означает ли это, что это версия 4.x этого класса или класс .NET 4.x? Если это класс .NET 4.x, имеет ли это какое-либо отношение к делу, то есть является ли это проблемой для Powershell?
Он явно не загружен. Должен ли я также загружать зависимости вручную?
Я попытался добавить его; Он загружается, но я все еще получаю то же исключение.
Извините, я не могу воспроизвести проблему. Мне пришлось загрузить обе сборки, чтобы код заработал. Я бы попробовал закрыть PowerShell и снова открыть его, а также попытаться явно загрузить .dll
, потому что это может быть несоответствие версии, например. загрузка с частичным именем — это загрузка из GAC, и то, что зарегистрировано в GAC. то есть: загрузить [System.Reflection.Assembly]::LoadFile('C:\Program Files\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Replication.dll')
Подожди - твой находится в Program Files. Вы делаете это в системе, где установлен MS SQL? Идея состоит в том, чтобы иметь возможность делать это удаленно из агента CI, поэтому я надеюсь, что MS SQL не нужно устанавливать локально. FWIW моя версия для ConnectionInfo говорит 2.0.50727..
Да, мне пришлось, это было единственное место, где я мог загрузить правильную комбинацию сборок. Не могли бы вы подтвердить, что можете запустить $conn.connect()
, а затем $conn.InUse
вернётся True
?
Да и с самим подключением все в порядке. И IsOpen, и InUse верны после подключения.
Давайте продолжить обсуждение в чате.
TLDR: сводка по устранению неполадок: @Keilaron ранее выполнил Import-Module SqlServer
в сеансе PowerShell, что вызвало странное поведение.
Лично я не был удовлетворен тем, что простой перезапуск сеанса PowerShell решил проблему, поскольку такого рода ошибки не должно было произойти. Когда я продолжил копать, я думаю, что обнаружил основную причину и обнаружил, что это более серьезная проблема, которую можно легко пропустить.
Во-первых, код для воспроизведения обнаруженного поведения:
Import-Module SqlServer
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.RMO")
$server = 'MyServer'
$dbuser = 'sa'
$dbPasswd = '1234'
$conn = New-Object "Microsoft.SqlServer.Management.Common.ServerConnection" @($server, $dbUser, $dbPasswd);
$publicationDb = New-Object "Microsoft.SqlServer.Replication.ReplicationDatabase"
$publicationDb.Name = 'RandomDatabase'
$publicationDb.ConnectionContext = $conn;
Происходят две ключевые вещи:
Import-Module SqlServer
загружает включенный SqlServer .dll
с участием модуль и нет установленные модули GAC. Это сделано специально, так как модуль не зависит от установленного SQL Server.Microsoft.SqlServer.Rmo.dll
не является частью модуля SqlServer и не загружается вместе с ним, поскольку в модуле SqlServer нет команд репликации. Таким образом, чтобы использовать команды репликации, мы должны сами вручную загрузить это .dll
.Два .dll
, о которых мы заботимся, чтобы Import-Module SqlServer
прозрачно импортировался, были двумя зависимыми от соединения .dll
из расположения модуля SqlServer PowerShell:
[System.Reflection.Assembly]::LoadFile('C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SqlServer\Microsoft.SqlServer.ConnectionInfo.dll')
[System.Reflection.Assembly]::LoadFile('C:\Windows\System32\WindowsPowerShell\v1.0\Modules\SqlServer\Microsoft.SqlServer.SqlClrProvider.dll')
--> Примечание: Эти .dll
были импортированы как 64 бит.dll
.
RMO .dll
, который нам пришлось импортировать вручную, поступает от GAC, но по сути происходит от:
"C:\Program Files (x86)\Microsoft SQL Server\140\SDK\Assemblies\Microsoft.SqlServer.Rmo.dll"
Примечание: Это 32 бит.dll
. Вот почему мы не могли преобразовать "Microsoft.SqlServer.Management.Common.ServerConnection"
в тип "Microsoft.SqlServer.Management.Common.ServerConnection"
. Несмотря на то, что они одного типа по названию, их разная разрядность делает их несовместимыми.
В частности: я не знал, что импорт модуля повлияет на консоль, запускающую его после завершения выполнения скрипта, что это вызовет конфликты версий (или, по крайней мере, я предполагаю, что это происходит), несмотря на явную загрузку других сборок впоследствии, и так далее. Спасибо еще раз за помощь!
Я еще немного покопался, и я считаю, что обнаружил корень проблемы. Смотрите мои правки выше.
Я ценю это, хотя оказывается, что тот факт, что я игнорировал, что у меня не было репликации, является проблемой: он пытается загрузить его только после того, как я вызываю .Script()
для объекта публикации. Так что мне придется найти какой-то способ получить это без установки MS SQL (желательно).
Как вы загружаете
ConnectionInfo
? то есть[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo")