30

I have a .NET assembly (a dll) which is an API to backup software we use here. It contains some properties and methods I would like to take advantage of in my Powershell script(s). However, I am running into a lot of issues with first loading the assembly, then using any of the types once the assembly is loaded.

The complete file path is:

C:\rnd\CloudBerry.Backup.API.dll

In Powershell I use:

$dllpath = "C:\rnd\CloudBerry.Backup.API.dll"
Add-Type -Path $dllpath

I get the error below:

Add-Type : Unable to load one or more of the requested types. Retrieve the
LoaderExceptions property for more information.
At line:1 char:9
+ Add-Type <<<<  -Path $dllpath
+ CategoryInfo          : NotSpecified: (:) [Add-Type], ReflectionTypeLoadException
+ FullyQualifiedErrorId : System.Reflection.ReflectionTypeLoadException,Microsoft.PowerShell.Commands.AddTypeComma
ndAdd-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

Using the same cmdlet on another .NET assembly, DotNetZip, which has examples of using the same functionality on the site also does not work for me.

I eventually find that I am seemingly able to load the assembly using reflection:

[System.Reflection.Assembly]::LoadFrom($dllpath)

Although I don't understand the difference between the methods Load, LoadFrom, or LoadFile that last method seems to work.

However, I still seem to be unable to create instances or use objects. Each time I try, I get errors that describe that Powershell is unable to find any of the public types.

I know the classes are there:

$asm = [System.Reflection.Assembly]::LoadFrom($dllpath)
$cbbtypes = $asm.GetExportedTypes()
$cbbtypes | Get-Member -Static

---- start of excerpt ----

   TypeName: CloudBerryLab.Backup.API.BackupProvider

Name                MemberType Definition
----                ---------- ----------
PlanChanged         Event          System.EventHandler`1[CloudBerryLab.Backup.API.Utils.ChangedEventArgs] PlanChanged(Sy...
PlanRemoved         Event          System.EventHandler`1[CloudBerryLab.Backup.API.Utils.PlanRemoveEventArgs] PlanRemoved...
CalculateFolderSize Method     static long CalculateFolderSize()
Equals              Method     static bool Equals(System.Object objA, System.Object objB)
GetAccounts         Method     static CloudBerryLab.Backup.API.Account[],     CloudBerry.Backup.API, Version=1.0.0.1, Cu...
GetBackupPlans      Method     static CloudBerryLab.Backup.API.BackupPlan[], CloudBerry.Backup.API, Version=1.0.0.1,...
ReferenceEquals     Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
SetProfilePath      Method     static System.Void SetProfilePath(string profilePath)

----end of excerpt----

Trying to use static methods fail, I don't know why!!!

[CloudBerryLab.Backup.API.BackupProvider]::GetAccounts()
Unable to find type [CloudBerryLab.Backup.API.BackupProvider]: make sure that the     assembly containing this type is load
ed.
At line:1 char:42
+ [CloudBerryLab.Backup.API.BackupProvider] <<<< ::GetAccounts()
    + CategoryInfo          : InvalidOperation:     (CloudBerryLab.Backup.API.BackupProvider:String) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

Any guidance appreciated!!

amandion
  • 323
  • 2
  • 4
  • 7

6 Answers6

19

Could you surround the Add-Type with a try catch and print the LoaderExceptions property, as the error is stating to do. It may provide an exception with a more detailed error message.

try
{
    Add-Type -Path "C:\rnd\CloudBerry.Backup.API.dll"
}
catch
{
    $_.Exception.LoaderExceptions | %
    {
        Write-Error $_.Message
    }
}
vulcan raven
  • 215
  • 1
  • 2
  • 10
jessenich
  • 301
  • 2
  • 5
4

Some of the methods above either did not work for me or were unclear.

Here's what I use to wrap -AddPath calls and catch LoaderExceptions:

try
{
   Add-Type -Path "C:\path\to.dll"
}
catch [System.Reflection.ReflectionTypeLoadException]
{
   Write-Host "Message: $($_.Exception.Message)"
   Write-Host "StackTrace: $($_.Exception.StackTrace)"
   Write-Host "LoaderExceptions: $($_.Exception.LoaderExceptions)"
}

Reference
https://social.technet.microsoft.com/Forums/sharepoint/en-US/dff8487f-69af-4b64-ab83-13d58a55c523/addtype-inheritance-loaderexceptions

Ralph Willgoss
  • 215
  • 2
  • 5
3

I found this link: http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

He says, ".LoadWithPartialName" has been deprecated. Therefore, instead of continuing to implement Add-Type with that method, it uses a static, internal table to translate the "partial name" to a "full name". In the example given in the question, CloudBerry.Backup.API.dll does not have an entry in PowerShell's internal table, which is why [System.Reflection.Assembly]::LoadFrom($dllpath) works. It is not using the table to look up a partial name.

1

The LoaderExceptions are hidden inside the error record. If the add-type error was the last one in the error list, use $Error[0].InnerException.LoaderExceptions to show the errors. Most likely, your library is dependent on another that has not been loaded. You can either Add-Type each one, or just make a list and use the -ReferencedAssemblies argument to Add-Type.

Eris
  • 111
  • 3
0

I used the following setup to load a custom csharp control in powershell. It allows the control to be customized and utilized from within powershell.

here is the blog link

http://justcode.ca/wp/?p=435

and here is the codeproject link with source

http://www.codeproject.com/Articles/311705/Custom-CSharp-Control-for-Powershell

  • 3
    Welcome to Server Fault! We really do prefer that answers contain content not pointers to content. Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – jscott Mar 10 '13 at 03:20
-2

I guess by now you MIGHT have found an answer to this phenomena. I ran upon this post after encountering the same problem...I could load the assembly, and view the types contained in the assembly, but was unable to instanciate a instance of it from a static class. Was it EFTIDY. Tidy, EFTidyNet.TidyNet.Options or what? Ooooo Weeee...Problems...problems...it could be anything. And looking through the static methods and types of the DLL didn't reveal anything promising. Now I was getting depressed. I had it working in a compiled C# program, but for my use I wanted to have it running in a interpeted language...powershell.

My solution I found, and it's still being proven, but I'm elated and wanted to share this. Build a small console.exe app exercising the func that I was interested in and then view it in something that would decompile it or show the IL code. I used Red-Gate's reflector and the powershell language generator add-in and Wallah! it showed what the proper constructor string was! :-) Try it. and I hope it works for whomever is faced with this problem.

  • 2
    And... what was the proper constructor string? This doesn't really answer the question the way it's written. Also, welcome to ServerFault! – austinian Aug 05 '15 at 03:48