Como adicionar adequadamente assemblies .NET à sessão do PowerShell?


24

Eu tenho um assembly .NET (uma dll) que é uma API para fazer backup do software que usamos aqui. Ele contém algumas propriedades e métodos dos quais gostaria de aproveitar meus scripts do Powershell. No entanto, estou enfrentando muitos problemas ao carregar primeiro o assembly e depois usar qualquer um dos tipos depois que o assembly é carregado.

O caminho completo do arquivo é:

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

No Powershell eu uso:

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

Eu recebo o erro abaixo:

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 o mesmo cmdlet em outro assembly .NET, DotNetZip , que tem exemplos de uso da mesma funcionalidade no site, também não funciona para mim.

Eventualmente, acho que sou capaz de carregar o assembly usando a reflexão:

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

Embora eu não entenda a diferença entre os métodos Load, LoadFrom ou LoadFile, esse último método parece funcionar.

No entanto, ainda pareço incapaz de criar instâncias ou usar objetos. Cada vez que tento, recebo erros que descrevem que o Powershell não consegue encontrar nenhum dos tipos públicos.

Eu sei que as aulas estão lá:

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

---- início do trecho ----

   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)

---- fim do trecho ----

Tentando usar métodos estáticos falham, não sei por que !!!

[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

Qualquer orientação apreciada !!

Respostas:


15

Você pode cercar o Add-Typecom uma tentativa de capturar e imprimir a propriedade LoaderExceptions, como o erro indica. Pode fornecer uma exceção com uma mensagem de erro mais detalhada.

try
{
    Add-Type -Path "C:\rnd\CloudBerry.Backup.API.dll"
}
catch
{
    $_.Exception.LoaderExceptions | %
    {
        Write-Error $_.Message
    }
}

9
Isso não funcionou para mim, mas me colocou no campo. Dentro da captura, o objeto LoaderExceptions está localizado aqui: $ _. Exception.LoaderExceptions
Brett

não existe uma maneira de usar o caminho relativo?
Amit

3

Encontrei este link: http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

Ele diz que ".LoadWithPartialName" foi preterido. Portanto, em vez de continuar implementando o Add-Type com esse método, ele usa uma tabela interna estática para converter o "nome parcial" em um "nome completo". No exemplo dado na pergunta, CloudBerry.Backup.API.dllnão há uma entrada na tabela interna do PowerShell, e é por isso que [System.Reflection.Assembly]::LoadFrom($dllpath)funciona. Não está usando a tabela para procurar um nome parcial.


2

Alguns dos métodos acima não funcionaram para mim ou não eram claros.

Aqui está o que eu uso para agrupar chamadas -AddPath e 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)"
}

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


0

Usei a seguinte configuração para carregar um controle csharp personalizado no PowerShell. Ele permite que o controle seja personalizado e utilizado de dentro do PowerShell.

aqui está o link do blog

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

e aqui está o link do codeproject com a fonte

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


3
Bem-vindo à falha do servidor! Nós realmente preferimos que as respostas contenham conteúdo e não ponteiros para o conteúdo. Embora isso possa teoricamente responder à pergunta, seria preferível incluir aqui as partes essenciais da resposta e fornecer o link para referência.
jscott

0

Eles LoaderExceptionsestão ocultos dentro do registro de erro. Se o erro do tipo adição foi o último na lista de erros, use $Error[0].InnerException.LoaderExceptionspara mostrar os erros. Provavelmente, sua biblioteca depende de outra que não foi carregada. Você pode Add-Typecada um ou apenas fazer uma lista e usar o -ReferencedAssembliesargumento para Add-Type.


Experimente $ Error [0] .Exception.LoaderExceptions e siga as recomendações de Eris.
Tahir Hassan

-1

Eu acho que agora você DEVE ter encontrado uma resposta para esse fenômeno. Fiz essa postagem depois de encontrar o mesmo problema ... Pude carregar o assembly e visualizar os tipos contidos no assembly, mas não consegui instanciar uma instância dele a partir de uma classe estática. Foi EFTIDY. Arrumado, EFTidyNet.TidyNet.Options ou o quê? Ooooo Weeee ... problemas ... problemas ... pode ser qualquer coisa. E analisar os métodos e tipos estáticos da DLL não revelou nada de promissor. Agora eu estava ficando deprimido. Eu o tinha trabalhando em um programa C # compilado, mas, para meu uso, eu queria que ele fosse executado em um idioma interpetado ... PowerShell.

Encontrei minha solução e ainda está sendo comprovada, mas estou feliz e queria compartilhar isso. Crie um pequeno aplicativo console.exe que exerça a função em que eu estava interessado e, em seguida, visualize-o em algo que o descompile ou mostre o código IL. Usei o refletor da Red-Gate e o complemento gerador de linguagem PowerShell e Wallah! mostrou qual era a string de construtor apropriada! :-) Tente. e espero que funcione para quem enfrenta esse problema.


2
E ... qual foi a sequência correta do construtor? Isso realmente não responde à pergunta da maneira como está escrita. Além disso, bem-vindo ao ServerFault!
de Austin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.