我需要在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:tempBcrypt.netBCrypt.Net-Next.dll")
我没有收到任何错误,事实上我没有得到任何输出——它只是转到下一行。但是程序集未安装在%windir%\Microsoft.NET\assembly中
知道为什么不起作用吗?
注意:我是这样做的,而不是使用NuGet,因为我将在SSIS脚本组件中使用它。显然,NuGet不适用于SSIS解决方案。
补充您自己的答案:
我很惊讶[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,它是在.NETCore上构建的,不再有GAC,因此在迁移时需要不同的方法。
- 在PowerShell[Core]中,
Add-Type -AssemblyName
在PowerShell本身附带的程序集中查找由简单名称给定的程序集,尽管它首先在当前目录中查找
- 在PowerShell[Core]中,
您正在使用的
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
参数和/或根据需要在事后编辑模块清单。
我使用的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:tempBcrypt.netBCrypt.Net-Next.StrongName.dll")
# to install a dll
$publisher.GacInstall("C:tempBcrypt.netBCrypt.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_*)
这里的挑战是,我仍然没有在脚本组件的任何引用中看到可用的程序集。我会继续研究这个问题,如果需要的话,我会提出一个新的问题。