无法使用 Powershell 在 Windows 10 上将 Bcrypt.Net-Next 程序集安装到 GAC

Unable to install the Bcrypt.Net-Next assembly in to the GAC on Windows 10 using Powershell

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

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 解决方案。

我使用的 Powershell 脚本不正确。

我们必须使用 Load

而不是 LoadWithPartialName
# NOTE: Run powershell as administrator
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publisher = New-Object System.EnterpriseServices.Internal.Publish

# to uninstall a dll
$publisher.GacRemove("C:\temp\Bcrypt.net\BCrypt.Net-Next.StrongName.dll")

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

这会将程序集安装到以下路径:

%windir%\Microsoft.NET\assembly\GAC_MSIL\BCrypt.Net-Next.StrongName\v4.0_3.2.1.0__cb41ca561ed0708f\BCrypt.Net-Next.StrongName.dll

注意:我使用的是 Git 上可用的最新版本,即 3.2.1。因此,未来的版本将产生不同的子文件夹路径,如上所示(即 v4.0_*)。

这里的挑战是我仍然没有在任何脚本组件的引用中看到可用的程序集。如果需要,我将继续研究这个问题和 post 一个新问题。

补充your own answer

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

  • 在语法方面更 PowerShell-idiomatic,
  • 如果无法加载程序集,
  • 报告 (statement-terminating) 错误 (而 [Reflection.Assembly]::LoadWithPartialName() 安静 no-op 以防加载程序集失败)。
# Try to load the latest System.EnterpriseServices.dll assembly
# from the GAC.
Add-Type -AssemblyName System.EnterpriseServices

[Reflection.Assembly]::LoadWithPartialName() 一样,Add-Type -AssemblyName 允许您通过 简单名称 加载 GAC 程序集(也反映在 DLL/executable 文件名中没有扩展名),这既不需要您知道程序集的 版本号 也不需要它的 public 键 (但是, Add-Type -AssemblyName not 是否也首先查看 application 目录,这在 PowerShell 中可能是 PowerShell 可执行文件本身的位置)。

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

但是,late-bound 脚本语言 中,例如 PowerShell,通过简单名称加载可能是可以接受的(Add-Type -AssemblyName过时),并简化加载(您可以指定程序集的明确全名 ,但是 - 请参阅下文)。

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

[Reflection.Assembly]::LoadWithPartialName() 的推荐替代品是 [Reflection.Assembly]::Load(),这是您最终使用的。它要求您知道程序集的全名,其中必须包括程序集的完整版本号 及其 public 键 - 虽然 比 GAC 中实际存在的版本号低 貌似被接受了。

请注意,Add-Type -AssemblyName 也接受 (strong-named) 个完整的程序集名称

# 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 过时,它建立在 .NET Core 之上,不再有 GAC,因此您在迁移时需要不同的方法。

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


相反,我推荐以下方法

  • 编写一个 辅助 PowerShell 模块 来包装感兴趣的程序集 ,命名为 BCrypt.

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

这样的模块很容易编写:

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

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

  • 切换到子目录并在其中创建模块清单 BCrypt.psd1

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

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