如何在PowerShell中加载程序集?

时间:2012-10-16 20:41:48

标签: powershell powershell-v3.0

以下PowerShell代码

#Get a server object which corresponds to the default instance
$srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
... rest of the script ...

给出以下错误消息:

New-Object : Cannot find type [Microsoft.SqlServer.Management.SMO.Server]: make sure 
the assembly containing this type is loaded.
At C:\Users\sortelyn\ ... \tools\sql_express_backup\backup.ps1:6  char:8
+ $srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

互联网上的每个答案都写道我必须加载程序集 - 确保我可以从错误信息中读取:-) - 问题是:

如何加载程序集并使脚本有效?

11 个答案:

答案 0 :(得分:165)

LoadWithPartialName已被弃用。 PowerShell V3的推荐解决方案是使用Add-Type cmdlet,例如:

Add-Type -Path 'C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll'

有多个不同版本,您可能想要选择特定版本。 : - )

答案 1 :(得分:67)

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")

答案 2 :(得分:35)

大多数人现在都知道System.Reflection.Assembly.LoadWithPartialName已被弃用,但事实证明Add-Type -AssemblyName Microsoft.VisualBasic does not behave much better than LoadWithPartialName

  

而不是尝试在上下文中解析您的请求   你的系统,[Add-Type]查看一个静态的内部表来翻译   “部分名称”改为“全名”。

     

如果您的“部分名称”没有出现在他们的表中,您的脚本将会出现   失败。

     

如果您安装了多个版本的程序集   计算机,它们之间没有智能算法可供选择。   你可能会得到他们桌子上出现的那个   年龄较大,过时的。

     

如果您安装的版本都比过时版本新   在表格中,您的脚本将失败。

     

Add-Type没有“部分名称”的智能解析器   .LoadWithPartialNames

微软说你实际应该做的事情是这样的:

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'

为程序集指定的长名称称为强名称,它对于版本和程序集都是唯一的,有时也称为全名。

但这留下了几个未回答的问题:

  1. 如何使用给定的部分名称确定系统上实际加载内容的强名称?

    [System.Reflection.Assembly]::LoadWithPartialName($TypeName).Location; [System.Reflection.Assembly]::LoadWithPartialName($TypeName).FullName;

  2. 如果我希望我的脚本始终使用.dll的特定版本,但我无法确定它的安装位置,如何确定.dll的强名称是什么?

    [System.Reflection.AssemblyName]::GetAssemblyName($Path).FullName;

  3. 如果我知道强名称,我如何确定.dll路径?

    [Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a').Location;

  4. 同样,如果我知道我正在使用的类型名称,我怎么知道它来自哪个组件?

    [Reflection.Assembly]::GetAssembly([Type]).Location [Reflection.Assembly]::GetAssembly([Type]).FullName

  5. 如何查看可用的程序集?

  6. 我建议GAC PowerShell moduleGet-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName效果非常好。

    1. 如何查看Add-Type使用的列表?
    2. 这有点复杂。我可以描述如何使用.Net反射器访问任何版本的PowerShell(请参阅下面的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是开源的。对于该版本,您可以跳过上述步骤直接查看代码online in their GitHub repository。但是,我无法保证该代码与任何其他版本的PowerShell匹配。

答案 3 :(得分:17)

如果要在PowerShell会话期间加载程序集而不锁定它,请使用:

$bytes = [System.IO.File]::ReadAllBytes($storageAssemblyPath)
[System.Reflection.Assembly]::Load($bytes)

其中$storageAssemblyPath是程序集的文件路径。

如果您需要清理会话中的资源,这将非常有用。例如,在部署脚本中。

答案 4 :(得分:15)

以下是一些博客文章,其中包含许多在PowerShell v1,v2和v3中加载程序集的方法示例。

方法包括:

  • 从源文件动态
  • 动态来自程序集
  • 使用其他代码类型,即F#

v1.0 How To Load .NET Assemblies In A PowerShell Session
v2.0 Using CSharp (C#) code in PowerShell scripts 2.0
v3.0 Using .NET Framework Assemblies in Windows PowerShell

答案 5 :(得分:7)

您可以使用

加载整个* .dll程序集
$Assembly = [System.Reflection.Assembly]::LoadFrom("C:\folder\file.dll");

答案 6 :(得分:4)

没有一个答案对我有帮助,所以我发布了适用于我的解决方案,我所要做的就是导入SQLPS模块,我意外地实现了这一点,我运行了Restore-SqlDatabase命令并开始工作,意味着该模块以某种方式引用了该程序集。

跑步:

Import-module SQLPS

注意:感谢Jason注意到SQLPS已被弃用

改为运行:

Import-Module SqlServer

Install-Module SqlServer

答案 7 :(得分:3)

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")为我工作。

答案 8 :(得分:2)

您可以使用LoadWithPartialName。但是,正如他们所说,这已被弃用。

您确实可以使用Add-Type,除了其他答案之外,如果您不想指定.dll文件的完整路径,您只需执行以下操作:

Add-Type -AssemblyName "Microsoft.SqlServer.Management.SMO"

对我来说这返回了一个错误,因为我没有安装SQL Server(我猜),但是,有了同样的想法,我能够加载Windows窗体程序集:

Add-Type -AssemblyName "System.Windows.Forms"

您可以在MSDN网站上找到属于特定类的精确程序集名称:

Example of finding out assembly name belonging to a particular class

答案 9 :(得分:0)

在顶部添加装配参考。

加载所需的程序集SMO和SmoExtended。

[System.Reflection.Assembly] :: LoadWithPartialName(" Microsoft.SqlServer.SMO")|外空 [System.Reflection.Assembly] :: LoadWithPartialName(" Microsoft.SqlServer.SmoExtended")|出空

答案 10 :(得分:0)

确保按顺序安装以下功能

SQL Server的1-Microsoft System CLR类型

2-Microsoft SQL Server共享管理对象

3-Microsoft Windows PowerShell Extensions

您也可能需要加载

Add-Type -Path“C:\ Program Files \ Microsoft SQL Server \ 110 \ SDK \ Assemblies \ Microsoft.SqlServer.Smo.dll”

Add-Type -Path“C:\ Program Files \ Microsoft SQL Server \ 110 \ SDK \ Assemblies \ Microsoft.SqlServer.SqlWmiManagement.dll”