【问题标题】:Unable to install the Bcrypt.Net-Next assembly in to the GAC on Windows 10 using Powershell无法使用 Powershell 在 Windows 10 上将 Bcrypt.Net-Next 程序集安装到 GAC
【发布时间】:2020-06-19 12:15:14
【问题描述】:

我需要在 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 解决方案。

【问题讨论】:

  • 我对这个过程很笨,所以请耐心等待。您确定它应该出现在程序集目录中吗?命令成功后(大概),ISE 是否看到命名空间? [System.Bcrypt.whatever]?
  • 是的,它应该显示在 Assembly 目录中。它是一个文件,需要存储在某个地方。您可以尝试构建它并将其部署到 GAC 吗?
  • 在工作中,我无法在此处使用 DL 随机库来实现它们。我回家后试试看。
  • 它是开源的。 DLL 不在其中。你必须建造它。注意:我使用了强符号
  • 因此,从 GitHub 下载代码并将其构建到 DLL 中与从 Internet 侧加载 DLL 的工作问题相同——至少就工作而言。对不起,伙计。

标签: windows git powershell ssis gac


【解决方案1】:

补充your own answer

我很惊讶[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

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

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

但是,后期绑定的脚本语言(例如 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 过时,它基于 .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的脚本都会将感兴趣的程序集隐式加载到会话中。

这样的模块很容易编写:

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

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

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

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

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

【讨论】:

  • 如何仅为程序集(而不是应用程序)创建 Windows 安装程序?此时,我需要该程序集在全局级别可用,以便任何项目/解决方案都可以引用它。因此,在一个项目中,当我右键单击引用时,我将能够添加我刚刚构建的任何程序集。
  • 后续问题链接:stackoverflow.com/q/65982471/45375
【解决方案2】:

我使用的 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_*)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2023-04-04
    相关资源
    最近更新 更多