如何在PowerShell中加载程序集?

Bax*_*ter 145 powershell powershell-3.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 ...
Run Code Online (Sandbox Code Playgroud)

给出以下错误消息:

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
Run Code Online (Sandbox Code Playgroud)

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

如何加载程序集并使脚本工作?

Kei*_*ill 172

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

Add-Type -Path 'C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll'
Run Code Online (Sandbox Code Playgroud)

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

  • PowerShell不区分大小写(除非您使用-cmatch,-ceq等运算符对其进行区分大小写).所以命令名称和参数的大小并不重要. (5认同)
  • 是.http://msdn.microsoft.com/en-us/library/12xc5368(v=vs.110).aspx请参阅顶部的说明 - "此API现已过时.当然,这并不能阻止人们从使用它. (5认同)
  • 好吧,我使用 PowerShell3 - 这些包含命令看起来非常复杂。我只期望像“包含文件名”这样的东西。 (2认同)
  • 虽然技术上正确的是不推荐使用`LoadWithPartialName`,但原因(如http://blogs.msdn.com/b/suzcook/archive/2003/05/30/57159.aspx中所述)显然不适用进行交互式Powershell会议.我建议你添加一个注释,该API适用于交互式Powershell用法. (2认同)

Sha*_*evy 71

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
Run Code Online (Sandbox Code Playgroud)

  • 这是非常有用的,无需更换即可弃用!我的团队使用了2008和2012客户端工具的混合体.这是使我的PowerShell脚本适用于我的所有团队而不包括笨拙的版本回退逻辑的唯一方法. (7认同)
  • 如果您不希望GAC回显内容,您可以将输出传递给`Out-Null`. (4认同)
  • @Baxter - 您应该接受这个答案或Keith's并让这个问题得到回答. (3认同)
  • 我使用[void] [System.Reflection.Assembly] :: LoadWithPartialName("Microsoft.SqlServer.Smo") (3认同)

Bac*_*its 41

大多数人现在System.Reflection.Assembly.LoadWithPartialName都知道已经弃用了,但事实证明它的Add-Type -AssemblyName Microsoft.VisualBasic 表现并不比LoadWithPartialName以下更好:

而不是尝试在系统上下文中解析您的请求,[Add-Type]查看静态内部表以将"部分名称"转换为"全名".

如果您的"部分名称"没有出现在他们的表中,您的脚本将失败.

如果您的计算机上安装了多个版本的程序集,则无法在它们之间进行选择.你将会得到他们的桌子中出现的任何一个,可能是旧的,过时的.

如果您安装的版本都比表中过时的版本新,那么您的脚本将失败.

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

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

Add-Type -AssemblyName 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Run Code Online (Sandbox Code Playgroud)

或者,如果您知道路径,可以这样:

Add-Type -Path 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.VisualBasic\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualBasic.dll'
Run Code Online (Sandbox Code Playgroud)

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

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

  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. 如何查看可用的组件?

我建议使用GAC PowerShell模块. Get-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName效果很好.

  1. 如何查看Add-Type使用的列表?

这有点复杂.我可以描述如何使用.Net反射器访问任何版本的PowerShell(请参阅下面的PowerShell Core 6.0更新).

首先,找出哪个库Add-Type来自:

Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
Run Code Online (Sandbox Code Playgroud)

用反射器打开生成的DLL.我已经使用了ILSpy,因为它是FLOSS,但任何C#反射器都应该有效.打开那个库,然后查看Microsoft.Powershell.Commands.Utility.在Microsoft.Powershell.Commands,应该有AddTypeCommand.

在代码清单中,有一个私有类,InitializeStrongNameDictionary().这列出了将短名称映射到强名称的字典.在我看过的库中有近750个条目.

更新:现在PowerShell Core 6.0是开源的.对于该版本,您可以跳过上述步骤,并在其GitHub存储库中直接在线查看代码.但是,我不能保证该代码与任何其他版本的PowerShell匹配.


Mar*_*ndl 21

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

$bytes = [System.IO.File]::ReadAllBytes($storageAssemblyPath)
[System.Reflection.Assembly]::Load($bytes)
Run Code Online (Sandbox Code Playgroud)

$storageAssemblyPath程序集的文件路径在哪里.

如果您需要清理会话中的资源,这尤其有用.例如,在部署脚本中.

  • 极好的。因为在 Visual Studio 中,调试 Powershell 时,PS 会话在执行后会挂起(通过 PowerShellToolsProcessHost)。这种方法解决了这个问题。谢谢。 (2认同)

Ral*_*oss 15

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

方法包括:

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

v1.0 如何在PowerShell Session
v2.0中加载.NET 程序集在PowerShell脚本2.0
v3.0中使用CSharp(C#)代码在Windows PowerShell中使用.NET Framework程序集


小智 8

您可以加载整个*.dll程序集

$Assembly = [System.Reflection.Assembly]::LoadFrom("C:\folder\file.dll");
Run Code Online (Sandbox Code Playgroud)