// Copyright 2017 - Refael Ackermann // Distributed under MIT style license // See accompanying file LICENSE at https://github.com/node4good/windows-autoconf // Usage: // powershell -ExecutionPolicy Unrestricted -Command "Add-Type -Path Find-VisualStudio.cs; [VisualStudioConfiguration.Main]::PrintJson()" // This script needs to be compatible with PowerShell v2 to run on Windows 2008R2 and Windows 7. using System; using System.Text; using System.Runtime.InteropServices; using System.Collections.Generic; namespace VisualStudioConfiguration { [Flags] public enum InstanceState : uint { None = 0, Local = 1, Registered = 2, NoRebootRequired = 4, NoErrors = 8, Complete = 4294967295, } [Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface IEnumSetupInstances { void Next([MarshalAs(UnmanagedType.U4), In] int celt, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt, [MarshalAs(UnmanagedType.U4)] out int pceltFetched); void Skip([MarshalAs(UnmanagedType.U4), In] int celt); void Reset(); [return: MarshalAs(UnmanagedType.Interface)] IEnumSetupInstances Clone(); } [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupConfiguration { } [Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupConfiguration2 : ISetupConfiguration { [return: MarshalAs(UnmanagedType.Interface)] IEnumSetupInstances EnumInstances(); [return: MarshalAs(UnmanagedType.Interface)] ISetupInstance GetInstanceForCurrentProcess(); [return: MarshalAs(UnmanagedType.Interface)] ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path); [return: MarshalAs(UnmanagedType.Interface)] IEnumSetupInstances EnumAllInstances(); } [Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupInstance { } [Guid("89143C9A-05AF-49B0-B717-72E218A2185C")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupInstance2 : ISetupInstance { [return: MarshalAs(UnmanagedType.BStr)] string GetInstanceId(); [return: MarshalAs(UnmanagedType.Struct)] System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate(); [return: MarshalAs(UnmanagedType.BStr)] string GetInstallationName(); [return: MarshalAs(UnmanagedType.BStr)] string GetInstallationPath(); [return: MarshalAs(UnmanagedType.BStr)] string GetInstallationVersion(); [return: MarshalAs(UnmanagedType.BStr)] string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid); [return: MarshalAs(UnmanagedType.BStr)] string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid); [return: MarshalAs(UnmanagedType.BStr)] string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath); [return: MarshalAs(UnmanagedType.U4)] InstanceState GetState(); [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] ISetupPackageReference[] GetPackages(); ISetupPackageReference GetProduct(); [return: MarshalAs(UnmanagedType.BStr)] string GetProductPath(); [return: MarshalAs(UnmanagedType.VariantBool)] bool IsLaunchable(); [return: MarshalAs(UnmanagedType.VariantBool)] bool IsComplete(); [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] ISetupPropertyStore GetProperties(); [return: MarshalAs(UnmanagedType.BStr)] string GetEnginePath(); } [Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupPackageReference { [return: MarshalAs(UnmanagedType.BStr)] string GetId(); [return: MarshalAs(UnmanagedType.BStr)] string GetVersion(); [return: MarshalAs(UnmanagedType.BStr)] string GetChip(); [return: MarshalAs(UnmanagedType.BStr)] string GetLanguage(); [return: MarshalAs(UnmanagedType.BStr)] string GetBranch(); [return: MarshalAs(UnmanagedType.BStr)] string GetType(); [return: MarshalAs(UnmanagedType.BStr)] string GetUniqueId(); [return: MarshalAs(UnmanagedType.VariantBool)] bool GetIsExtension(); } [Guid("c601c175-a3be-44bc-91f6-4568d230fc83")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] public interface ISetupPropertyStore { [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] string[] GetNames(); object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName); } [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] [CoClass(typeof(SetupConfigurationClass))] [ComImport] public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration { } [Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")] [ClassInterface(ClassInterfaceType.None)] [ComImport] public class SetupConfigurationClass { } public static class Main { public static void PrintJson() { ISetupConfiguration query = new SetupConfiguration(); ISetupConfiguration2 query2 = (ISetupConfiguration2)query; IEnumSetupInstances e = query2.EnumAllInstances(); int pceltFetched; ISetupInstance2[] rgelt = new ISetupInstance2[1]; List instances = new List(); while (true) { e.Next(1, rgelt, out pceltFetched); if (pceltFetched <= 0) { Console.WriteLine(String.Format("[{0}]", string.Join(",", instances.ToArray()))); return; } try { instances.Add(InstanceJson(rgelt[0])); } catch (COMException) { // Ignore instances that can't be queried. } } } private static string JsonString(string s) { return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; } private static string InstanceJson(ISetupInstance2 setupInstance2) { // Visual Studio component directory: // https://docs.microsoft.com/en-us/visualstudio/install/workload-and-component-ids StringBuilder json = new StringBuilder(); json.Append("{"); string path = JsonString(setupInstance2.GetInstallationPath()); json.Append(String.Format("\"path\":{0},", path)); string version = JsonString(setupInstance2.GetInstallationVersion()); json.Append(String.Format("\"version\":{0},", version)); List packages = new List(); foreach (ISetupPackageReference package in setupInstance2.GetPackages()) { string id = JsonString(package.GetId()); packages.Add(id); } json.Append(String.Format("\"packages\":[{0}]", string.Join(",", packages.ToArray()))); json.Append("}"); return json.ToString(); } } }