web-dev-qa-db-fra.com

Comment ajouter correctement des assemblys .NET à une session Powershell?

J'ai un assemblage .NET (une dll) qui est une API pour sauvegarder le logiciel que nous utilisons ici. Il contient certaines propriétés et méthodes dont j'aimerais tirer parti dans mes scripts Powershell. Cependant, je rencontre de nombreux problèmes avec le premier chargement de l'assembly, puis l'utilisation de l'un des types une fois l'assembly chargé.

Le chemin d'accès complet au fichier est:

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

Dans Powershell, j'utilise:

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

J'obtiens l'erreur ci-dessous:

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.

Utiliser la même applet de commande sur un autre assemblage .NET, DotNetZip , qui contient des exemples d'utilisation des mêmes fonctionnalités sur le site ne fonctionne pas non plus pour moi.

Je trouve finalement que je suis apparemment capable de charger l'Assemblée en utilisant la réflexion:

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

Bien que je ne comprenne pas la différence entre les méthodes Load, LoadFrom ou LoadFile, cette dernière méthode semble fonctionner.

Cependant, il me semble toujours impossible de créer des instances ou d'utiliser des objets. Chaque fois que j'essaye, j'obtiens des erreurs qui décrivent que Powershell est incapable de trouver l'un des types publics.

Je sais que les cours sont là:

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

---- début de l'extrait ----

   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 de l'extrait ----

Essayer d'utiliser des méthodes statiques échoue, je ne sais pas pourquoi !!!

[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

Toute orientation appréciée !!

27
amandion

Pourriez-vous entourer le Add-Type avec un try catch et imprimez la propriété LoaderExceptions, comme l'erreur indique de le faire. Il peut fournir une exception avec un message d'erreur plus détaillé.

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

J'ai trouvé ce lien: http://www.madwithpowershell.com/2013/10/add-type-vs-reflectionassembly-in.html

Il dit que ".LoadWithPartialName" est obsolète. Par conséquent, au lieu de continuer à implémenter Add-Type avec cette méthode, il utilise une table interne statique pour traduire le "nom partiel" en "nom complet". Dans l'exemple donné dans la question, CloudBerry.Backup.API.dll N'a pas d'entrée dans la table interne de PowerShell, c'est pourquoi [System.Reflection.Assembly]::LoadFrom($dllpath) fonctionne. Il n'utilise pas la table pour rechercher un nom partiel.

Certaines des méthodes ci-dessus n'ont pas fonctionné pour moi ou n'étaient pas claires.

Voici ce que j'utilise pour encapsuler les appels -AddPath et intercepter les 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)"
}

Référence
https://social.technet.Microsoft.com/Forums/sharepoint/en-US/dff8487f-69af-4b64-ab83-13d58a55c523/addtype-inheritance-loaderexceptions

2
Ralph Willgoss

Les LoaderExceptions sont cachés dans l'enregistrement d'erreur. Si l'erreur de type d'ajout était la dernière de la liste d'erreurs, utilisez $Error[0].InnerException.LoaderExceptions pour afficher les erreurs. Très probablement, votre bibliothèque dépend d'une autre qui n'a pas été chargée. Vous pouvez soit Add-Type chacun, ou faites simplement une liste et utilisez le -ReferencedAssemblies argument à Add-Type.

0
Eris

J'ai utilisé la configuration suivante pour charger un contrôle csharp personnalisé dans PowerShell. Il permet au contrôle d'être personnalisé et utilisé à partir de PowerShell.

voici le lien du blog

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

et voici le lien codeproject avec la source

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

0
justcode_ca