Powershell and .Net Loading
With the recent release of Powershell as a new command-line/scripting tool for system administrators, I see that .Net developers have been using the tool to automate their .Net applications. I noticed some issues arise when some customers try to load assemblies into Powershell.
When loading assemblies into Powershell, you should load the assemblies in the right binding context, use Load or LoadFrom and not LoadFile. The reason for this .Net is a strong typed framework, so loading assemblies with different load methods will treat the same types in each assembly as different types, type mismatch. Here's a good blog on this:
Choosing a Binding Context
https://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
This is the error you would get if you were load using LoadFile and trying to instantiate the .Net object with dependencies using new-object, no TypeLoadException or any obvious exceptions.
New-Object : Exception calling ".ctor" with "0" argument(s): "Could not load file or assembly "..., Version=x.x.x.x, Culture=neutral, PublicKey
Token=null' or one of its dependencies. The system cannot find the file specified."
To resolve this you can use the following with some caveats:
1. [Reflection.Assembly]::LoadFrom
LoadFrom takes a path and will load assemblies in the same context as Load. The advantage is that the assemblies can be located anywhere. You just need to load the main assembly and it will load all dependent assemblies in that same path. This is the best, except when you do serialization you will get an error concerning type-mismatch because LoadFrom is not entirely the same as Load, explained below. So serialization assemblies show be GAC'ed or placed in local app's directory.
Run-time Serialization
https://msdn.microsoft.com/msdnmag/issues/02/04/net/default.aspx
2. [Reflection.Assembly]::Load
You only have to load the main assembly and all dependent assemblies will be loaded when needed. The problem with this is that the DLL's needs to be in the application's local directory, in this case it's Powershell's: C:\WINDOWS\system32\windowspowershell\v1.0. This is actually messy, might use it temporarily since you will need to dump all dependent assemblies into the directory.
3. GAC everything which is not the best thing or use a script to create a new AppDomain and load everything into it and you can also have a config file to set assemblies private path, I have not tried yet but seems possible with Powershell :)
Use fuslogvw.exe tool part of the SDK to troubleshoot binding and probing issues and this article is a good read as well.
How the Runtime Locates Assemblies
https://msdn2.microsoft.com/en-us/library/yx7xezcf(vs.71).aspx
Comments
- Anonymous
May 01, 2010
Great! It worked. I had been using Load which was looking in the powershell.exe directory as you mentioned. Regarding your comment about using an appdomain: I'm pretty sure the classes need to be serializable for that to work - I tried it. Just use LoadFrom and you will be happy :)