¿Cómo agregar correctamente ensamblados .NET a la sesión de Powershell?

24

Tengo un ensamblado .NET (un dll) que es una API para respaldar el software que usamos aquí. Contiene algunas propiedades y métodos que me gustaría aprovechar en mis scripts de Powershell. Sin embargo, me encuentro con muchos problemas al cargar primero el ensamblaje y luego usar cualquiera de los tipos una vez que se carga el ensamblaje.

La ruta completa del archivo es:

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

En Powershell uso:

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

Me sale el error a continuación:

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.

Usar el mismo cmdlet en otro ensamblado .NET, DotNetZip , que tiene ejemplos del uso de la misma funcionalidad en el sitio, tampoco funciona para mí.

Eventualmente encuentro que aparentemente soy capaz de cargar el ensamblaje usando la reflexión:

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

Aunque no entiendo la diferencia entre los métodos Load, LoadFrom o LoadFile, ese último método parece funcionar.

Sin embargo, todavía parece que no puedo crear instancias o usar objetos. Cada vez que lo intento, recibo errores que describen que Powershell no puede encontrar ninguno de los tipos públicos.

Sé que las clases están ahí:

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

---- inicio del extracto ----

   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)

---- fin del extracto ----

Intentar usar métodos estáticos falla, ¡no sé por qué!

[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

Cualquier orientación apreciada!

amandion
fuente

Respuestas:

15

¿Podría rodearlo Add-Typecon un intento de captura e imprimir la propiedad LoaderExceptions, como indica el error? Puede proporcionar una excepción con un mensaje de error más detallado.

try
{
    Add-Type -Path "C:\rnd\CloudBerry.Backup.API.dll"
}
catch
{
    $_.Exception.LoaderExceptions | %
    {
        Write-Error $_.Message
    }
}
jessenich
fuente
99
Esto no funcionó para mí, pero me metió en el estadio. Dentro de la captura, el objeto LoaderExceptions se encuentra aquí: $ _. Exception.LoaderExceptions
Brett
¿No hay una manera de usar la ruta relativa?
Amit
3

Encontré este enlace: http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

Él dice: ".LoadWithPartialName" ha quedado en desuso. Por lo tanto, en lugar de continuar implementando Add-Type con ese método, utiliza una tabla interna estática para traducir el "nombre parcial" a un "nombre completo". En el ejemplo dado en la pregunta, CloudBerry.Backup.API.dllno tiene una entrada en la tabla interna de PowerShell, razón por la cual [System.Reflection.Assembly]::LoadFrom($dllpath)funciona. No está usando la tabla para buscar un nombre parcial.

Slogmeister Extraordinaire
fuente
2

Algunos de los métodos anteriores no funcionaron para mí o no estaban claros.

Esto es lo que uso para envolver llamadas -AddPath y capturar 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)"
}

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

Ralph Willgoss
fuente
0

Usé la siguiente configuración para cargar un control csharp personalizado en powershell. Permite que el control se personalice y se utilice desde powershell.

aquí está el enlace del blog

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

y aquí está el enlace del proyecto de código con la fuente

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

justcode_ca
fuente
3
¡Bienvenido a Server Fault! Realmente preferimos que las respuestas contengan contenido, no punteros al contenido. Si bien esto puede responder teóricamente la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace para referencia.
jscott
0

El LoaderExceptionsestán escondidos en el interior del registro de error. Si el error add-type fue el último en la lista de errores, use $Error[0].InnerException.LoaderExceptionspara mostrar los errores. Lo más probable es que su biblioteca dependa de otra que no se haya cargado. Puede Add-Typecada uno, o simplemente hacer una lista y usar el -ReferencedAssembliesargumento para Add-Type.

Eris
fuente
Pruebe $ Error [0] .Exception.LoaderExceptions y siga los consejos de Eris.
Tahir Hassan
-1

Creo que a estas alturas PODRÍAS haber encontrado una respuesta a este fenómeno. Me encontré con esta publicación después de encontrar el mismo problema ... Pude cargar el ensamblaje y ver los tipos contenidos en el ensamblaje, pero no pude instanciar una instancia de él desde una clase estática. ¿Fue EFTIDY? Tidy, EFTidyNet.TidyNet.Options o qué? Ooooo Weeee ... Problemas ... problemas ... podría ser cualquier cosa. Y mirar a través de los métodos y tipos estáticos de la DLL no reveló nada prometedor. Ahora me estaba deprimiendo. Lo tenía trabajando en un programa C # compilado, pero para mi uso quería que se ejecutara en un lenguaje interpelado ... PowerShell.

Encontré mi solución, y todavía se está probando, pero estoy eufórico y quería compartir esto. Construya una pequeña aplicación console.exe ejerciendo el func que me interesaba y luego véala en algo que la descompilara o mostrara el código IL. ¡Utilicé el reflector de Red-Gate y el complemento del generador de lenguaje powershell y Wallah! ¡mostró cuál era la cadena de constructor adecuada! :-) Intentalo. y espero que funcione para quien enfrenta este problema.

Kim D. Alexander
fuente
2
Y ... ¿cuál era la cadena de constructor adecuada? Esto realmente no responde la pregunta de la forma en que está escrita. Además, ¡bienvenido a ServerFault!
austinian