Большинство людей к настоящему моменту знают, что System.Reflection.Assembly.LoadWithPartialName
это устарело, но оказывается, что Add-Type -AssemblyName Microsoft.VisualBasic
не ведет себя намного лучше, чемLoadWithPartialName
:
Вместо того, чтобы пытаться анализировать ваш запрос в контексте вашей системы, [Add-Type] просматривает статическую внутреннюю таблицу, чтобы перевести «частичное имя» в «полное имя».
Если ваше «частичное имя» не отображается в их таблице, ваш сценарий потерпит неудачу.
Если на вашем компьютере установлено несколько версий сборки, интеллектуального алгоритма для выбора между ними не существует. Вы получите то, что появится в их таблице, вероятно, старое, устаревшее.
Если все версии, которые вы установили, являются более новыми, чем устаревшая в таблице, ваш скрипт завершится ошибкой.
Add-Type не имеет интеллектуального синтаксического анализатора типа «частичных имен»
.LoadWithPartialNames
.
Microsoft говорит, что на самом деле вы должны делать что-то вроде этого:
Add-Type -AssemblyName 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Или, если вы знаете путь, что-то вроде этого:
Add-Type -Path 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.VisualBasic\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualBasic.dll'
Это длинное имя, данное для сборки, называется строгим именем , которое уникально как для версии, так и для сборки, а также иногда называется полным именем.
Но это оставляет пару вопросов без ответа:
Как определить строгое имя того, что на самом деле загружается в моей системе с данным частичным именем?
[System.Reflection.Assembly]::LoadWithPartialName($TypeName).Location;
[System.Reflection.Assembly]::LoadWithPartialName($TypeName).FullName;
Они также должны работать:
Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
Если я хочу, чтобы в моем сценарии всегда использовалась определенная версия .dll, но я не могу быть уверен в том, где он установлен, как определить, какое строгое имя используется в .dll?
[System.Reflection.AssemblyName]::GetAssemblyName($Path).FullName;
Или:
Add-Type $Path -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
Если я знаю строгое имя, как мне определить путь к .dll?
[Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a').Location;
И в том же духе, если я знаю имя типа того, что я использую, как я узнаю, из какой сборки это происходит?
[Reflection.Assembly]::GetAssembly([Type]).Location
[Reflection.Assembly]::GetAssembly([Type]).FullName
Как посмотреть какие сборки доступны?
Я предлагаю модуль GAC PowerShell . Get-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName
работает довольно хорошо
- Как я могу увидеть список, который
Add-Type
использует?
Это немного сложнее. Я могу описать, как получить к нему доступ для любой версии PowerShell с помощью отражателя .Net (см. Обновление ниже для PowerShell Core 6.0).
Сначала выясните, из какой библиотеки Add-Type
происходит:
Get-Command -Name Add-Type | Select-Object -Property DLL
Откройте полученную DLL вашим отражателем. Я использовал ILSpy для этого, потому что это FLOSS, но любой отражатель C # должен работать. Откройте эту библиотеку и посмотрите Microsoft.Powershell.Commands.Utility
. Под Microsoft.Powershell.Commands
, там должно быть AddTypeCommand
.
В листинге кода для этого есть закрытый класс InitializeStrongNameDictionary()
. Это перечисляет словарь, который отображает короткие имена в строгие имена. В библиотеке я посмотрел почти 750 записей.
Обновление: теперь, когда PowerShell Core 6.0 с открытым исходным кодом. Для этой версии вы можете пропустить описанные выше шаги и увидеть код прямо онлайн в их репозитории GitHub . Однако я не могу гарантировать, что этот код соответствует любой другой версии PowerShell.