Jak poprawnie dodać zestawy .NET do sesji Powershell?

24

Mam zestaw .NET (dll), który jest interfejsem API do tworzenia kopii zapasowych oprogramowania, którego tutaj używamy. Zawiera niektóre właściwości i metody, z których chciałbym skorzystać w moich skryptach Powershell. Mam jednak wiele problemów z pierwszym załadowaniem zestawu, a następnie użyciem dowolnego z typów po załadowaniu zestawu.

Pełna ścieżka do pliku to:

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

W PowerShell używam:

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

Otrzymuję błąd poniżej:

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.

Używanie tego samego polecenia cmdlet w innym zestawie .NET, DotNetZip , który ma przykłady użycia tej samej funkcjonalności na stronie, również dla mnie nie działa.

W końcu okazało się, że pozornie jestem w stanie załadować zestaw za pomocą odbicia:

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

Chociaż nie rozumiem różnicy między metodami Load, LoadFrom lub LoadFile, ta ostatnia metoda wydaje się działać.

Jednak nadal nie mogę tworzyć instancji ani używać obiektów. Za każdym razem, gdy próbuję, pojawiają się błędy opisujące, że Powershell nie może znaleźć żadnego z typów publicznych.

Wiem, że są tam zajęcia:

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

---- początek fragmentu ----

   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)

---- koniec fragmentu ----

Próba użycia metod statycznych kończy się niepowodzeniem, nie wiem dlaczego !!!

[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

Wszelkie wskazówki są mile widziane !!

amandion
źródło

Odpowiedzi:

15

Czy możesz otoczyć Add-Typepróbę catch i wydrukować właściwość LoaderExceptions, ponieważ błąd ma to zrobić. Może stanowić wyjątek z bardziej szczegółowym komunikatem o błędzie.

try
{
    Add-Type -Path "C:\rnd\CloudBerry.Backup.API.dll"
}
catch
{
    $_.Exception.LoaderExceptions | %
    {
        Write-Error $_.Message
    }
}
jessenich
źródło
9
Nie działało to dla mnie, ale doprowadziło mnie do gry w piłkę. Wewnątrz haczyka znajduje się obiekt LoaderExceptions: $ _. Exception.LoaderExceptions
Brett
czy nie ma sposobu na użycie ścieżki względnej?
Amit,
3

Znalazłem ten link: http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

Mówi: „.LoadWithPartialName” jest przestarzałe. Dlatego zamiast kontynuować wdrażanie metody Add-Type za pomocą tej metody, używa ona statycznej wewnętrznej tabeli do przetłumaczenia „częściowej nazwy” na „pełną nazwę”. W przykładzie podanym w pytaniu CloudBerry.Backup.API.dllnie ma wpisu w wewnętrznej tabeli PowerShell, dlatego [System.Reflection.Assembly]::LoadFrom($dllpath)działa. Nie używa tabeli do wyszukiwania częściowej nazwy.

Slogmeister Extraordinaire
źródło
2

Niektóre z powyższych metod albo nie działały dla mnie, albo były niejasne.

Oto, czego używam do zawijania wywołań -AddPath i przechwytywania wyjątków LoaderException:

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)"
}

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

Ralph Willgoss
źródło
0

Użyłem następującej konfiguracji, aby załadować niestandardową kontrolę csharp w PowerShell. Pozwala na dostosowanie i wykorzystanie kontroli z poziomu PowerShell.

tutaj jest link do bloga

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

a tutaj jest link do kodu projektu ze źródłem

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

justcode_ca
źródło
3
Witaj w Server Fault! Naprawdę wolimy, aby odpowiedzi zawierały treść, a nie wskaźniki do treści. Chociaż teoretycznie może to odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj istotne części odpowiedzi i podać odnośnik.
jscott,
0

LoaderExceptionsSą ukryte wewnątrz rekordu błędu. Jeśli błąd typu dodawania był ostatnim na liście błędów, użyj przycisku, $Error[0].InnerException.LoaderExceptionsaby wyświetlić błędy. Najprawdopodobniej twoja biblioteka jest zależna od innej, która nie została załadowana. Możesz albo Add-Typekażdy z nich, albo po prostu stworzyć listę i użyć -ReferencedAssembliesargumentu do Add-Type.

Eris
źródło
Spróbuj $ Error [0] .Exception.LoaderExceptions i postępuj zgodnie z zaleceniami Eris.
Tahir Hassan
-1

Myślę, że do tej pory MUSISZ znaleźć odpowiedź na to zjawisko. Natknąłem się na ten post po napotkaniu tego samego problemu ... Mogłem załadować zestaw i wyświetlić typy zawarte w zestawie, ale nie byłem w stanie zaimplementować jego wystąpienia z klasy statycznej. Czy to było EFTIDY. Tidy, EFTidyNet.TidyNet.Options czy co? Ooooo Weeee ... Problemy ... problemy ... to może być cokolwiek. A przeglądanie statycznych metod i typów bibliotek DLL nie ujawnił niczego obiecującego. Teraz miałam depresję. Miałem go do pracy w skompilowanym programie C #, ale dla własnego użytku chciałem, aby działał w interpolowanym języku ... PowerShell.

Moje rozwiązanie znalazłem i wciąż jest sprawdzane, ale jestem podekscytowany i chciałem się tym podzielić. Zbuduj małą aplikację console.exe, wykonując func, który mnie interesował, a następnie wyświetl go w coś, co go zdekompiluje lub pokaże kod IL. Użyłem reflektora Red-Gate i dodatku do generatora języka PowerShell oraz Wallah! pokazał, jaki był prawidłowy ciąg konstruktora! :-) Spróbuj. i mam nadzieję, że zadziała dla każdego, kto ma do czynienia z tym problemem.

Kim D. Alexander
źródło
2
I ... jaki był prawidłowy ciąg konstruktora? To tak naprawdę nie odpowiada na pytanie w sposób, w jaki zostało napisane. Witamy także w ServerFault!
austin