I'd like to automate adding/removing files to/from a SSDT (Database) Project in Powershell 7.
My Solution has 3 SSDT Projects in it and is running in a VS 2019 instance.
I can get the DTE object with help from # Is there a substitue for System.Runtime.InteropServices.Marshal.GetActiveObject() in .NET Core? along with the EnvDTE, EnvDTE80, EnvDTE90 and EnvDTE100 v16.10.31320.204 libraries from Nuget
It feels like I need some more libraries though as I get all these impenetrable System.__ComObject's - but I cannot work out how to discover the libraries that I need.
Here are the main sights I've seen on the journey so far:
> $dte
Name : Microsoft Visual Studio
FileName : C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe
Version : 16.0
CommandBars : System.__ComObject
Windows : System.__ComObject
Events : System.__ComObject
AddIns :
MainWindow : System.__ComObject
ActiveWindow : System.__ComObject
DisplayMode : 2
Solution : System.__ComObject
Commands : System.__ComObject
SelectedItems : System.__ComObject
CommandLineArguments : "C:\Users\bgerhardi\source\Vega\VegaDW\src\VegaDW-DBs.sln"
DTE : System.__ComObject
LocaleID : 1033
WindowConfigurations : System.__ComObject
Documents : System.__ComObject
ActiveDocument : System.__ComObject
Globals : System.__ComObject
StatusBar : System.__ComObject
FullName : C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe
UserControl : True
ObjectExtenders : System.__ComObject
Find : System.__ComObject
Mode : 1
ItemOperations : System.__ComObject
UndoContext : System.__ComObject
Macros :
ActiveSolutionProjects : {}
MacrosIDE :
RegistryRoot : Software\Microsoft\VisualStudio\16.0_cd071aac
Application : System.__ComObject
ContextAttributes : System.__ComObject
SourceControl : System.__ComObject
SuppressUI : False
Debugger : System.__ComObject
Edition : Enterprise
looking in the $env.Solution I can see a nice object and another bunch of System.__ComObject's
> $dte.Solution
System.__ComObject
System.__ComObject
System.__ComObject
Name : Miscellaneous Files
FileName :
IsDirty : False
Collection :
DTE : System.__ComObject
Kind : {66A2671D-8FB5-11D2-AA7E-00C04F688DDE}
ProjectItems : System.__ComObject
Properties :
UniqueName : <MiscFiles>
Object :
ExtenderNames : {}
ExtenderCATID : {610d4612-d0d5-11d2-8599-006097c68e81}
FullName :
Saved : True
ConfigurationManager :
Globals :
ParentProjectItem :
CodeModel :
However I don't see this Miscellanous Files item in the VS UI.
If I try to go into these, strangely there is nothing in 0 but just these impenetrable System.__ComObject's
> $dte.Solution[0]
OperationStopped: Value does not fall within the expected range.
> $dte.Solution[1]
System.__ComObject
> $dte.Solution[1] | gm
>
I've tried casting to a few differnet things but all tell me a (COM?) GUID that I can't find anywhere in my registry or on the internet
> [EnvDTE.Project]$dte.Solution[1]
InvalidArgument: Cannot convert the "System.__ComObject" value of type "System.__ComObject#{2aa7b615-65c8-356e-8652-98f68ab7548e}" to type "EnvDTE.Project".
What is the right way to navigate my way through these __ComObject's and find the correct Types that I need?
To create a repro for this on your own machine, simply
- create a new "SQL Server Database Project" in Visual Studio 2019. It behaves the same way for me - impenetrable System.__ComObject's
- Run PS7 instance
- run the following
$methoddef = 'public static object GetActiveObject(string progId, bool throwOnError = false) { if (progId == null) throw new ArgumentNullException(nameof(progId)); var hr = CLSIDFromProgIDEx(progId, out var clsid); if (hr < 0) { if (throwOnError) Marshal.ThrowExceptionForHR(hr); return null; } hr = GetActiveObject(clsid, IntPtr.Zero, out var obj); if (hr < 0) { if (throwOnError) Marshal.ThrowExceptionForHR(hr); return null; } return obj; } [DllImport("ole32")] private static extern int CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] string lpszProgID, out Guid lpclsid); [DllImport("oleaut32")] private static extern int GetActiveObject([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk);' $blah = add-type -MemberDefinition $methoddef -Name "Blah" -Namespace "Blah" -PassThru $dte = $blah::GetActiveObject('VisualStudio.DTE.16.0')
- notice that
$dte.ActiveSolutionProjects[0]
returns nothing useful, just System.__ComObject