2013-03-04 10 views
9

Ich versuche, PowerShell zu verwenden, um den Prozess der Erstellung einer n-Tier-Lösung basierend auf einer Seed-Konfiguration (EDMX-Datei oder DbContext) zu automatisieren. Ich möchte in der Lage sein, eine Skelettlösung zu öffnen, die aktive Instanz abzurufen und Projektdateien mit automatisch generiertem Code zu füllen.Wie wird DTE in PowerShell verwendet?

Ich versuche, das Beispiel here Powershell zu transcodieren, bekomme ich jedoch Fehler.

Hier ist die Powershell-Code-I-Tests sind:

Zuerst fahre ich eine kleine Funktion, die DTE-Baugruppen zu verweisen.

$libs = "envdte.dll", "envdte80.dll", "envdte90.dll", "envdte100.dll" 
function LoadDTELibs { 
    param(
     $path = "\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies" 
    ) 

    Process { 
     $libs | 
      ForEach { 
       $dll = Join-Path "$env:ProgramFiles\$path" $_ 

       if(-not (Test-Path $dll)) { 
        $dll = Join-Path "${env:ProgramFiles(x86)}\$path" $_ 
       } 

       Add-Type -Path $dll -PassThru | Where {$_.IsPublic -and $_.BaseType} | Sort Name 
      } 
    } 
} 


LoadDTELibs 

Dann versuche ich, ein Objekt zu erstellen, das Ergebnis der [System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE.11.0")

PS> $dte = New-Object -ComObject EnvDTE80.DTE2 

New-Object : Retrieving the COM class factory for component with CLSID {00000000-0000-0000-0000-000000000000} failed due to the following error: 80040154 
Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)). 
At line:1 char:8 
+ $dte = New-Object -ComObject EnvDTE80.DTE2 
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : ResourceUnavailable: (:) [New-Object], COMException 
    + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand 

oder referenzieren Aufruf:

PS> $dte = New-Object EnvDTE80.DTE2 

New-Object : Constructor not found. Cannot find an appropriate constructor for type EnvDTE80.DTE2. 
At line:1 char:8 
+ $dte = New-Object EnvDTE80.DTE2 
+  ~~~~~~~~~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : ObjectNotFound: (:) [New-Object], PSArgumentException 
    + FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand 

Schließlich funktioniert das nicht entweder:

PS> [EnvDTE80.DTE2]$dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE.11.0") 

Cannot convert the "System.__ComObject" value of type "System.__ComObject#{04a72314-32e9-48e2-9b87-a63603454f3e}" to type "EnvDTE80.DTE2". 
At line:1 char:1 
+ [EnvDTE80.DTE2]$dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject(... 
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : MetadataError: (:) [], ArgumentTransformationMetadataException 
    + FullyQualifiedErrorId : RuntimeException 

Also, meine Frage ist, wie verwenden Sie DTE von PowerShell? Genauer gesagt, wie wird das Ergebnis des Aufrufs von GetActiveObject in EnvDTE.DTE2 umgewandelt?

+0

Ich glaube, NuGet's [TypeWrapper] (http://nuget.codeplex.com/SourceControl/changeset/view/46278ab10d9a#src/VsConsole/PowerShellHost/Utils/TypeWrapper.cs) -Klasse funktioniert um das gleiche Problem. (** Achtung: ** Apache-lizenzierter Code im Besitz der Outercurve Foundation) – bricelam

+0

Dies ist ein großartiger Vorschlag, und durch die Überprüfung dieses Codes wurden viele Einsichten geliefert. Es scheint jedoch, dass ich eine einfache Alternative gefunden habe. Wie Sie in meiner Antwort sehen werden, behandelt PowerShell den Prozess ein wenig anders. Daher ist Casting wie in MSDN beschrieben nicht erforderlich. –

+0

Wenn Sie die Paketmanagerkonsole in VS verwenden, wird das EnvDTE der aktuellen Instanz bereits von der Variablen $ dte bereitgestellt. – StingyJack

Antwort

13

Ich fand eine einfache Antwort, indem ich eine Weile mit der Idee in ISE spielte.

Grundsätzlich gibt der Aufruf von GetActiveObject ein COM-Objekt zurück, das direkt in PowerShell verwendet werden kann. Nach dem Ausführen von LoadDTELibs können Sie eine Instanz von DTE abrufen, indem Sie GetActiveObject aufrufen und dann direkt auf das Ergebnis verweisen.

So ...

PS> $dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE.11.0") 

Dann:

PS> $dte.solution.Create("D:\Testing", "Acme.sln") 
PS> $dte.solution.SaveAs("D:\Testing\Acme.sln") 

Ich bin nicht 100% sicher, weil ich weiß, Powershell nicht oder COM alles gut, aber ich glaube, Sie don Sie müssen sich wirklich keine Sorgen über die Freigabe der COM-Instanz machen.

+0

Es war [dieser] (http://www.computerperformance.co.uk/powershell/powershell_com.htm) Artikel, der die Hinweise lieferte, die bei der Suche nach der Antwort hilfreich waren. –

+0

"Nach dem Ausführen von LoadDTELibs" - Wie haben Sie das ausgeführt? – Rhyous