web-dev-qa-db-fra.com

Comment charger des assemblages dans PowerShell?

Le code PowerShell suivant

#Get a server object which corresponds to the default instance
$srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
... rest of the script ...

Donne le message d'erreur suivant:

New-Object : Cannot find type [Microsoft.SqlServer.Management.SMO.Server]: make sure 
the Assembly containing this type is loaded.
At C:\Users\sortelyn\ ... \tools\sql_express_backup\backup.ps1:6  char:8
+ $srv = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Server
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

Chaque réponse sur Internet indique que je dois charger l'Assemblée - bien sûr, je peux le lire dans le message d'erreur :-) - la question est la suivante:

Comment charger l'assembly et faire en sorte que le script fonctionne?

137
Baxter

LoadWithPartialName est obsolète. La solution recommandée pour PowerShell V3 consiste à utiliser la cmdlet Add-Type par exemple:

Add-Type -Path 'C:\Program Files\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll'

Il existe plusieurs versions différentes et vous pouvez choisir une version particulière. :-)

169
Keith Hill
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
69
Shay Levy

La plupart des gens savent maintenant que System.Reflection.Assembly.LoadWithPartialName est obsolète, mais il s'avère que Add-Type -AssemblyName Microsoft.VisualBasicne se comporte pas beaucoup mieux que LoadWithPartialName :

Plutôt que d'essayer d'analyser votre demande dans le contexte de votre système, [Add-Type] examine une table interne statique pour traduire le "nom partiel" en un "nom complet".

Si votre "nom partiel" n'apparaît pas dans leur tableau, votre script échouera.

Si plusieurs versions de Assembly sont installées sur votre ordinateur, aucun algorithme intelligent ne permet de choisir entre elles. Vous obtiendrez celui qui apparaît dans leur tableau, probablement le plus ancien et obsolète.

Si les versions que vous avez installées sont toutes plus récentes que la version obsolète du tableau, votre script échouera.

Add-Type n'a pas d'analyseur intelligent de "noms partiels" comme .LoadWithPartialNames.

Qu'est-ce que Microsoft dit que vous êtes réellement supposé faire quelque chose comme ceci:

Add-Type -AssemblyName 'Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

Ou, si vous connaissez le chemin, quelque chose comme ceci:

Add-Type -Path 'C:\WINDOWS\Microsoft.Net\Assembly\GAC_MSIL\Microsoft.VisualBasic\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualBasic.dll'

Ce nom long donné à l’Assemblée est appelé nom fort , qui est à la fois unique à la version et à l’Assemblée, et parfois aussi appelé nom complet.

Mais cela laisse quelques questions sans réponse:

  1. Comment déterminer le nom fort de ce qui est réellement chargé sur mon système avec un nom partiel donné?

    [System.Reflection.Assembly]::LoadWithPartialName($TypeName).Location;[System.Reflection.Assembly]::LoadWithPartialName($TypeName).FullName;

Ceux-ci devraient également fonctionner:

Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. Si je veux que mon script utilise toujours une version spécifique d'un fichier .dll mais que je ne puisse pas savoir avec certitude où il est installé, comment puis-je déterminer le nom fort du fichier .dll?

    [System.Reflection.AssemblyName]::GetAssemblyName($Path).FullName;

Ou:

Add-Type $Path -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. Si je connais le nom fort, comment puis-je déterminer le chemin d'accès .dll?

    [Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a').Location;

  2. Et, dans le même ordre d'idées, si je connais le nom du type que j'utilise, comment puis-je savoir de quelle assemblée il s'agit?

    [Reflection.Assembly]::GetAssembly([Type]).Location[Reflection.Assembly]::GetAssembly([Type]).FullName

  3. Comment voir quels assemblages sont disponibles?

Je suggère le module GAC PowerShell . Get-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName fonctionne plutôt bien.

  1. Comment voir la liste utilisée par Add-Type?

C'est un peu plus complexe. Je peux décrire comment y accéder pour n’importe quelle version de PowerShell avec un réflecteur .Net (voir la mise à jour ci-dessous pour PowerShell Core 6.0).

D'abord, déterminez de quelle bibliothèque Add-Type provient:

Get-Command -Name Add-Type | Select-Object -Property DLL

Ouvrez le DLL résultant avec votre réflecteur. J'ai utilisé ILSpy pour cela car c'est FLOSS, mais tout réflecteur C # devrait fonctionner. Ouvrez cette bibliothèque et cherchez dans Microsoft.Powershell.Commands.Utility. Sous Microsoft.Powershell.Commands, il devrait y avoir AddTypeCommand.

Dans la liste de code pour cela, il y a une classe privée, InitializeStrongNameDictionary(). Cela répertorie le dictionnaire qui associe les noms abrégés aux noms forts. Il y a près de 750 entrées dans la bibliothèque que j'ai consultées.

Mise à jour: Maintenant que PowerShell Core 6.0 est open source. Pour cette version, vous pouvez ignorer les étapes ci-dessus et voir le code directement en ligne dans leur référentiel GitHub . Je ne peux cependant pas garantir que ce code correspond à une autre version de PowerShell.

40
Bacon Bits

Si vous souhaitez charger un assembly sans le verrouiller pendant la durée de la session PowerShell, utilisez ceci:

$bytes = [System.IO.File]::ReadAllBytes($storageAssemblyPath)
[System.Reflection.Assembly]::Load($bytes)

$storageAssemblyPath est le chemin de fichier de votre assemblage.

Ceci est particulièrement utile si vous devez nettoyer les ressources de votre session. Par exemple, dans un script de déploiement.

17
Martin Brandl

Voici quelques articles de blog avec de nombreux exemples de méthodes de chargement d'assemblages dans PowerShell v1, v2 et v3.

Les moyens incluent:

  • dynamiquement à partir d'un fichier source
  • dynamiquement d'une assemblée
  • en utilisant d'autres types de code, c'est-à-dire F #

v1.0 Comment charger des assemblages .NET dans une session PowerShell
v2.0 tilisation du code CSharp (C #) dans les scripts PowerShell 2.
v3.0 tilisation d'assemblages .NET Framework dans Windows PowerShell

15
Ralph Willgoss

Vous pouvez charger l’ensemble * .dll Assembly avec

$Assembly = [System.Reflection.Assembly]::LoadFrom("C:\folder\file.dll");
8
Yanaki

Aucune des réponses ne m’a aidé. Je publie donc la solution qui a fonctionné pour moi. Tout ce que j’avais à faire est d’importer le module SQLPS. l'Assemblée a été référencée dans ce module d'une manière ou d'une autre.

Il suffit de courir:

Import-module SQLPS

Remarque: Merci à Jason d'avoir noté que SQLPS est obsolète.

à la place, lancez:

Import-Module SqlServer

ou

Install-Module SqlServer
4
dim_user

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") a travaillé pour moi.

3
Tez Kurmala

Vous pouvez utiliser LoadWithPartialName. Cependant, cela est déconseillé comme ils l'ont dit.

Vous pouvez en effet aller avec Add-Type, et en plus des autres réponses, si vous ne voulez pas spécifier le chemin complet du fichier .dll, vous pouvez simplement faire:

Add-Type -AssemblyName "Microsoft.SqlServer.Management.SMO"

Cela m'a renvoyé une erreur, car SQL Server n'est pas installé (je suppose), mais avec cette même idée, j'ai pu charger l'assemblage de Windows Forms:

Add-Type -AssemblyName "System.Windows.Forms"

Vous pouvez trouver le nom d'assembly précis appartenant à la classe en question sur le site MSDN:

Example of finding out Assembly name belonging to a particular class

2
ThomasMX

Ajoutez les références d'assemblage en haut.

Chargez les assemblys requis SMO et SmoExtended.

[System.Reflection.Assembly] :: LoadWithPartialName ("Microsoft.SqlServer.SMO") | Out-Null [System.Reflection.Assembly] :: LoadWithPartialName ("Microsoft.SqlServer.SmoExtended") | Out-Null

0
Amrita Basu

Assurez-vous que les fonctionnalités ci-dessous sont installées dans l'ordre.

Types 1-Microsoft System CLR pour SQL Server

2-Objets de gestion partagée Microsoft SQL Server

3-Microsoft Windows PowerShell Extensions

Aussi, vous devrez peut-être charger

Add-Type -Path "C:\Programmes\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Smo.dll"

Add-Type -Path "C:\Programmes\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.SqlWmiManagement.dll"

0
shadi eftekhari