Skip to content

Instantly share code, notes, and snippets.

@damianh
Created November 18, 2016 16:23
Show Gist options
  • Save damianh/0215b54dbb4b2570461b6d2866acd284 to your computer and use it in GitHub Desktop.
Save damianh/0215b54dbb4b2570461b6d2866acd284 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Setup.Configuration;
namespace LocateMSBuild
{
public class Instance
{
private static ISetupConfiguration GetSetupConfiguration()
{
ISetupConfiguration setupConfiguration;
try
{
setupConfiguration = new SetupConfiguration();
}
catch (COMException comException) when (comException.HResult == unchecked((int)0x80040154))
{
Console.WriteLine("COM registration is missing, Visual Studio may not be installed correctly");
throw;
}
return setupConfiguration;
}
private static IEnumerable<ISetupInstance> EnumerateVisualStudioInstances()
{
var setupConfiguration = GetSetupConfiguration() as ISetupConfiguration2;
var instanceEnumerator = setupConfiguration.EnumAllInstances();
var instances = new ISetupInstance[3];
var instancesFetched = 0;
instanceEnumerator.Next(instances.Length, instances, out instancesFetched);
if (instancesFetched == 0)
{
throw new Exception("There were no instances of Visual Studio 15.0 or later found.");
}
do
{
for (var index = 0; index < instancesFetched; index++)
{
yield return instances[index];
}
instanceEnumerator.Next(instances.Length, instances, out instancesFetched);
}
while (instancesFetched != 0);
}
private static ISetupInstance LocateVisualStudioInstance(string vsProductVersion, HashSet<string> requiredPackageIds)
{
var instances = EnumerateVisualStudioInstances().Where((instance) => instance.GetInstallationVersion().StartsWith(vsProductVersion));
var instanceFoundWithInvalidState = false;
foreach (ISetupInstance2 instance in instances.OrderByDescending(i => i.GetInstallationVersion()))
{
var packages = instance.GetPackages()
.Where((package) => requiredPackageIds.Contains(package.GetId()));
if (packages.Count() != requiredPackageIds.Count)
{
continue;
}
const InstanceState minimumRequiredState = InstanceState.Local | InstanceState.Registered;
var state = instance.GetState();
if ((state & minimumRequiredState) == minimumRequiredState)
{
return instance;
}
Console.WriteLine($"An instance matching the specified requirements but had an invalid state. (State: {state})");
instanceFoundWithInvalidState = true;
}
throw new Exception(instanceFoundWithInvalidState ?
"An instance matching the specified requirements was found but it was in an invalid state." :
"There were no instances of Visual Studio 15.0 or later found that match the specified requirements.");
}
public static string GetMsBuildInstallPath()
{
var instance = LocateVisualStudioInstance("15.0", new HashSet<string>(new[] { "Microsoft.Component.MSBuild" })) as ISetupInstance2;
var installationPath = instance.GetInstallationPath();
return Path.Combine(installationPath, "MSBuild", "15.0");
}
}
}
@damianh
Copy link
Author

damianh commented Nov 18, 2016

Using in Powershell

function Locate-MsBuildInstallPath {
  $locateVsApi = Locate-LocateMsBuildApi
  Add-Type -path $locateVsApi
  $vsInstallPath = [LocateMSBuild.Instance]::GetMsBuildInstallPath()
  return Resolve-Path -path $vsInstallPath
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment