首页 > 解决方案 > 无法使用 Powershell 在 Windows 10 上将 Bcrypt.Net-Next 程序集安装到 GAC

问题描述

我需要在 SSIS 包的数据流中实现 BCrypt 散列。我想通过将 Bcrypt 程序集部署到 GAC 然后在脚本组件中调用它来做到这一点。我从 Git 下载了项目,构建了强命名项目(我创建了一个密钥),并使用 Powershell 将程序集部署到 GAC。我使用 Powershell 而不是 gacutil.exe,因为我运行的是没有 gacutil.exe 的 Windows 10。

https://github.com/BcryptNet/bcrypt.net

# NOTE: Run powershell as administrator
[Reflection.Assembly]::LoadWithPartialName("System.EnterpriseServices") | Out-Null         
[System.EnterpriseServices.Internal.Publish] $publish = New-Object System.EnterpriseServices.Internal.Publish

# to install a dll
$publish.GacInstall("C:\temp\Bcrypt.net\BCrypt.Net-Next.dll")

我没有收到任何错误,实际上我没有得到任何输出 - 它只是转到下一行。但程序集未安装在%windir%\Microsoft.NET\assembly

知道为什么这不起作用吗?

注意:我是这样做的,而不是使用 NuGet,因为我将在 SSIS 脚本组件中使用它。显然,NuGet 不适用于 SSIS 解决方案。

标签: windowsgitpowershellssisgac

解决方案


为了补充您自己的答案

我很惊讶这[Reflection.Assembly]::LoadWithPartialName('System.EnterpriseServices')不起作用 - 它对我有用,但这是一个有争议的问题,因为在 PowerShell 中最好使用
Add-Type -AssemblyName
,它:

  • 在语法方面更符合 PowerShell 的习惯,并且
  • 如果无法加载程序集,则报告(语句终止)错误[Reflection.Assembly]::LoadWithPartialName()(而在加载程序集失败的情况下是安静的空操作)。
# Try to load the latest System.EnterpriseServices.dll assembly
# from the GAC.
Add-Type -AssemblyName System.EnterpriseServices

Like [Reflection.Assembly]::LoadWithPartialName(),Add-Type -AssemblyName允许您通过其简单名称加载 GAC 程序集(也反映在不带扩展名的 DLL/可执行文件名中),这既不需要您知道程序集的版本号也不需要知道它的公钥(但是,Add-Type -AssemblyName也不需要先查看应用程序目录,在PowerShell 中可能是 PowerShell 可执行文件本身的位置)。

请注意,它[Reflection.Assembly]::LoadWithPartialName()已被正式声明为obsolete,因为通过简单名称加载程序集可能会在以后破坏现有代码,因为安装了不兼容的版本或具有重复简单名称的程序集。

但是,在诸如 PowerShell 之类的后期绑定脚本语言Add-Type -AssemblyName中,通过简单名称加载可能是可以接受的(不是过时的),并且简化了加载(但是,您可以指定程序集的明确全名- 见下文)。

当然,如果[Reflection.Assembly]::LoadWithPartialName('System.EnterpriseServices')莫名其妙地对你不起作用,Add-Type -AssemblyName System.EnterpriseServices可能同样会失败,但大体上是成立的。

推荐的替换[Reflection.Assembly]::LoadWithPartialName()[Reflection.Assembly]::Load(),这是您最终使用的。它要求您知道程序集的全名,其中必须包括程序集的完整版本号及其公钥- 尽管似乎接受了低于GAC 中实际存在的版本号的版本号。

请注意,它也Add-Type -AssemblyName接受(强命名的)完整程序集名称

# Load from the GAC by *full assembly name*.
# Equivalent of [Reflection.Assembly]::Load()
Add-Type -AssemblyName 'System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

退后一步:

我建议避免在 GAC: 中放置自定义程序集,原因有两个:

  • PowerShell [Core] 6+ 最终将使 Windows PowerShell 过时,它基于不再具有 GAC的 .NET Core构建,因此您在迁移时需要采用不同的方法。

    • 在 PowerShell [Core] 中,Add-Type -AssemblyName在 PowerShell 本身附带的程序集中查找由简单名称给出的程序集,尽管它首先在当前目录中查找。
  • 您正在使用的 System.EnterpriseServices.Internal.Publish类型没有官方支持直接使用:“Publish由 .NET Framework 在内部使用。您不需要直接在代码中使用它。”,以及唯一官方支持的在GAC 是通过Windows 安装程序gacutil.exe仅在开发期间使用)。


相反,我推荐以下方法

  • 编写一个辅助 PowerShell 模块,该模块包装感兴趣的程序集,例如BCrypt.

  • 将该模块放在 中列出的目录之一中$env:PSModulePath,以便执行的任何脚本Import-Module BCrypt都将感兴趣的程序集隐式加载到会话中。

这样的模块很容易编写:

  • 选择一个合适的目录并在$env:PSModulePath其中创建一个名为的子目录BCrypt

  • 将您的程序集 DLL ( BCrypt.Net-Next.dll) 复制到该子目录中。

  • 切换到子目录并在BCrypt.psd1那里创建一个模块清单:

      New-ModuleManifest BCrypt.psd1 -RequiredAssemblies BCrypt.Net-Next.dll -ModuleVersion 1.0
    

根据需要提供额外New-ModuleManifest的参数和/或根据需要在事后编辑模块清单。


推荐阅读