web-dev-qa-db-de.com

Wie lade ich Assemblys in PowerShell?

Der folgende PowerShell-Code

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

Gibt folgende Fehlermeldung aus:

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

Jede Antwort im Internet schreibt, dass ich die Assembly laden muss - na sicher kann ich das aus der Fehlermeldung ablesen :-) - die Frage ist:

Wie lade ich die Assembly und bringe das Skript zum Laufen?

137
Baxter

LoadWithPartialName ist veraltet. Die empfohlene Lösung für PowerShell V3 ist die Verwendung von Add-Type Cmdlet, z.

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

Es gibt mehrere verschiedene Versionen, und Sie möchten möglicherweise eine bestimmte Version auswählen. :-)

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

Die meisten Leute wissen inzwischen, dass System.Reflection.Assembly.LoadWithPartialName Veraltet ist, aber es stellt sich heraus, dass Add-Type -AssemblyName Microsoft.VisualBasicverhält sich nicht viel besser als LoadWithPartialName :

Anstatt zu versuchen, Ihre Anfrage im Kontext Ihres Systems zu analysieren, durchsucht [Add-Type] eine statische interne Tabelle, um den "Teilnamen" in einen "vollständigen Namen" zu übersetzen.

Wenn Ihr "Teilname" nicht in der Tabelle erscheint, schlägt Ihr Skript fehl.

Wenn auf Ihrem Computer mehrere Versionen der Assembly installiert sind, können Sie keinen intelligenten Algorithmus auswählen. Sie bekommen, was auch immer in ihrer Tabelle steht, wahrscheinlich die ältere, veraltete.

Wenn die von Ihnen installierten Versionen alle neuer als die veraltete Version in der Tabelle sind, schlägt Ihr Skript fehl.

Add-Type hat keinen intelligenten Parser für "Teilnamen" wie .LoadWithPartialNames.

Was Microsoft sagt, dass Sie eigentlich tun sollen, ist ungefähr so:

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

Oder, wenn Sie den Pfad kennen, ungefähr so:

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

Dieser lange Name für die Assembly wird als starker Name bezeichnet, der sowohl für die Version als auch für die Assembly eindeutig ist vollständiger Name.

Aber dies lässt ein paar Fragen offen:

  1. Wie bestimme ich den starken Namen dessen, was tatsächlich auf meinem System geladen wird, mit einem bestimmten Teilnamen?

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

Diese sollten auch funktionieren:

Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. Wenn mein Skript immer eine bestimmte Version einer DLL verwenden soll, ich jedoch nicht sicher bin, wo es installiert ist, wie ermittle ich den starken Namen aus der DLL?

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

Oder:

Add-Type $Path -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. Wie bestimme ich den DLL-Pfad, wenn ich den starken Namen kenne?

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

  2. Und auf ähnliche Weise: Wenn ich den Typnamen meiner verwendeten Assembly kenne, woher weiß ich dann, von welcher Assembly sie stammt?

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

  3. Wie sehe ich, welche Baugruppen verfügbar sind?

Ich schlage das GAC PowerShell-Modul vor. Get-GacAssembly -Name 'Microsoft.SqlServer.Smo*' | Select Name, Version, FullName Funktioniert ziemlich gut.

  1. Wie kann ich die Liste sehen, die Add-Type Verwendet?

Das ist etwas komplexer. Ich kann beschreiben, wie für jede Version von PowerShell mit einem .NET-Reflektor darauf zugegriffen wird (siehe das Update unten für PowerShell Core 6.0).

Stellen Sie zunächst fest, aus welcher Bibliothek Add-Type Stammt:

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

Öffnen Sie die resultierende DLL mit Ihrem Reflektor. Ich habe ILSpy dafür verwendet, weil es FLOSS ist, aber jeder C # -Reflektor sollte funktionieren. Öffnen Sie diese Bibliothek und schauen Sie in Microsoft.Powershell.Commands.Utility. Unter Microsoft.Powershell.Commands Sollte AddTypeCommand stehen.

In der Codeauflistung dafür gibt es eine private Klasse, InitializeStrongNameDictionary(). Das listet das Wörterbuch auf, das die Kurznamen den starken Namen zuordnet. Es gibt fast 750 Einträge in der Bibliothek, die ich mir angesehen habe.

Update: Jetzt, da PowerShell Core 6.0 Open Source ist. Für diese Version können Sie die obigen Schritte überspringen und den Code direkt anzeigen online in ihrem GitHub-Repository . Ich kann jedoch nicht garantieren, dass dieser Code mit einer anderen Version von PowerShell übereinstimmt.

40
Bacon Bits

Wenn Sie eine Assembly laden möchten ohne sie während der PowerShell-Sitzung zu sperren, verwenden Sie Folgendes:

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

Wo $storageAssemblyPath ist der Dateipfad Ihrer Versammlung.

Dies ist besonders nützlich, wenn Sie die Ressourcen in Ihrer Sitzung bereinigen müssen. Zum Beispiel in einem Implementierungsskript.

17
Martin Brandl

Hier sind einige Blogposts mit zahlreichen Beispielen für das Laden von Assemblys in PowerShell v1, v2 und v3.

Die Möglichkeiten umfassen:

  • dynamisch aus einer Quelldatei
  • dynamisch aus einer Assembly
  • verwenden anderer Codetypen, d. h. F #

v1.0 Laden von .NET-Assemblys in einer PowerShell-Sitzung
v2.0 Verwenden von CSharp-Code (C #) in PowerShell-Skripten 2.
v3.0 Verwenden von .NET Framework-Assemblys in Windows PowerShell

15
Ralph Willgoss

Sie können die gesamte * .dll-Assembly mit laden

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

Keine der Antworten hat mir geholfen. Ich poste die Lösung, die für mich funktioniert hat. Ich musste nur das SQLPS-Modul importieren. Dies wurde mir bewusst, als ich versehentlich den Befehl Restore-SqlDatabase ausführte und mit der Arbeit begann Auf die Assembly wurde in diesem Modul irgendwie verwiesen.

Renn einfach:

Import-module SQLPS

Hinweis: Vielen Dank, Jason, für die Feststellung, dass SQLPS veraltet ist

stattdessen laufen:

Import-Module SqlServer

oder

Install-Module SqlServer
4
dim_user

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") hat für mich gearbeitet.

3
Tez Kurmala

Sie könnten LoadWithPartialName verwenden. Das ist jedoch veraltet, wie sie sagten.

Sie können in der Tat Add-Type Befolgen und zusätzlich zu den anderen Antworten, wenn Sie nicht den vollständigen Pfad der DLL-Datei angeben möchten, können Sie einfach Folgendes tun:

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

Für mich gab dies einen Fehler zurück, da ich SQL Server nicht installiert habe (ich vermute), aber mit der gleichen Idee konnte ich die Windows Forms Assembly laden:

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

Den genauen Assemblynamen für die jeweilige Klasse finden Sie auf der MSDN-Site:

Example of finding out Assembly name belonging to a particular class

2
ThomasMX

Fügen Sie die Assembly-Referenzen oben hinzu.

Laden Sie die erforderlichen Assemblys SMO und SmoExtended.

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

0
Amrita Basu

Stellen Sie sicher, dass die folgenden Funktionen in der richtigen Reihenfolge installiert sind

1-Microsoft System CLR-Typen für SQL Server

2-Gemeinsam genutzte Microsoft SQL Server-Verwaltungsobjekte

3-Microsoft Windows PowerShell-Erweiterungen

Möglicherweise müssen Sie auch laden

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

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

0
shadi eftekhari