Remove project from solution via Package Manager C

2019-04-27 02:49发布

问题:

I am trying to use powershell within the Package Manager Console to script the removal of a project from a solution and I am having a surprisingly hard time.

I can easily add a project by

PM> $dte.Solution.AddFromFile("C:\Dev\Project1.csproj")

Now I want to be remove a project and can't get anything to work.

I have tried a number of things including:

PM> $project1 = Get-Project "Project1Name"
PM> $dte.Solution.Remove($project1)>

Cannot convert argument "0", with value: "System.__ComObject", for "Remove" to
type "EnvDTE.Project": "Cannot convert the "System.__ComObject" value of type
"System.__ComObject#{866311e6-c887-4143-9833-645f5b93f6f1}" to type
"EnvDTE.Project"."
PM> $project = Get-Interface $project1 ([EnvDTE.Project])
PM> $dte.Solution.Remove($project)

Cannot convert argument "0", with value: "System.__ComObject", for "Remove" to
type "EnvDTE.Project": "Cannot convert the "System.__ComObject" value of type
"NuGetConsole.Host.PowerShell.Implementation.PSTypeWrapper" to type
"EnvDTE.Project"."
PM> $project = [EnvDTE.Project] ($project1)

Cannot convert the "System.__ComObject" value of type
"System.__ComObject#{866311e6-c887-4143-9833-645f5b93f6f1}" to type
"EnvDTE.Project".
PM> $solution2 = Get-Interface $dte.Solution ([EnvDTE80.Solution2])
PM> $solution2.Remove($project1)

Exception calling "Remove" with "1" argument(s): "Exception calling
"InvokeMethod" with "3" argument(s): "Object must implement IConvertible.""
PM> $dte2 = Get-Interface $dte ([EnvDTE80.DTE2])
PM> $dte2.Solution.Remove($project)

Method invocation failed because [System.Object[]] doesn't contain a method
named 'Remove'.

I have tried other combinations, but I am clearly spinning my wheels. I appreciate any suggestions.

回答1:

Right, I know I'm late to the party but I've just been tackling this same issue for an internal NuGet package we've been writing, and I think I've found how to do it.

Indeed Microsoft have (helpfully) left the Delete method unimplemented, and as we have both found, attempting to call the Remove method on the Solution2 interface throws an exciting myriad of errors depending on context!

However what I have found is that directly invoking the Remove method defined in SolutionClass does actually work (despite its being documented by Microsoft as internal use only. But hey, when every other option is exhausted...). The only catch is that the runtime binder also sometimes seems to fail to resolve the method overload, producing the error:

No overload for method 'Remove' takes 1 arguments

All of which means that it's time to get our reflection crayons out! The code looks like this:

$removeMethod = [EnvDTE.SolutionClass].GetMethod("Remove");
$solution = $dte.Solution;
$toremove = ($solution.Projects | where ProjectName -eq "<whatever>");
$removeMethod.Invoke($solution, @($toremove));

After a day of various iterations (many closely resembling those in the question) and varying degrees of success (depending on whether I was executing inside the package manager, from inside the install script or within a debugger), the above is what I have found to be most reliable.

One thing to note is that because the reflected method is defined in EnvDTE.SolutionClass, passing it a EnvDTE._Solution or EnvDTE80.Solution2 throws a Type mismatch error, so unfortunately you cannot obtain your $solution object by the Get-Interface cmdlet (which is usually my preferred method). Doing the cast to [EnvDTE.SolutionClass] wherever possible is obviously preferable, but again I've found varying degrees of success in doing so. Hence the slightly sloppy $solution = $dte.Solution above.

Hope this is useful to someone else!



回答2:

Looks like it is "Delete" instead of "Remove". See this MSDN article

Project prj = dte.Solution.Projects.Item(1);
prj.Delete();