I need to implement BCrypt hashing in an SSIS package's data flow. I would like to do this by deploying the Bcrypt assembly to the GAC and then calling it in a script component. I downloaded the project from Git, built the strong named project (I created a key), and deployed the assembly to the GAC using Powershell. I used Powershell instead of gacutil.exe because I am running Windows 10, which does not have 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")
I do not get any error, in fact I do not get any output - it just goes to the next line. But the assembly is not installed in %windir%\Microsoft.NET\assembly
Any idea why this is not working?
Note: I am doing it this way as opposed to using NuGet because I am going to be using this in an SSIS script component. Apparently, NuGet does not work with SSIS solutions.
To complement your own answer:
I'm surprised that [Reflection.Assembly]::LoadWithPartialName('System.EnterpriseServices')
didn't work - it does for me, but it's a moot point, because in PowerShell it's preferable to useAdd-Type -AssemblyName
, which:
[Reflection.Assembly]::LoadWithPartialName()
is a quiet no-op in case of failure to load the assembly).# Try to load the latest System.EnterpriseServices.dll assembly
# from the GAC.
Add-Type -AssemblyName System.EnterpriseServices
Like [Reflection.Assembly]::LoadWithPartialName()
, Add-Type -AssemblyName
allows you to load GAC assemblies by their simple name (as also reflected in the DLL/executable file name without extension), which neither requires you to know the assembly's version number nor its public key (however, Add-Type -AssemblyName
does not also first look in the application directory, which in PowerShell would presumably be the location of the PowerShell executable itself).
Note that [Reflection.Assembly]::LoadWithPartialName()
is officially declared obsolete, because loading assemblies by simple name can break existing code later, due to installation of incompatible versions or assemblies with duplicate simple names.
However, in a late-bound scripting language such as PowerShell, loading by simple name may be acceptable (Add-Type -AssemblyName
is not obsolete), and simplifies loading (you can specify an assembly's unambiguous full name, however - see below).
Of course, if [Reflection.Assembly]::LoadWithPartialName('System.EnterpriseServices')
inexplicably didn't work for you, Add-Type -AssemblyName System.EnterpriseServices
may similarly fail, but the general point stands.
The recommended replacement for [Reflection.Assembly]::LoadWithPartialName()
is [Reflection.Assembly]::Load()
, which is what you ended up using. It requires you to know the assembly's full name, which must include the assembly's full version number and its public key - although a lower version number than the one actually present in the GAC is seemingly accepted.
Note that Add-Type -AssemblyName
accepts (strong-named) full assembly names too:
# 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'
Taking a step back:
I suggest avoiding putting a custom assembly in the GAC:, for two reasons:
PowerShell [Core] 6+, which will eventually make Windows PowerShell obsolete, is built on .NET Core, which doesn't have a GAC anymore, so you'll need a different approach when you migrate.
Add-Type -AssemblyName
looks for assemblies given by simple name among the assemblies that ship with PowerShell itself, though it looks in the current directory first.The System.EnterpriseServices.Internal.Publish
type you're using isn't officially supported for direct use: "Publish
is used internally by the .NET Framework. You do not need to use it directly in your code.", and the only officially supported way to install assemblies in the GAC is via Windows Installer (gacutil.exe
is only meant to be used during development).
Instead, I recommend the following approach:
Author an auxiliary PowerShell module that wraps the assembly of interest, named, say, BCrypt
.
Place that module in one of the directories listed in $env:PSModulePath
, so that any script executing Import-Module BCrypt
implicitly loads the assembly of interest into the session.
Such a module is easy to author:
Choose a suitable directory listed in $env:PSModulePath
and create a subdirectory named, say, BCrypt
in it.
Copy your assembly DLL (BCrypt.Net-Next.dll
) into that subdirectory.
Change to the subdirectory and create a module manifest BCrypt.psd1
there:
New-ModuleManifest BCrypt.psd1 -RequiredAssemblies BCrypt.Net-Next.dll -ModuleVersion 1.0
Provide additional New-ModuleManifest
arguments as needed and/or edit the module manifest after the fact, as needed.
The Powershell script I was using is incorrect.
Instead of using LoadWithPartialName
, we must use Load
# 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")
This will install the assembly into the following path:
%windir%\Microsoft.NET\assembly\GAC_MSIL\BCrypt.Net-Next.StrongName\v4.0_3.2.1.0__cb41ca561ed0708f\BCrypt.Net-Next.StrongName.dll
Note: I am using the most recent version available on Git, which is 3.2.1. So, future releases will result in a different sub-folder path as seen above (i.e., v4.0_*).
The challenge here is that I still do not see the assembly available in any of the script component's references. I will continue to research this and post a new question if needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With