WintellectPowerShellHelper/WintellectPowerShellHelper/VisualStudioSetup.cs
using System;
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.Setup.Configuration; using System.Runtime.InteropServices; using System.Diagnostics; using System.Globalization; namespace WintellectPowerShellHelper { /// <summary> /// Helper class for getting all Visual Studio Instances. /// </summary> public static class VisualStudioSetup { private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154); /// <summary> /// Returns the list of <seealso cref="VisualStudioInstance"/> representing the installed /// Visual Studio instances on the machine. /// </summary> /// <param name="lcid"> /// The local id to use for returning internationalized strings. /// </param> /// <param name="includeIncompleteInstances"> /// If true, does all instances, even those that are incomplete. If false, the default, /// does just completed instances. /// </param> /// <param name="includeAllPackages"> /// If true, includes all packages with the returned results. The default is to only /// return the main installation data. /// </param> /// <returns> /// The list of installed instances. An empty list if none are installed. /// </returns> public static IList<VisualStudioInstance> GetInstalledInstances(int lcid = 0, Boolean includeIncompleteInstances = false, Boolean includeAllPackages = false) { List<VisualStudioInstance> resultList = new List<VisualStudioInstance>(); // Grab the config interface and enumerate the instances. var setupConfig = GetSetupConfig(); if (setupConfig != null) { IEnumSetupInstances instanceList = null; if (includeIncompleteInstances == false) { instanceList = setupConfig.EnumInstances(); } else { instanceList = setupConfig.EnumAllInstances(); } // Now it is time to loop! int fetched; ISetupInstance2[] instance = new ISetupInstance2[1]; do { instanceList.Next(1, instance, out fetched); if (fetched > 0) { var filledInstance = FillInInstanceData(instance[0], lcid, includeAllPackages); resultList.Add(filledInstance); } } while (fetched > 0); } return resultList; } private static VisualStudioInstance FillInInstanceData(ISetupInstance2 instance, int lcid, Boolean includePackages) { VisualStudioInstance result = new VisualStudioInstance() { InstanceId = instance.GetInstanceId(), InstalledVersionNumber = instance.GetInstallationVersion(), Description = instance.GetDescription(lcid), DisplayName = instance.GetDisplayName(lcid) }; // Hides the non-CLS clompliant uint. var tempState = instance.GetState(); if (tempState == InstanceState.Complete) { result.Status = InstanceStatus.Complete; } else { result.Status = (InstanceStatus)tempState; } result.InstallationPath = instance.GetInstallationPath(); ISetupPackageReference prod = instance.GetProduct(); if (prod != null) { result.ProductName = prod.GetId(); } if ((result.Status & InstanceStatus.Local) == InstanceStatus.Local) { result.InstallationPath = instance.GetInstallationPath(); } if (includePackages) { ProcessPackages(instance, result); } return result; } private static void ProcessPackages(ISetupInstance2 instance, VisualStudioInstance result) { ISetupPackageReference[] packages = instance.GetPackages(); foreach (var package in packages) { String packageType = package.GetType(); PackageReference refPackage = CreatePackageReference(package); switch (packageType.ToUpper(CultureInfo.InvariantCulture)) { case "PRODUCT": result.Products.Add(refPackage); break; case "WORKLOAD": result.Workloads.Add(refPackage); break; case "COMPONENT": result.Components.Add(refPackage); break; case "VSIX": result.Visx.Add(refPackage); break; case "EXE": result.Exe.Add(refPackage); break; case "MSI": result.Msi.Add(refPackage); break; case "MSU": result.Msu.Add(refPackage); break; case "GROUP": result.Group.Add(refPackage); break; case "WINDOWSFEATURE": result.WindowsFeature.Add(refPackage); break; default: Trace.WriteLine(packageType); result.OtherPackages.Add(refPackage); break; } } } private static PackageReference CreatePackageReference(ISetupPackageReference package) { PackageReference refPackage = new PackageReference() { Branch = package.GetBranch(), Chip = package.GetChip(), Id = package.GetId(), IsExtension = package.GetIsExtension(), Language = package.GetLanguage(), UniqueId = package.GetUniqueId(), Version = package.GetVersion() }; return refPackage; } private static ISetupConfiguration2 GetSetupConfig() { try { // Do the CoCreate dance first. return (ISetupConfiguration2)(new SetupConfiguration()); } catch (COMException ex) when (ex.HResult == REGDB_E_CLASSNOTREG) { // Try it with the app-local call. var result = NativeMethods.GetSetupConfiguration(out var query, IntPtr.Zero); if (result < 0) { // This means VS 2017+ is not installed. return null; } return (ISetupConfiguration2)query; } } } } |