├── .gitattributes
├── .gitignore
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── CONTRIBUTING.md
├── DataFiles
├── Microsoft Visual Studio Community 2013 with Update 5.bin
├── Microsoft Visual Studio Community 2015.bin
├── Microsoft Visual Studio Enterprise 2015.bin
├── Microsoft Visual Studio Premium 2012.bin
├── Microsoft Visual Studio Premium 2013 with Update 5.bin
├── Microsoft Visual Studio Professional 2012.bin
├── Microsoft Visual Studio Professional 2013 with Update 4.bin
├── Microsoft Visual Studio Professional 2013 with Update 5.bin
├── Microsoft Visual Studio Professional 2015.bin
├── Microsoft Visual Studio Ultimate 2013 with Update 5.bin
└── Microsoft Visual Studio Ultimate 2013.bin
├── ReadMe.md
├── TotalUninstaller EULA.docx
├── Uninstaller.sln
├── UninstallerTests
├── ConfigurationManagerSupportTests.cs
├── ConfigurationManagerTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── Uninstall_WrapperTests.cs
└── UninstallerTests.csproj
├── lib
├── Branding.rc
├── Branding.targets
├── Common.Cpp.props
├── Common.NuGet.targets
├── Common.csproj.props
├── Common.csproj.targets
├── Common.props
├── Common.ruleset
├── Common.targets
└── Common.vcxproj.targets
├── license.txt
├── src
├── Uninstall_Wrapper
│ ├── App.config
│ ├── CommandOption.cs
│ ├── ConsoleOperations.cs
│ ├── DataFile.bin
│ ├── Program.cs
│ ├── TotalUninstaller EULA.docx
│ ├── Uninstall_Wrapper.csproj
│ ├── VisualStudioSpecifc.cs
│ ├── app.manifest
│ └── packages.config
├── VS.ConfigurationManager.Support
│ ├── ArchitectureConfiguration.cs
│ ├── ConfigurationManagerException.cs
│ ├── ElevationDetection.cs
│ ├── Logger.cs
│ ├── NativeMethods.cs
│ ├── OperatingSystemConfiguration.cs
│ ├── RegistryHandler.cs
│ ├── Utility.cs
│ ├── VS.ConfigurationManager.Support.csproj
│ └── packages.config
└── VS.ConfigurationManager
│ ├── Bundle.cs
│ ├── BundlesAndPackagesStore.cs
│ ├── External
│ ├── Microsoft.Deployment.WindowsInstaller.dll
│ └── wix.dll
│ ├── Filter.cs
│ ├── Package.cs
│ ├── Primitives.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── SystemSettings.cs
│ ├── UninstallAction.cs
│ ├── VS.ConfigurationManager.csproj
│ └── packages.config
└── tools
├── PreBuild.ps1
└── Publish.proj
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | bld/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # Roslyn cache directories
20 | *.ide/
21 |
22 | # MSTest test Results
23 | [Tt]est[Rr]esult*/
24 | [Bb]uild[Ll]og.*
25 |
26 | #NUNIT
27 | *.VisualState.xml
28 | TestResult.xml
29 |
30 | # Build Results of an ATL Project
31 | [Dd]ebugPS/
32 | [Rr]eleasePS/
33 | dlldata.c
34 |
35 | *_i.c
36 | *_p.c
37 | *_i.h
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.svclog
58 | *.scc
59 |
60 | # Chutzpah Test files
61 | _Chutzpah*
62 |
63 | # Visual C++ cache files
64 | ipch/
65 | *.aps
66 | *.ncb
67 | *.opensdf
68 | *.sdf
69 | *.cachefile
70 |
71 | # Visual Studio profiler
72 | *.psess
73 | *.vsp
74 | *.vspx
75 |
76 | # TFS 2012 Local Workspace
77 | $tf/
78 |
79 | # Guidance Automation Toolkit
80 | *.gpState
81 |
82 | # ReSharper is a .NET coding add-in
83 | _ReSharper*/
84 | *.[Rr]e[Ss]harper
85 | *.DotSettings.user
86 |
87 | # JustCode is a .NET coding addin-in
88 | .JustCode
89 |
90 | # TeamCity is a build add-in
91 | _TeamCity*
92 |
93 | # DotCover is a Code Coverage Tool
94 | *.dotCover
95 |
96 | # NCrunch
97 | _NCrunch_*
98 | .*crunch*.local.xml
99 |
100 | # MightyMoose
101 | *.mm.*
102 | AutoTest.Net/
103 |
104 | # Web workbench (sass)
105 | .sass-cache/
106 |
107 | # Installshield output folder
108 | [Ee]xpress/
109 |
110 | # DocProject is a documentation generator add-in
111 | DocProject/buildhelp/
112 | DocProject/Help/*.HxT
113 | DocProject/Help/*.HxC
114 | DocProject/Help/*.hhc
115 | DocProject/Help/*.hhk
116 | DocProject/Help/*.hhp
117 | DocProject/Help/Html2
118 | DocProject/Help/html
119 |
120 | # Click-Once directory
121 | publish/
122 |
123 | # Publish Web Output
124 | *.[Pp]ublish.xml
125 | *.azurePubxml
126 | ## TODO: Comment the next line if you want to checkin your
127 | ## web deploy settings but do note that will include unencrypted
128 | ## passwords
129 | #*.pubxml
130 |
131 | # NuGet Packages Directory
132 | packages/*
133 | ## TODO: If the tool you use requires repositories.config
134 | ## uncomment the next line
135 | #!packages/repositories.config
136 |
137 | # Enable "build/" folder in the NuGet Packages folder since
138 | # NuGet packages use it for MSBuild targets.
139 | # This line needs to be after the ignore of the build folder
140 | # (and the packages folder if the line above has been uncommented)
141 | !packages/build/
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # LightSwitch generated files
187 | GeneratedArtifacts/
188 | _Pvt_Extensions/
189 | ModelManifest.xml
190 |
191 | # Original shared repo content
192 | telemetry/
193 | tools/*/
194 |
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 |
32 |
33 |
34 |
35 | $(SolutionDir).nuget
36 |
37 |
38 |
39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config
40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config
41 |
42 |
43 |
44 | $(MSBuildProjectDirectory)\packages.config
45 | $(PackagesProjectConfig)
46 |
47 |
48 |
49 |
50 | $(NuGetToolsPath)\NuGet.exe
51 | @(PackageSource)
52 |
53 | "$(NuGetExePath)"
54 | mono --runtime=v4.0.30319 "$(NuGetExePath)"
55 |
56 | $(TargetDir.Trim('\\'))
57 |
58 | -RequireConsent
59 | -NonInteractive
60 |
61 | "$(SolutionDir) "
62 | "$(SolutionDir)"
63 |
64 |
65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
67 |
68 |
69 |
70 | RestorePackages;
71 | $(BuildDependsOn);
72 |
73 |
74 |
75 |
76 | $(BuildDependsOn);
77 | BuildPackage;
78 |
79 |
80 |
81 |
82 |
83 |
84 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute to the Microsoft Visual Studio Uninstaller
2 |
3 | In order to contribute, you will need to be able to build the source, deploy to test and run automated tests.
4 | Please fork and send pull requests.
5 |
6 | ## Building From Source
7 |
8 | ### Clone the repo
9 | ```bash
10 | git clone https://github.com/Microsoft/VisualStudioUninstaller.git
11 | ```
12 |
13 | ### Build Pre-reqs
14 |
15 | You will need Visual Studio 2013 Community or greater in order to build this project.
16 | ```bash
17 | Download it for free here: https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx
18 | ```
19 |
20 | ### Build
21 | Open Uninstaller.sln in Visual Studio
22 | ```bash
23 | Build Solution
24 | ```
25 |
26 | This builds the project and output binaries to ./bin/Debug
27 |
28 | ### Run Tests
29 |
30 | Please run all unit tests in the solution prior to PR.
31 |
32 | ```bash
33 | Unit tests
34 | ```
35 |
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Community 2013 with Update 5.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Community 2013 with Update 5.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Community 2015.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Community 2015.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Enterprise 2015.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Enterprise 2015.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Premium 2012.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Premium 2012.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Premium 2013 with Update 5.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Premium 2013 with Update 5.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Professional 2012.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Professional 2012.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Professional 2013 with Update 4.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Professional 2013 with Update 4.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Professional 2013 with Update 5.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Professional 2013 with Update 5.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Professional 2015.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Professional 2015.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Ultimate 2013 with Update 5.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Ultimate 2013 with Update 5.bin
--------------------------------------------------------------------------------
/DataFiles/Microsoft Visual Studio Ultimate 2013.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/DataFiles/Microsoft Visual Studio Ultimate 2013.bin
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | Visual Studio Uninstaller
2 | =========
3 |
4 | This executable is designed to clean up and delete Preview, RC and final releases of Visual Studio 2013 and Visual Studio 2015. It is designed to be used as a final resort to clean up a system of remaining artifacts from a non-successful installation, instead of having to reimage the machine.
5 |
6 | WARNING: running this application may stop earlier remaining installations of Visual Studio 2012 and earlier from working, because Visual Studio 2012 and below share MSI upgrade code with Visual Studio 2013 and above.
7 |
8 | Download: https://github.com/Microsoft/VisualStudioUninstaller/releases
9 |
10 | How it works?
11 | ========
12 |
13 | This app finds and uninstall every Preview/RC/RTM release of Visual Studio 2013 and 2015. It will first execute uninstall command on the bundle, and then it will uninstall any stale MSIs. The application contains a master list of Bundle IDs and upgrade codes for every MSI ever chained in by Visual Studio 2013-2015. It will not uninstall MSU or MSIs that marked as ReallyPermanent.
14 |
15 | Status
16 | ========
17 | Shipped
18 |
19 | Contributing and building this project
20 | ========
21 | See CONTRIBUTING.md
22 |
23 | Goals/Vision/Scope
24 | ========
25 | Our goal is to provide a way to thoroughly and reliably remove Visual Studio. This program first attempts to force uninstall Visual Studio from top down, and then remove any remaining MSIs and MSUs. This program will work on any BURN based Visual Studio; that means this program is only capable of removing Visual Studio 2012 - 2015.
26 |
27 | Mailing list/contacts/forums
28 | ========
29 | https://www.visualstudio.com/support/support-overview-vs
30 |
31 | Usage
32 | ========
33 |
34 | **How to debug Total Uninstaller remotely?**
35 |
36 | IMPORTANT: Do not run this on your development machine without setting the `DoNotExecuteProcess` flag. This will prevent the application from uninstalling the very development environment you are working from.
37 |
38 | To get the most out of the debug experience, I recommend the following:
39 |
40 | 1. Create a VM with Dev14 installed.
41 | 2. Start the 64-bit remote debugger with administrative privileges.
42 | 3. Copy the debug Bin directory to the VM.
43 | 4. Run the application with Administrative privileges.
44 | 5. Create a snapshot of the machine using Hyper-V.
45 | 6. Start a remote debugging session to your VM and attach.
46 | 7. Step through to your hearts delight.
47 | 8. If you find something you don’t like, restore the snapshot and recopy the Bin directory and go to step 6 again.
48 |
49 | **Using Total Uninstall:**
50 |
51 | 1. Download and unzip the zip file to a folder.
52 | 2. Open cmd.exe with Administrative privileges
53 | 2. Execute Setup.ForcedUninstall.exe
54 | 3. Press Y and hit enter to run the application.
55 | 4. If the application ask to reboot the system, please reboot the system, and rerun this application again.
56 |
57 | **Commands:**
58 |
59 | 1. help or /help or /? : Print usage.
60 | 2. break : run the application and pause until the user hit any key.
61 | 3. noprocess : run the application but does not uninstall anything.
62 |
63 | Roadmap
64 | ========
65 | 1. Periodically update of the Total Uninstaller to ensure the data used for uninstallation is up to date with the most recent Visual Studio releases.
66 |
67 | Open issues
68 | ========
69 | Please file an issue request as necessary.
70 |
71 | Guidelines
72 | =========
73 | These are general guidelines for source code within this solution:
74 |
75 | Native code
76 | -----------
77 |
78 | * Parameters should be declared with SAL annotation.
79 | * Input string parameters should be declared as LPCWSTR.
80 | * Output string parameters should be declared as CStringW& references.
81 | * Class members should not be references or pointers, but be created and destroyed with the owning class.
82 |
83 |
84 | Managed code
85 | -----------
86 |
87 | Please follow these coding standards:
88 | https://msdn.microsoft.com/en-us/library/Ff926074.aspx?f=255&MSPPError=-2147217396
89 |
--------------------------------------------------------------------------------
/TotalUninstaller EULA.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/TotalUninstaller EULA.docx
--------------------------------------------------------------------------------
/Uninstaller.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Uninstall_Wrapper", "src\Uninstall_Wrapper\Uninstall_Wrapper.csproj", "{1E70C6F2-8570-4620-822E-E3F71BF1A0F7}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VS.ConfigurationManager", "src\VS.ConfigurationManager\VS.ConfigurationManager.csproj", "{CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VS.ConfigurationManager.Support", "src\VS.ConfigurationManager.Support\VS.ConfigurationManager.Support.csproj", "{13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UninstallerTests", "UninstallerTests\UninstallerTests.csproj", "{9727E23C-496A-4887-9C87-C5A96F3B05B1}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {1E70C6F2-8570-4620-822E-E3F71BF1A0F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1E70C6F2-8570-4620-822E-E3F71BF1A0F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1E70C6F2-8570-4620-822E-E3F71BF1A0F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1E70C6F2-8570-4620-822E-E3F71BF1A0F7}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {9727E23C-496A-4887-9C87-C5A96F3B05B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {9727E23C-496A-4887-9C87-C5A96F3B05B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {9727E23C-496A-4887-9C87-C5A96F3B05B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {9727E23C-496A-4887-9C87-C5A96F3B05B1}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/UninstallerTests/ConfigurationManagerSupportTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 | using Microsoft.VS.ConfigurationManager.Support;
6 |
7 | namespace UninstallerTests
8 | {
9 | ///
10 | /// Summary description for ConfigurationManagerSupportTestscs
11 | ///
12 | [TestClass]
13 | public class ConfigurationManagerSupportTests
14 | {
15 | public ConfigurationManagerSupportTests()
16 | {
17 | //
18 | // TODO: Add constructor logic here
19 | //
20 | }
21 |
22 | private TestContext testContextInstance;
23 |
24 | ///
25 | ///Gets or sets the test context which provides
26 | ///information about and functionality for the current test run.
27 | ///
28 | public TestContext TestContext
29 | {
30 | get
31 | {
32 | return testContextInstance;
33 | }
34 | set
35 | {
36 | testContextInstance = value;
37 | }
38 | }
39 |
40 | #region Additional test attributes
41 | //
42 | // You can use the following additional attributes as you write your tests:
43 | //
44 | // Use ClassInitialize to run code before running the first test in the class
45 | // [ClassInitialize()]
46 | // public static void MyClassInitialize(TestContext testContext) { }
47 | //
48 | // Use ClassCleanup to run code after all tests in a class have run
49 | // [ClassCleanup()]
50 | // public static void MyClassCleanup() { }
51 | //
52 | // Use TestInitialize to run code before running each test
53 | // [TestInitialize()]
54 | // public void MyTestInitialize() { }
55 | //
56 | // Use TestCleanup to run code after each test has run
57 | // [TestCleanup()]
58 | // public void MyTestCleanup() { }
59 | //
60 | #endregion
61 |
62 | [TestMethod]
63 | public void LoggerTest()
64 | {
65 | Logger.LogLocation = null;
66 | Assert.IsTrue(Logger.LogLocation.StartsWith(System.IO.Path.GetTempPath()));
67 | Assert.IsTrue(Logger.LogLocation.EndsWith(".LOG", StringComparison.OrdinalIgnoreCase));
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/UninstallerTests/ConfigurationManagerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using Microsoft.VS.ConfigurationManager;
4 |
5 | namespace UninstallerTests
6 | {
7 | [TestClass]
8 | public class ConfigurationManagerTests
9 | {
10 | [TestMethod]
11 | public void BundleConstructorTest()
12 | {
13 | Bundle bundle = new Bundle();
14 | Assert.IsTrue(bundle.BundleId == Guid.Empty);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/UninstallerTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("UninstallerTests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("UninstallerTests")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("bfdfc571-75be-4727-9696-e1f7cff3edd6")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/UninstallerTests/Uninstall_WrapperTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace UninstallerTests
7 | {
8 | ///
9 | /// Summary description for Uninstall_Wrapper
10 | ///
11 | [TestClass]
12 | public class Uninstall_WrapperTests
13 | {
14 | public Uninstall_WrapperTests()
15 | {
16 | //
17 | // TODO: Add constructor logic here
18 | //
19 | }
20 |
21 | private TestContext testContextInstance;
22 |
23 | ///
24 | ///Gets or sets the test context which provides
25 | ///information about and functionality for the current test run.
26 | ///
27 | public TestContext TestContext
28 | {
29 | get
30 | {
31 | return testContextInstance;
32 | }
33 | set
34 | {
35 | testContextInstance = value;
36 | }
37 | }
38 |
39 | #region Additional test attributes
40 | //
41 | // You can use the following additional attributes as you write your tests:
42 | //
43 | // Use ClassInitialize to run code before running the first test in the class
44 | // [ClassInitialize()]
45 | // public static void MyClassInitialize(TestContext testContext) { }
46 | //
47 | // Use ClassCleanup to run code after all tests in a class have run
48 | // [ClassCleanup()]
49 | // public static void MyClassCleanup() { }
50 | //
51 | // Use TestInitialize to run code before running each test
52 | // [TestInitialize()]
53 | // public void MyTestInitialize() { }
54 | //
55 | // Use TestCleanup to run code after each test has run
56 | // [TestCleanup()]
57 | // public void MyTestCleanup() { }
58 | //
59 | #endregion
60 |
61 | [TestMethod]
62 | public void TestMethod1()
63 | {
64 | //
65 | // TODO: Add test logic here
66 | //
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/UninstallerTests/UninstallerTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {9727E23C-496A-4887-9C87-C5A96F3B05B1}
7 | Library
8 | Properties
9 | UninstallerTests
10 | UninstallerTests
11 | v4.5
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | {1e70c6f2-8570-4620-822e-e3f71bf1a0f7}
61 | Uninstall_Wrapper
62 |
63 |
64 | {13c73873-a5ed-42de-97f0-a3b2d7a1d76f}
65 | VS.ConfigurationManager.Support
66 |
67 |
68 | {caccc6e1-fcb8-4dbe-9159-0f8eaa69d27a}
69 | VS.ConfigurationManager
70 |
71 |
72 |
73 |
74 |
75 |
76 | False
77 |
78 |
79 | False
80 |
81 |
82 | False
83 |
84 |
85 | False
86 |
87 |
88 |
89 |
90 |
91 |
92 |
99 |
--------------------------------------------------------------------------------
/lib/Branding.rc:
--------------------------------------------------------------------------------
1 | // To use, remove any version information from projects' .rc files and define the following:
2 | //
3 | // #define VER_APP (VER_DLL, none)
4 | // #define VER_LANG_NEUTRAL (optional)
5 | // #define VER_ORIGINAL_FILENAME "foo.exe"
6 | // #define VER_INTERNAL_NAME "foo"
7 | // #define VER_PRODUCT_NAME "Foo"
8 | // #define VER_FILE_DESCRIPTION "Description of foo.exe"
9 | // #include "Branding.rc"
10 | //
11 | // Optionally, define the following before the #include to customize translation block:
12 | //
13 | // #define VER_LANG 0x0000
14 | // #define VER_CP 0x04E4
15 | // #define VER_BLOCK "000004E4"
16 | //
17 |
18 | #include
19 | #include "BrandingInfo.h"
20 |
21 | #ifdef DEBUG
22 | #define VER_DEBUG VS_FF_DEBUG
23 | #define VER_PRIVATE_BUILD VS_FF_PRIVATEBUILD
24 | #define VER_PRE_RELEASE (VS_FF_PRERELEASE | VS_FF_SPECIALBUILD)
25 | #else
26 | #define VER_DEBUG 0
27 | #define VER_PRIVATE_BUILD 0
28 | #define VER_PRE_RELEASE 0
29 | #endif
30 |
31 | #if defined(VER_APP)
32 | #define VER_FILE_TYPE VFT_APP
33 | #elif defined(VER_DLL)
34 | #define VER_FILE_TYPE VFT_DLL
35 | #else
36 | #define VER_FILE_TYPE VFT_UNKNOWN
37 | #endif
38 |
39 | #if defined(VER_LANG_NEUTRAL)
40 | #ifndef VER_LANG
41 | #define VER_LANG 0x0000
42 | #endif
43 | #ifndef VER_CP
44 | #define VER_CP 0x04E4
45 | #endif
46 | #ifndef VER_BLOCK
47 | #define VER_BLOCK "000004E4"
48 | #endif
49 | #else
50 | #ifndef VER_LANG
51 | #define VER_LANG 0x0409
52 | #endif
53 | #ifndef VER_CP
54 | #define VER_CP 0x04E4
55 | #endif
56 | #ifndef VER_BLOCK
57 | #define VER_BLOCK "040904E4"
58 | #endif
59 | #endif
60 |
61 | #define VER_FILE_VERSION MAJOR_VERSION, MINOR_VERSION, BUILD_VERSION, REVISION_NUMBER
62 | #define VER_FILE_VERSION_STRING vwzProductVersion
63 | #define VER_PRODUCT_VERSION MAJOR_VERSION, MINOR_VERSION, BUILD_VERSION, REVISION_NUMBER
64 | #define VER_PRODUCT_VERSION_STRING vwzProductVersion
65 | #define VER_FILE_FLAGS_MASK VS_FFI_FILEFLAGSMASK
66 | #define VER_FILE_FLAGS (VER_DEBUG | VER_PRIVATE_BUILD | VER_PRE_RELEASE)
67 |
68 | #define VER_FILE_OS VOS__WINDOWS32
69 |
70 | #define VER_COMPANY_NAME "Microsoft Corporation"
71 | #ifndef VER_PRODUCT_NAME
72 | #define VER_PRODUCT_NAME "Visual Studio"
73 | #endif
74 | #ifndef VER_FILE_DESCRIPTION
75 | #define VER_FILE_DESCRIPTION "Visual Studio component"
76 | #endif
77 |
78 | #if defined(VER_LEGAL_COPYRIGHT)
79 | #error
80 | #endif
81 | #define VER_LEGAL_COPYRIGHT "Copyright (c) Microsoft Corporation. All rights reserved."
82 |
83 | #if !defined(VER_FILE_SUBTYPE)
84 | #define VER_FILE_SUBTYPE 0
85 | #endif
86 |
87 | #ifdef RC_INVOKED
88 |
89 | VS_VERSION_INFO VERSIONINFO
90 | FILEVERSION VER_FILE_VERSION
91 | PRODUCTVERSION VER_PRODUCT_VERSION
92 | FILEFLAGSMASK VER_FILE_FLAGS_MASK
93 | FILEFLAGS VER_FILE_FLAGS
94 | FILEOS VER_FILE_OS
95 | FILETYPE VER_FILE_TYPE
96 | FILESUBTYPE VER_FILE_SUBTYPE
97 | BEGIN
98 | BLOCK "StringFileInfo"
99 | BEGIN
100 | BLOCK VER_BLOCK
101 | BEGIN
102 | VALUE "CompanyName", VER_COMPANY_NAME
103 | VALUE "FileDescription", VER_FILE_DESCRIPTION
104 | VALUE "FileVersion", VER_FILE_VERSION_STRING
105 | VALUE "InternalName", VER_INTERNAL_NAME
106 | VALUE "LegalCopyright", VER_LEGAL_COPYRIGHT
107 | VALUE "OriginalFilename", VER_ORIGINAL_FILENAME
108 | VALUE "ProductName", VER_PRODUCT_NAME
109 | VALUE "ProductVersion", VER_FILE_VERSION_STRING
110 | END
111 | END
112 |
113 | BLOCK "VarFileInfo"
114 | BEGIN
115 | VALUE "Translation", VER_LANG, VER_CP
116 | END
117 | END
118 |
119 | #endif
120 |
--------------------------------------------------------------------------------
/lib/Branding.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 | 0
6 |
7 | alpha
8 |
9 |
10 |
11 |
12 |
13 | $([System.DateTime]::Now.Subtract($([System.DateTime]::Parse("01/01/2000 00:00:00"))).Days)
14 | $([System.Convert]::ToInt32($([MSBuild]::Divide($([System.DateTime]::Now.Subtract($([System.DateTime]::Parse("00:00:00"))).TotalSeconds), 2))))
15 | $(MajorVersion).$(MinorVersion).$(BuildVersion)
16 | $(MajorVersion).$(MinorVersion).$(BuildVersion)-$(ReleaseToken)-$(RevisionNumber)
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/Common.Cpp.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | v120
6 | Unicode
7 | true
8 | 4006,4221
9 |
10 |
11 | false
12 | v120
13 | true
14 | Unicode
15 | false
16 | 4006,4221
17 |
18 |
19 |
20 | Use
21 | Level3
22 | Disabled
23 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
24 | MultiThreadedDebug
25 | true
26 | true
27 |
28 |
29 | true
30 | true
31 | true
32 |
33 |
34 |
35 |
36 | Level3
37 | Use
38 | MaxSpeed
39 | true
40 | true
41 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
42 | MultiThreaded
43 | true
44 | true
45 |
46 |
47 | true
48 | true
49 | true
50 | true
51 | true
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/lib/Common.NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <_OutDir>$(OutDir.Trim('\\'))
7 | $(BuildCommand) -BasePath "$(_OutDir)" -Properties "Src=$(SourceDir);Version=$(ProductVersion)" -NoPackageAnalysis -Verbosity Detailed
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/Common.csproj.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Properties
5 | Microsoft.VisualStudio.Setup.$(MSBuildProjectName)
6 | v4.5
7 |
8 |
9 | true
10 | full
11 | false
12 | $(DefineConstants);DEBUG;TRACE
13 | prompt
14 | 4
15 |
16 |
17 | pdbonly
18 | true
19 | $(DefineConstants);TRACE
20 | prompt
21 | 4
22 |
23 |
24 |
25 | true
26 | $(MSBuildThisFileDirectory)Common.ruleset
27 | $(DefineConstants);CODE_ANALYSIS
28 | $(OutDir)\$(AssemblyName).xml
29 |
30 |
31 |
--------------------------------------------------------------------------------
/lib/Common.csproj.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
8 |
9 |
10 |
11 | $(SolutionDir)obj\$(Configuration)\BrandingInfo.cs
12 |
13 | WriteBrandingInfo;
14 | $(BuildDependsOn);
15 |
16 |
17 |
18 |
19 | Properties\BrandingInfo.cs
20 |
21 |
22 |
27 |
28 | <_BrandingInfoFile Include="$(BrandingInfoFile)"/>
29 |
30 |
31 | <_BrandingInfo Include="System.Reflection.AssemblyCompanyAttribute">
32 | <_Parameter1>Microsoft Corporation
33 |
34 | <_BrandingInfo Include="System.Reflection.AssemblyCopyrightAttribute">
35 | <_Parameter1>Copyright (C) Microsoft Corporation. All rights reserved.
36 |
37 | <_BrandingInfo Include="System.Reflection.AssemblyProductAttribute">
38 | <_Parameter1>Visual Studio
39 |
40 | <_BrandingInfo Include="System.Resources.NeutralResourcesLanguageAttribute">
41 | <_Parameter1>en
42 |
43 | <_BrandingInfo Include="System.Reflection.AssemblyVersionAttribute">
44 | <_Parameter1>$(MajorVersion).$(MinorVersion).0.0
45 |
46 | <_BrandingInfo Include="System.Reflection.AssemblyFileVersionAttribute">
47 | <_Parameter1>$(MajorVersion).$(MinorVersion).$(BuildVersion).$(RevisionNumber)
48 |
49 |
50 | <_BrandingInfo Include="System.Reflection.AssemblyInformationalVersionAttribute">
51 | <_Parameter1 Condition="'$(ReleaseToken)' == 'rtm'">$(MajorVersion).$(MinorVersion).$(BuildVersion)
52 | <_Parameter1 Condition="'$(ReleaseToken)' != 'rtm'">$(MajorVersion).$(MinorVersion).$(BuildVersion)-$(ReleaseToken)-$(RevisionNumber)
53 |
54 |
55 |
56 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/lib/Common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | Microsoft.VisualStudio.Setup
7 | true
8 |
9 |
10 | $([System.IO.Path]::GetFullPath("$(MSBuildThisFileDirectory).."))
11 | $(SolutionDir)\
12 | $(SolutionDir)bin\$(Configuration)
13 | $(OutDir)\
14 | $(OutDir)
15 | $(OutDir.Trim('\\'))
16 | $(SolutionDir)src
17 |
18 |
19 |
20 | true
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/Common.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/Common.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib/Common.vcxproj.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <_FilesToSign Include="$(TargetPath)" Condition="'$(SignOutput)'!='false'" />
7 | <_FilesToSign Include="$(AdditionalFilesToSign)" />
8 |
9 | Microsoft
10 |
11 |
12 |
13 |
14 |
15 |
16 | $(SolutionDir)obj\$(Configuration)\BrandingInfo.h
17 |
18 | WriteBrandingInfo;
19 | $(BuildDependsOn);
20 |
21 |
22 |
23 |
24 | Branding.rc
25 |
26 |
27 |
28 |
29 | $(SolutionDir)lib;$(SolutionDir)obj\$(Configuration);%(AdditionalIncludeDirectories)
30 |
31 |
32 | $(SolutionDir)lib;$(SolutionDir)obj\$(Configuration);%(AdditionalIncludeDirectories)
33 |
34 |
35 |
36 |
41 |
42 | <_BrandingInfoFile Include="$(BrandingInfoFile)"/>
43 |
44 |
45 | <_BrandingInfo Include="
46 | // auto-generated
47 | #ifndef _BRANDINGINFO_H_
48 | #define _BRANDINGINFO_H_
49 |
50 | #define MAJOR_VERSION $(MajorVersion)
51 | #define MINOR_VERSION $(MinorVersion)
52 | #define BUILD_VERSION $(BuildVersion)
53 | #define REVISION_NUMBER $(RevisionNumber)
54 | " />
55 | <_BrandingInfo Condition="'$(ReleaseToken)' != 'rtm'" Include="
56 | #define vwzProductVersion "$(MajorVersion).$(MinorVersion).$(BuildVersion)-$(ReleaseToken)-$(RevisionNumber)"
57 | " />
58 | <_BrandingInfo Condition="'$(ReleaseToken)' == 'rtm'" Include="
59 | #define vwzProductVersion "$(MajorVersion).$(MinorVersion).$(BuildVersion)"
60 | " />
61 | <_BrandingInfo Include="
62 | #endif // _BRANDINGINFO_H_
63 | " />
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Visual Studio Uninstaller
2 | Copyright (c) Microsoft Corporation
3 | All rights reserved.
4 | MIT License
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/CommandOption.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VS.ConfigurationManager.Support;
3 | using System.Globalization;
4 |
5 | namespace Microsoft.VS.Uninstaller
6 | {
7 | ///
8 | /// Option class to describe name-value pairs.
9 | ///
10 | public class CommandOption
11 | {
12 | private static readonly string AppName = "CommandOption";
13 | ///
14 | /// This is a descriptor of a command that can be run via a console application.
15 | ///
16 | public string Command { get; set; }
17 | ///
18 | /// This is a description showed to the user of what the command does.
19 | ///
20 | public string Description { get; set; }
21 | ///
22 | /// What value should we try to check for comparison?
23 | ///
24 | public string CommandCompareValue { get; set; }
25 | ///
26 | /// What is the value of the parameter
27 | ///
28 | public string Value { get; set; }
29 | ///
30 | /// Creating a new option takes the 4 properties values as parameters
31 | ///
32 | ///
33 | ///
34 | ///
35 | ///
36 | public CommandOption(string command, string description, string commandcomparevalue, string value)
37 | {
38 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Creating option: Command: {0}, Description: {1}, Keyword: {2}, Comparison value: {3}", command, description, commandcomparevalue, value), Logger.MessageLevel.Verbose, AppName);
39 | Command = command;
40 | Description = description;
41 | CommandCompareValue = commandcomparevalue;
42 | Value = value;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/ConsoleOperations.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager;
2 | using Microsoft.VS.ConfigurationManager.Support;
3 | using System;
4 | using System.Globalization;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.IO;
9 |
10 | namespace Microsoft.VS.Uninstaller
11 | {
12 | static internal class ConsoleOperations
13 | {
14 | private const string _explorer = "Explorer.exe";
15 | private const int _width = 85;
16 | private const int _height = 45;
17 |
18 | public static List Options = new List();
19 |
20 | private static string line = new StringBuilder().Append('-', 85).ToString();
21 | private static string path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "DataFiles");
22 | public const string AppName = "ConsoleOperations";
23 | public const string COMMAND_COMPARE_DIRECTORY = "DIR";
24 | public const string COMMAND_COMPARE_LIST = "LIST";
25 | public const string COMMAND_COMPARE_CREATE = "CREATE";
26 | public const string COMMAND_COMPARE_LOAD = "LOAD";
27 | public const string COMMAND_COMPARE_SELECT = "SELECT";
28 | public const string COMMAND_COMPARE_INSTALLED = "INSTALLED";
29 | public const string COMMAND_COMPARE_VSINSTALLED = "VSINSTALLED";
30 | public const string COMMAND_COMPARE_UNINSTALL = "UNINSTALL";
31 | public const string COMMAND_COMPARE_MSIS = "MSIS";
32 | public const string COMMAND_COMPARE_TEMP = "TEMP";
33 | public const string COMMAND_COMPARE_LOGSELECTED = "LOG";
34 |
35 | internal static Primitives PrimitiveObject { get; set; }
36 |
37 | static internal string MsgRelease { get; set; }
38 |
39 | static internal void SecurityWarning()
40 | {
41 | Console.WriteLine(Logger.Log("Not running as elevated or administrator.", Logger.MessageLevel.Information, AppName));
42 | Console.ForegroundColor = ConsoleColor.Red;
43 | Console.WriteLine(Logger.Log("Possible error condition found.", Logger.MessageLevel.Information, AppName));
44 | Console.ResetColor();
45 | Console.WriteLine(Logger.Log("If you are not running with elevated permissions, the uninstall processes can result in errors. For optimal results, please run command console as administrator.", Logger.MessageLevel.Information, AppName));
46 | Console.ForegroundColor = ConsoleColor.White;
47 | Console.WriteLine("\r\nPress enter to continue.");
48 | Console.ResetColor();
49 | Console.ReadLine();
50 | }
51 |
52 | static internal void SetConsoleAttributes()
53 | {
54 | Console.WindowHeight = Console.LargestWindowHeight < _height ? Console.LargestWindowHeight : _height;
55 | Console.WindowWidth = _width;
56 | Console.Title = "WixPdb sourced uninstall driver";
57 | }
58 |
59 | static internal void OpenTempDirectory()
60 | {
61 | Console.WriteLine(Logger.Log("Opening temp directory", Logger.MessageLevel.Verbose, AppName));
62 | Utility.ExecuteProcess(_explorer, Utility.TempDir);
63 | }
64 |
65 | static internal void SetUpLogging()
66 | {
67 | var time = DateTime.Now.ToString("MM-dd-yy-hhmmss", CultureInfo.InvariantCulture);
68 | var logfilepath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "dd_Microsoft.VS.Uninstaller_" + System.IO.Path.ChangeExtension(time, "log"));
69 | Logger.LogLocation = logfilepath;
70 | Logger.LoggingLevel = Logger.MessageLevel.Verbose;
71 | Logger.ConsoleOutput = true;
72 | }
73 |
74 | static internal void GetUsage()
75 | {
76 |
77 | var sb = new StringBuilder();
78 |
79 | sb.AppendLine("Please use the key words to execute a command.\r\n");
80 | sb.AppendLine("Command".PadRight(30) + "Key words".PadRight(15) + "Description".PadRight(40));
81 | sb.AppendLine(line);
82 |
83 | Console.ForegroundColor = ConsoleColor.White;
84 | Console.WriteLine(sb.ToString());
85 | Console.ResetColor();
86 |
87 | foreach (CommandOption op in GetOptions())
88 | {
89 | sb = new StringBuilder();
90 | sb.Append(op.Command.PadRight(30));
91 | sb.Append(op.CommandCompareValue.PadRight(15));
92 | Console.ForegroundColor = ConsoleColor.White;
93 | Console.Write(sb.ToString());
94 | Console.ResetColor();
95 | FormatOutput(op.Description, 30, 45);
96 | }
97 | Console.ForegroundColor = ConsoleColor.White;
98 | sb = new StringBuilder();
99 |
100 | sb.AppendLine();
101 | sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "Working directory: {0}", PrimitiveObject.DataFilesPath));
102 | sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "Debug: {0}", PrimitiveObject.DebugReporting.ToString()));
103 | sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "Do Not Process: {0}", PrimitiveObject.DoNotExecuteProcess.ToString()));
104 | sb.AppendLine();
105 | sb.AppendLine("Enter in a key word to run the next command or 'quit' to exit");
106 | sb.AppendLine();
107 | sb.Append("> ");
108 | Console.Write(sb.ToString());
109 | sb = null;
110 | }
111 |
112 | private static ICollection GetOptions()
113 | {
114 | if (Options.FirstOrDefault() == null)
115 | {
116 | Options.Add(new CommandOption("Directory", "Identifies which directory files are loaded from and saved to. This has no impact on the Content directory where the WixPdbs go.", COMMAND_COMPARE_DIRECTORY, null));
117 | Options.Add(new CommandOption("List", "Lists all the bundles that the application is aware of.", COMMAND_COMPARE_LIST, null));
118 | Options.Add(new CommandOption("Create config files", "Creates configuration files from wixpdbs.", COMMAND_COMPARE_CREATE, null));
119 | Options.Add(new CommandOption("Load config files", "Loads configuration files from disk", COMMAND_COMPARE_LOAD, null));
120 | Options.Add(new CommandOption("Select", "Allows you to choose which bundle(s) to uninstall", COMMAND_COMPARE_SELECT, null));
121 | Options.Add(new CommandOption("Show what is installed", "Shows what is currently installed on this machine.", COMMAND_COMPARE_INSTALLED, null));
122 | Options.Add(new CommandOption("Show what VS installs what", "Shows of the things that are installed, which ones are installed by Visual Studio", COMMAND_COMPARE_VSINSTALLED, null));
123 | Options.Add(new CommandOption("Uninstall", "Triggers an uninstall of the selected bundle(s)", COMMAND_COMPARE_UNINSTALL, null));
124 | Options.Add(new CommandOption("Uninstall MSIs", "Used after uninstalling the selected bundle(s) to remove any loose MSIs left behind.", COMMAND_COMPARE_MSIS, null));
125 | Options.Add(new CommandOption("Open temp dir", "Opens the temporary directory where logs are stored.", COMMAND_COMPARE_TEMP, null));
126 | }
127 | return Options;
128 | }
129 |
130 | private static void FormatOutput(string textselection, int pos, int startpad)
131 | {
132 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Formatting output: {0}", textselection), Logger.MessageLevel.Verbose, AppName);
133 | if (textselection.Length > pos && textselection.IndexOf(' ', pos) != -1)
134 | {
135 | var space = textselection.IndexOf(' ', pos);
136 |
137 | Console.WriteLine(textselection.Substring(0, space).PadLeft(pos));
138 |
139 | while (textselection.Length >= pos && textselection.IndexOf(' ', pos) != -1)
140 | {
141 | textselection = textselection.Length >= pos ? textselection.Substring(space, textselection.Length - space).Trim() : textselection;
142 | space = textselection.IndexOf(' ', pos >= textselection.Length ? textselection.Length : pos);
143 | Console.WriteLine(" ".PadLeft(startpad) + textselection.Substring(0, space == -1 ? textselection.Length : space));
144 | }
145 | }
146 | else
147 | {
148 | Console.WriteLine(textselection);
149 | }
150 | Logger.Log("Formatting output ended", Logger.MessageLevel.Verbose, AppName);
151 | }
152 |
153 |
154 | static internal void ChangeWorkingDirectory(string[] cmdset)
155 | {
156 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Change working directory command started."), Logger.MessageLevel.Verbose, AppName);
157 | var dir = cmdset[1].Replace(COMMAND_COMPARE_DIRECTORY, "");
158 |
159 | PrimitiveObject.DataFilesPath = (String.IsNullOrEmpty(dir)) ? PrimitiveObject.DataFilesPath : dir;
160 | var di = new DirectoryInfo(dir);
161 |
162 | if (!di.Exists) { di.Create(); }
163 |
164 | PrimitiveObject.DataFilesPath = dir;
165 |
166 | Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "Working directory has been reset to {0}", PrimitiveObject.DataFilesPath));
167 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Change working directory: {0}", PrimitiveObject.DataFilesPath), Logger.MessageLevel.Information, AppName);
168 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Change working directory command ended."), Logger.MessageLevel.Verbose, AppName);
169 | }
170 |
171 | static internal void SetupPrimitivesValues(bool debug, bool donotprocess)
172 | {
173 | // uti.bDebug = op.Debug; ip.DebugReporting = op.Debug;
174 | PrimitiveObject.MachineArchitectureConfiguration = SystemSettings.Is64() ? ArchitectureConfiguration.x64 : ArchitectureConfiguration.x86;
175 | PrimitiveObject.MachineOSVersion = SystemSettings.Version();
176 |
177 | PrimitiveObject.Filters.Clear();
178 | PrimitiveObject.UninstallActions.Clear();
179 |
180 | VisualStudioSpecific.VSFilters(PrimitiveObject);
181 | VisualStudioSpecific.VSUninstallActions(PrimitiveObject);
182 |
183 | PrimitiveObject.DataFilesPath = path;
184 | PrimitiveObject.DoNotExecuteProcess = donotprocess;
185 | PrimitiveObject.DebugReporting = debug;
186 |
187 | //Initialize
188 | PrimitiveObject.Initialize();
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/DataFile.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/src/Uninstall_Wrapper/DataFile.bin
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager;
2 | using Microsoft.VS.ConfigurationManager.Support;
3 | using Microsoft.Win32;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Globalization;
8 | using System.IO;
9 | using System.Linq;
10 | using System.Reflection;
11 | using System.Text;
12 |
13 | namespace Microsoft.VS.Uninstaller
14 | {
15 | internal class Program
16 | {
17 | private const string _explorer = "Explorer.exe";
18 | private const string AppName = "Console Application";
19 |
20 | private static bool _debug;
21 | private static bool _donotprocess;
22 |
23 | #region Private Methods
24 |
25 | private static int Main(string[] args)
26 | {
27 | string wixpdbsPathsFile = string.Empty;
28 | string[] wixpdbsPaths = null;
29 | string dataFilePath = string.Empty;
30 | //args = new string[] { "noprocess", @"/wixpdbs:C:\Users\user\Desktop\test\paths.txt" };
31 | //args = new string[] { "noprocess", @"/binfile:C:\Users\user\Desktop\test\DataFile.bin" };
32 | //args = new string[] { "noprocess", @"/binfile:C:\Users\user\Desktop\test\DataFile.bin", @"/wixpdbs:\\myshare\Drops\user\wixpdbsPS\sub\Files.txt" };
33 | if (args != null && args.Count() > 0)
34 | {
35 | foreach (var arg in args)
36 | {
37 | switch(arg.ToLowerInvariant())
38 | {
39 | case "help":
40 | case "/help":
41 | case "/?":
42 | PrintUsage();
43 | return 0;
44 | case "break":
45 | Console.WriteLine("Program stopped, please attach debugger and then hit any key to continue.");
46 | Console.ReadKey(true);
47 | break;
48 | case "debug":
49 | _debug = true;
50 | break;
51 | case "noprocess":
52 | _donotprocess = true;
53 | break;
54 | default:
55 | // Path to the file containing a list of paths to the wixpdbs.
56 | // e.g. /wixpdbs:c:\myPaths.txt
57 | if (arg.StartsWith("/wixpdbs:", StringComparison.OrdinalIgnoreCase))
58 | {
59 | wixpdbsPathsFile = arg.Substring("/wixpdbs:".Length);
60 | wixpdbsPaths = File.ReadAllLines(wixpdbsPathsFile);
61 | }
62 | // Path to the file containing the DataFile.bin; if no file is passed in, it will use the embedded one.
63 | // e.g. /binfile:C:\DataFile.bin
64 | else if (arg.StartsWith("/binfile:", StringComparison.OrdinalIgnoreCase))
65 | {
66 | dataFilePath = arg.Substring("/binfile:".Length);
67 | }
68 | break;
69 | }
70 | }
71 | }
72 |
73 | var ip = new Primitives();
74 |
75 | ConsoleOperations.PrimitiveObject = ip;
76 | ConsoleOperations.SetUpLogging();
77 |
78 | ip.DoNotExecuteProcess = _donotprocess;
79 | ip.DebugReporting = _debug;
80 |
81 | try
82 | {
83 | // Check for permissions to run uninstall actions
84 | var elev = new ElevationDetection();
85 | if (!elev.Level)
86 | {
87 | ConsoleOperations.SecurityWarning();
88 | return 0;
89 | }
90 | else
91 | {
92 | Logger.Log("Running elevated or as administrator", Logger.MessageLevel.Information, AppName);
93 | }
94 | elev = null;
95 |
96 | // Define base variables for use of primitives object; adding filters, uninstall actions, logging location, and default location of data files
97 | ConsoleOperations.SetupPrimitivesValues(_debug, _donotprocess);
98 |
99 | // If /wixpdbs is used, .bin data file is generated for the user.
100 | if (wixpdbsPaths != null && wixpdbsPaths.Length > 0)
101 | {
102 | if (!string.IsNullOrEmpty(dataFilePath) && File.Exists(dataFilePath))
103 | {
104 | Logger.LogWithOutput(string.Format("Loading from {0}", dataFilePath));
105 | ip.LoadFromDataFile(dataFilePath);
106 | }
107 |
108 | Logger.LogWithOutput("Generating data file from wixpdbs ....");
109 | foreach (var wixpdbPath in wixpdbsPaths)
110 | {
111 | ip.LoadFromWixpdb(wixpdbPath);
112 | }
113 |
114 | ip.SaveToDataFile();
115 | Logger.Log("Data File generation operation is successful. Exiting ...", Logger.MessageLevel.Information, AppName);
116 | return 0;
117 | }
118 | // Else uninstall Visual Studio 2013/2015/vNext
119 | else
120 | {
121 | if (!string.IsNullOrEmpty(dataFilePath) && File.Exists(dataFilePath))
122 | {
123 | ip.LoadFromDataFile(dataFilePath);
124 | }
125 | else
126 | {
127 | // load from embedded.
128 | var assembly = Assembly.GetExecutingAssembly();
129 | var dataFile = "Microsoft.VisualStudio.Setup.DataFile.bin";
130 |
131 | using (Stream stream = assembly.GetManifestResourceStream(dataFile))
132 | {
133 | ip.LoadFromDataFile(stream);
134 | }
135 | }
136 |
137 | ip.InstalledVisualStudioReport();
138 | Logger.LogWithOutput("WARNING: This executable is designed to cleanup/scorch all Preview/RC/RTM releases of Visual Studio 2013, Visual Studio 2015 and Visual Studio vNext.");
139 | Logger.LogWithOutput("It should be used as the last resort to clean up the user's system before resorting to reimaging the machine. ");
140 | Logger.LogWithOutput("Would you like to continue? [Y/N]");
141 | var action = Console.ReadLine();
142 | if (!string.IsNullOrEmpty(action) && action.StartsWith("y", StringComparison.OrdinalIgnoreCase))
143 | {
144 | // cache the vs dirs in memory before uninstalling.
145 | var vsDirs = GetVisualStudioInstallationDirs();
146 |
147 | int exitCode = ip.Uninstall();
148 |
149 | if (exitCode == 3010)
150 | {
151 | Logger.LogWithOutput("Bundle requested to reboot the system. Please reboot your computer and run this application again.");
152 | return 3010;
153 | }
154 | ip.CleanupVisualStudioFolders(vsDirs);
155 | ip.CleanupSecondaryInstallerCache();
156 | ip.CleanupVisualStudioRegistryHives();
157 | }
158 | else
159 | {
160 | Logger.LogWithOutput("Exiting ...");
161 | }
162 | }
163 | }
164 | catch (Exception ex)
165 | {
166 | Logger.Log(ex, AppName);
167 | }
168 | finally
169 | {
170 | ip.Dispose();
171 | }
172 |
173 | return 0;
174 | }
175 |
176 | private static IEnumerable GetVisualStudioInstallationDirs()
177 | {
178 | List vsDirs = new List();
179 |
180 | var vsVers = new string[] { "12.0", "14.0", "15.0" };
181 |
182 | // %AppData%\Microsoft\VisualStudio\14.0 & 12.0 & 15.0
183 | // %LocalAppData%\Microsoft\VisualStudio\14.0 & 12.0 & 15.0
184 | // %LocalAppData%\Microsoft\VSCommon\14.0 & 12.0 & 15.0
185 | var appDataRoot = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
186 | var localAppDataRoot = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
187 |
188 | foreach (var vsVer in vsVers)
189 | {
190 | if (Environment.Is64BitOperatingSystem)
191 | {
192 | var installDir = (string)Registry.GetValue(
193 | string.Format("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\{0}\\", vsVer),
194 | "ShellFolder",
195 | null);
196 | if (!string.IsNullOrEmpty(installDir))
197 | {
198 | vsDirs.Add(installDir);
199 | }
200 | }
201 | else
202 | {
203 | var installDir = (string)Registry.GetValue(
204 | string.Format("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\{0}\\", vsVer),
205 | "ShellFolder",
206 | null);
207 | if (!string.IsNullOrEmpty(installDir))
208 | {
209 | vsDirs.Add(installDir);
210 | }
211 | }
212 |
213 | vsDirs.Add(Path.Combine(appDataRoot, "Microsoft", "VisualStudio", vsVer));
214 | vsDirs.Add(Path.Combine(localAppDataRoot, "Microsoft", "VisualStudio", vsVer));
215 | vsDirs.Add(Path.Combine(localAppDataRoot, "Microsoft", "VSCommon", vsVer));
216 | }
217 |
218 | return vsDirs;
219 | }
220 |
221 | private static void PrintUsage()
222 | {
223 | Console.WriteLine("Welcome to Total Uninstaller.");
224 | Console.WriteLine("Running this application will remove Visual Studio 2013/2015/vNext completely.");
225 | Console.WriteLine("It should be used as the last resort to clean up your machine.");
226 | Console.WriteLine("----------- Normal Usage --------------");
227 | Console.WriteLine("Please run this application as administrator without any parameter.");
228 | }
229 |
230 | #endregion Private Methods
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/TotalUninstaller EULA.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/src/Uninstall_Wrapper/TotalUninstaller EULA.docx
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/Uninstall_Wrapper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | app.manifest
7 | {1E70C6F2-8570-4620-822E-E3F71BF1A0F7}
8 | publish\
9 | true
10 | Disk
11 | false
12 | Foreground
13 | 7
14 | Days
15 | false
16 | false
17 | true
18 | 0
19 | 1.0.0.%2a
20 | false
21 | false
22 | true
23 | v4.0
24 |
25 |
26 |
27 |
28 |
29 | Microsoft.VS.Uninstaller.Program
30 |
31 |
32 | TRACE;DEBUG;DOTNETFRAMEWORK35
33 | ManagedMinimumRules.ruleset
34 | false
35 | false
36 |
37 |
38 | Setup.ForcedUninstall
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Always
60 |
61 |
62 |
63 | Always
64 |
65 |
66 |
67 |
68 | False
69 | .NET Framework 3.5 SP1
70 | true
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Microsoft
79 |
80 |
81 |
82 |
83 | {13c73873-a5ed-42de-97f0-a3b2d7a1d76f}
84 | VS.ConfigurationManager.Support
85 |
86 |
87 | {caccc6e1-fcb8-4dbe-9159-0f8eaa69d27a}
88 | VS.ConfigurationManager
89 |
90 |
91 |
92 |
93 |
94 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/VisualStudioSpecifc.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager;
2 | using Microsoft.VS.ConfigurationManager.Support;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace Microsoft.VS.Uninstaller
7 | {
8 | internal static class VisualStudioSpecific
9 | {
10 | internal static void VSFilters(Primitives ip)
11 | {
12 | ip.Filters.Add(Filter.CreateFilter("Replace Visual Studio with shorter version", "Microsoft Visual Studio ", "VS "));
13 | ip.Filters.Add(Filter.CreateFilter("Shorten Microsoft", "Microsoft ", "MS "));
14 | ip.Filters.Add(Filter.CreateFilter("Shorten Team Foundation Server", "Team Foundation Server ", "TFS "));
15 | ip.Filters.Add(Filter.CreateFilter("Shorten Visual C++", "Visual C++ ", "VC "));
16 | }
17 |
18 | internal static void VSUninstallActions(Primitives ip)
19 | {
20 |
21 | ip.UninstallActions.Add(
22 | UninstallAction.CreateUninstallAction(
23 | new List { ArchitectureConfiguration.x86, ArchitectureConfiguration.x64 },
24 | new List { OperatingSystemConfiguration.Windows81 },
25 | "2999226",
26 | UninstallAction.TemplateType.Pre,
27 | UninstallAction.WixObjectType.MSU
28 | )
29 | );
30 | ip.UninstallActions.Add(
31 | UninstallAction.CreateUninstallAction(
32 | new List { ArchitectureConfiguration.x86, ArchitectureConfiguration.x64 },
33 | new List { OperatingSystemConfiguration.Windows8 },
34 | "2999226",
35 | UninstallAction.TemplateType.Pre,
36 | UninstallAction.WixObjectType.MSU
37 | )
38 | );
39 |
40 | ip.UninstallActions.Add(
41 | UninstallAction.CreateUninstallAction(
42 | new List { ArchitectureConfiguration.x86, ArchitectureConfiguration.x64 },
43 | new List { OperatingSystemConfiguration.Windows7 },
44 | "2999226",
45 | UninstallAction.TemplateType.Pre,
46 | UninstallAction.WixObjectType.MSU
47 | )
48 | );
49 |
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
51 |
58 |
59 |
60 |
73 |
74 |
--------------------------------------------------------------------------------
/src/Uninstall_Wrapper/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/ArchitectureConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Microsoft.VS.ConfigurationManager.Support
7 | {
8 | ///
9 | /// Defining an architecture as x86 or 64-bit
10 | ///
11 | public class ArchitectureConfiguration
12 | {
13 | ///
14 | /// Setting the property value
15 | ///
16 | ///
17 | public ArchitectureConfiguration(string value) { Value = value; }
18 | ///
19 | /// Property for holding value
20 | ///
21 | public string Value { get; set; }
22 |
23 | private static readonly List _archlist = new List();
24 | ///
25 | /// 64-bit property for use in the UninstallAction class
26 | ///
27 | public static ArchitectureConfiguration x64 { get { return new ArchitectureConfiguration("x64"); } }
28 | ///
29 | /// 32-bit property for use in the UninstallAction class
30 | ///
31 | public static ArchitectureConfiguration x86 { get { return new ArchitectureConfiguration("x86"); } }
32 | ///
33 | /// Generating a list of Architectures supported.
34 | ///
35 | public static ICollection Architectures()
36 | {
37 | Logger.Log("Creating list of architectures", Logger.MessageLevel.Information, "ArchitectureConfiguration");
38 | if (_archlist == null)
39 | {
40 | _archlist.Add(x64);
41 | _archlist.Add(x86);
42 | }
43 | return _archlist;
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/ConfigurationManagerException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace Microsoft.VS.ConfigurationManager.Support
5 | {
6 | ///
7 | /// Custom exceptions derived from base class
8 | ///
9 | [Serializable()]
10 | public class ConfigurationManagerException : Exception, ISerializable
11 | {
12 | ///
13 | /// Default constructor for exception
14 | ///
15 | public ConfigurationManagerException() { }
16 | ///
17 | /// Constructor with message only
18 | ///
19 | ///
20 | public ConfigurationManagerException(string message) : base(message) { }
21 | ///
22 | /// Constructor with message and inner exception
23 | ///
24 | ///
25 | ///
26 | public ConfigurationManagerException(string message, Exception inner) : base(message, inner) { }
27 | ///
28 | /// Protected constructor for exception
29 | ///
30 | ///
31 | ///
32 | protected ConfigurationManagerException(SerializationInfo info, StreamingContext context) : base(info, context) { }
33 | }
34 |
35 | ///
36 | /// Exception to let user know that a reboot is required.
37 | ///
38 | [Serializable()]
39 | public class RebootRequiredException : ConfigurationManagerException
40 | {
41 | ///
42 | /// Default constructor for exception
43 | ///
44 | public RebootRequiredException() { }
45 | ///
46 | /// Constructor with message only
47 | ///
48 | ///
49 | public RebootRequiredException(string message) : base(message) { }
50 | ///
51 | /// Constructor with message and inner exception
52 | ///
53 | ///
54 | ///
55 | public RebootRequiredException(string message, Exception inner) : base(message, inner) { }
56 | ///
57 | /// Protected constructor for exception
58 | ///
59 | ///
60 | ///
61 | protected RebootRequiredException(SerializationInfo info, StreamingContext context) : base(info, context) { }
62 | }
63 |
64 | ///
65 | /// Exception when WixPdbs are unavailable and configuration files are unavailable.
66 | ///
67 | [Serializable()]
68 | public class NoSourceFilesAvailableForParsingException : ConfigurationManagerException
69 | {
70 | ///
71 | /// Default constructor for exception
72 | ///
73 | public NoSourceFilesAvailableForParsingException() { }
74 | ///
75 | /// Constructor with message only
76 | ///
77 | ///
78 | public NoSourceFilesAvailableForParsingException(string message) : base(message) { }
79 | ///
80 | /// Constructor with message and inner exception
81 | ///
82 | ///
83 | ///
84 | public NoSourceFilesAvailableForParsingException(string message, Exception inner) : base(message, inner) { }
85 | ///
86 | /// Protected constructor for exception
87 | ///
88 | ///
89 | ///
90 | protected NoSourceFilesAvailableForParsingException(SerializationInfo info, StreamingContext context) : base(info, context) { }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/ElevationDetection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Principal;
3 | using System.Threading;
4 |
5 | namespace Microsoft.VS.ConfigurationManager.Support
6 | {
7 | ///
8 | /// Class to determine if a user has run the application with administrative priviledges.
9 | ///
10 | public class ElevationDetection
11 | {
12 | private const string AppName = "ElevationDetection";
13 | #region Constructor:
14 | ///
15 | /// Constructor that sets whether permission is available to read the registry and uninstall.
16 | ///
17 | public ElevationDetection()
18 | {
19 | // Invoke Method On Creation:
20 | Elevate();
21 | }
22 |
23 | #endregion Constructor:
24 | ///
25 | /// Property that defines a user has permission.
26 | ///
27 | public bool Level { get; set; }
28 |
29 | private void Elevate()
30 | {
31 | try
32 | {
33 | Logger.Log("Identifying if elevation has been provided", Logger.MessageLevel.Information, AppName);
34 | // Was this thread started with admin priviledges?
35 | var domain = Thread.GetDomain();
36 |
37 | domain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
38 | var role = (WindowsPrincipal)Thread.CurrentPrincipal;
39 |
40 | if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6)
41 | {
42 | Logger.Log("Lower OS found (< 6.0 revision or not Win32 NT)", Logger.MessageLevel.Information, AppName);
43 | Level = false;
44 | // Todo: Exception/ Exception Log
45 | }
46 | else
47 | {
48 | if (!role.IsInRole(WindowsBuiltInRole.Administrator))
49 | {
50 | Logger.Log("Not part of the Administrator role", Logger.MessageLevel.Information, AppName);
51 | Level = false;
52 | // Todo: "Exception Log / Exception"
53 | }
54 | else
55 | {
56 | Logger.Log("Part of the Administrator role", Logger.MessageLevel.Information, AppName);
57 | Level = true;
58 | }
59 | } // Initial Else 'Close'
60 | }
61 | catch (Exception ex)
62 | {
63 | Logger.Log(ex, AppName);
64 | Level = false;
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Globalization;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace Microsoft.VS.ConfigurationManager.Support
8 | {
9 | /// All logging capabilites for class run through these trace listeners
10 | public static class Logger
11 | {
12 | private const string displayName = "VS.ConfigurationManager";
13 | private const string _warning = "Warning";
14 | private const string _error = "ERROR";
15 | private const string _info = "Info";
16 | private static readonly object _syncObject = new object();
17 | private static string _logLocation = String.Empty;
18 | private static string _ThisAssembly = String.Empty;
19 |
20 | /// Defining event types that can be written out.
21 | public enum MessageLevel
22 | {
23 | /// No value provided and default to writing errors out
24 | None = 0,
25 |
26 | /// Write an error message
27 | Error = 1,
28 |
29 | /// Write a warning message
30 | Warning = 2,
31 |
32 | /// Write informational message
33 | Information = 3,
34 |
35 | /// Write a verbose message
36 | Verbose = 4
37 | }
38 |
39 | ///
40 | /// Setting debug property to do verbose logging or generating warnings only.
41 | ///
42 | public static bool Debug { get; set; }
43 |
44 | ///
45 | /// Define what level of logging should be done
46 | ///
47 | public static MessageLevel LoggingLevel { get; set; }
48 |
49 | /// Log location used for this instance of the object
50 | public static string LogLocation
51 | {
52 | get
53 | {
54 | return _logLocation;
55 | }
56 | set
57 | {
58 | // If LogLocation is not set and a location has been passed in, then use the temp directory.
59 | _logLocation = String.IsNullOrEmpty(value) ? System.IO.Path.GetTempPath() : value;
60 |
61 | // Add a unique filename if a file name is not already in place
62 | _logLocation = _logLocation.ToUpperInvariant().Contains(".LOG") ? _logLocation :
63 | System.IO.Path.ChangeExtension
64 | (
65 | System.IO.Path.Combine
66 | (
67 | _logLocation, "ApplicationLog-" + DateTime.Now.ToString("MM-dd-yy-hhmmss", CultureInfo.InvariantCulture)
68 | ), "log"
69 | );
70 |
71 | }
72 | }
73 |
74 | ///
75 | /// Property to force information to the console window
76 | ///
77 | public static bool ConsoleOutput { get; set; }
78 | #region Log Overloads
79 |
80 | ///
81 | /// With passed exceptions, information is written to log
82 | ///
83 | ///
84 | ///
85 | ///
86 | public static string Log(Exception ex, string sourcelocation)
87 | {
88 | return Log(String.Format(CultureInfo.InvariantCulture, "Caller: {0} Msg: {1}", GetCurrentMethod(new StackTrace(ex, true)), ex.Message), MessageLevel.Error, sourcelocation);
89 | }
90 |
91 | /// With passed exceptions, information is written to log
92 | ///
93 | public static string Log(Exception ex)
94 | {
95 | return Log(ex.Message, MessageLevel.Error, GetCurrentMethod(new StackTrace(ex, true)));
96 | }
97 |
98 | ///
99 | /// Logging source location as well as event level
100 | ///
101 | ///
102 | ///
103 | ///
104 | ///
105 | public static string Log(string logtext, MessageLevel eventlevel = MessageLevel.Information, string source = "Default")
106 | {
107 | // Ensure that stream writer is instantiated
108 | var consoleoutput = String.Empty;
109 | source = String.IsNullOrEmpty(source) ? "Default" : source;
110 |
111 | if (Debug || ConsoleOutput || eventlevel == MessageLevel.Error || eventlevel == MessageLevel.Warning)
112 | {
113 | consoleoutput = logtext;
114 | }
115 | try
116 | {
117 | switch (eventlevel)
118 | {
119 | case 0:
120 | break;
121 | case MessageLevel.Error:
122 | GenerateOutputMessage(logtext, MessageLevel.Error, source);
123 | break;
124 | case MessageLevel.Warning:
125 | GenerateOutputMessage(logtext, MessageLevel.Warning, source);
126 | break;
127 | case MessageLevel.Information:
128 | GenerateOutputMessage(logtext, MessageLevel.Information, source);
129 | break;
130 | case MessageLevel.Verbose:
131 | GenerateOutputMessage(logtext, MessageLevel.Verbose, source);
132 | break;
133 | }
134 | }
135 | catch(IOException ex) {
136 | System.Diagnostics.Debug.Write(String.Format(CultureInfo.InvariantCulture, "IO Exception hit: {0}", ex.Message));
137 | }
138 |
139 | return consoleoutput;
140 |
141 | }
142 |
143 | ///
144 | /// Logging source location as well as event level
145 | ///
146 | ///
147 | ///
148 | ///
149 | ///
150 | ///
151 | public static string LogWithOutput(string logtext, MessageLevel eventlevel = MessageLevel.Information, string source = "Default")
152 | {
153 | Console.WriteLine(logtext);
154 | return Log(logtext, eventlevel, source);
155 | }
156 |
157 | #endregion Log Overloads
158 |
159 | private static void GenerateOutputMessage(string logtext, MessageLevel prefix, string source)
160 | {
161 | switch (LoggingLevel >= prefix)
162 | {
163 | case true:
164 | var _sb = new StringBuilder();
165 | var logtimestamp = DateTime.Now.ToString("MM-dd-yyyy hh:mm:ss:sss.fff", CultureInfo.InvariantCulture);
166 | _sb.Append(logtimestamp.PadRight(30));
167 | _sb.Append(prefix.ToString().PadRight(30));
168 | _sb.Append(source.PadRight(40));
169 | _sb.Append(GetCurrentMethod(GetCaller()).PadRight(30));
170 | _sb.Append(logtext);
171 | lock (_syncObject)
172 | {
173 | using (StreamWriter sw = new StreamWriter(LogLocation, true)) { sw.WriteLine(_sb.ToString()); }
174 | }
175 | break;
176 | case false:
177 | break;
178 | }
179 | }
180 |
181 | private static StackFrame GetCaller()
182 | {
183 | // TODO: GetCaller frame is returning method names that do not appear to be correct in the log
184 |
185 | // Get our own, current namespace name.
186 | _ThisAssembly = String.IsNullOrEmpty(_ThisAssembly) ? new StackFrame(0).GetMethod().DeclaringType.ToString() : _ThisAssembly;
187 |
188 | // We’ll use this to walk the stack looking for a
189 | // method name that is not the same as our method
190 | // name—that is, the name of the method that called
191 | // this method name.
192 | var trace = new StackTrace(true);
193 |
194 | // Look for the first occurence of a stack frame that
195 | // contains a namespace name that is different from our
196 | // own.
197 | var i = 0;
198 | var frame = trace.GetFrame(i);
199 | while ((frame.GetMethod().DeclaringType.FullName.ToUpperInvariant() == _ThisAssembly.ToUpperInvariant()) && (i < trace.FrameCount))
200 | {
201 | i++;
202 | frame = trace.GetFrame(i);
203 | }
204 |
205 | return frame;
206 | }
207 |
208 | private static string GetCurrentMethod(StackFrame sf)
209 | {
210 | return sf.GetMethod().Name;
211 | }
212 |
213 | private static string GetCurrentMethod(StackTrace st = null)
214 | {
215 | return GetCurrentMethod(st.GetFrame(0));
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Microsoft.VS.ConfigurationManager.Support
5 | {
6 | internal static class NativeMethods
7 | {
8 | #region Read 64bit Reg from 32bit app
9 | [DllImport("Advapi32.dll")]
10 | internal static extern uint RegOpenKeyEx(
11 | UIntPtr hKey,
12 | string lpSubKey,
13 | uint ulOptions,
14 | int samDesired,
15 | out int phkResult);
16 |
17 | [DllImport("Advapi32.dll")]
18 | internal static extern uint RegCloseKey(int hKey);
19 |
20 | ///
21 | /// Importing call to allow reading under 3.5
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | ///
29 | ///
30 | [DllImport("advapi32.dll", EntryPoint = @"RegQueryValueEx")]
31 | internal static extern int RegQueryValueEx(
32 | int hKey, string lpValueName,
33 | int lpReserved,
34 | ref uint lpType,
35 | System.Text.StringBuilder lpData,
36 | ref uint lpcbData);
37 | #endregion
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/OperatingSystemConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Microsoft.VS.ConfigurationManager.Support
7 | {
8 | ///
9 | /// Listing of operating systems and their versions for use with UninstallAction
10 | ///
11 | public class OperatingSystemConfiguration : IEnumerable
12 | {
13 | private const string AppName = "OperatingSystemConfiguration";
14 | private static List _oslist = new List();
15 | ///
16 | /// Setting the value property
17 | ///
18 | ///
19 | public OperatingSystemConfiguration(string value) { Value = value; }
20 | ///
21 | /// The version number for the given instance.
22 | ///
23 | public string Value { get; set; }
24 | ///
25 | /// Windows 2000 version number
26 | ///
27 | public static OperatingSystemConfiguration Windows2000 { get { return new OperatingSystemConfiguration("5.0"); } }
28 | ///
29 | /// Windows XP version number
30 | ///
31 | public static OperatingSystemConfiguration WindowsXP { get { return new OperatingSystemConfiguration("5.1"); } }
32 | ///
33 | /// Windows XP 64-bit version number
34 | ///
35 | public static OperatingSystemConfiguration WindowsXP64Bit { get { return new OperatingSystemConfiguration("5.2"); } }
36 | ///
37 | /// Windows 2003 version number
38 | ///
39 | public static OperatingSystemConfiguration Windows2003 { get { return new OperatingSystemConfiguration("5.2"); } }
40 | ///
41 | /// Windows 2003R2 version number
42 | ///
43 | public static OperatingSystemConfiguration Windows2003R2 { get { return new OperatingSystemConfiguration("5.2"); } }
44 | ///
45 | /// Windows Vista version number
46 | ///
47 | public static OperatingSystemConfiguration WindowsVista { get { return new OperatingSystemConfiguration("6.0"); } }
48 | ///
49 | /// Windows Server 2008 version number
50 | ///
51 | public static OperatingSystemConfiguration WindowsServer2008 { get { return new OperatingSystemConfiguration("6.0"); } }
52 | ///
53 | /// Windows Server 2008R2 version number
54 | ///
55 | public static OperatingSystemConfiguration WindowsServer2008R2 { get { return new OperatingSystemConfiguration("6.1"); } }
56 | ///
57 | /// Windows 7 version number
58 | ///
59 | public static OperatingSystemConfiguration Windows7 { get { return new OperatingSystemConfiguration("6.1"); } }
60 | ///
61 | /// Windows Server 2012 version number
62 | ///
63 | public static OperatingSystemConfiguration WindowsServer2012 { get { return new OperatingSystemConfiguration("6.2"); } }
64 | ///
65 | /// Windows 8 version number
66 | ///
67 | public static OperatingSystemConfiguration Windows8 { get { return new OperatingSystemConfiguration("6.2"); } }
68 | ///
69 | /// Windows 8.1 version number
70 | ///
71 | public static OperatingSystemConfiguration Windows81 { get { return new OperatingSystemConfiguration("6.3"); } }
72 | ///
73 | /// Windows Server 2012R2 version number
74 | ///
75 | public static OperatingSystemConfiguration WindowsServer2012R2 { get { return new OperatingSystemConfiguration("6.3"); } }
76 | ///
77 | /// Windows 10 version number
78 | ///
79 | public static OperatingSystemConfiguration Windows10 { get { return new OperatingSystemConfiguration("10.0"); } }
80 | ///
81 | /// Windows Server Technical Preview version number
82 | ///
83 | public static OperatingSystemConfiguration WindowsServerTechnicalPreview { get { return new OperatingSystemConfiguration("10.0"); } }
84 |
85 | ///
86 | /// Overloaded function for generating a list of operating systems
87 | ///
88 | ///
89 | public static ICollection ToList()
90 | {
91 | Logger.Log("Creating list of OSes available for detection", Logger.MessageLevel.Information, AppName);
92 | if (_oslist.FirstOrDefault() == null)
93 | {
94 | _oslist.Add(Windows2000);
95 | _oslist.Add(WindowsXP);
96 | _oslist.Add(WindowsXP64Bit);
97 | _oslist.Add(Windows2003);
98 | _oslist.Add(Windows2003R2);
99 | _oslist.Add(WindowsVista);
100 | _oslist.Add(WindowsServer2008);
101 | _oslist.Add(WindowsServer2008R2);
102 | _oslist.Add(Windows7);
103 | _oslist.Add(WindowsServer2012);
104 | _oslist.Add(Windows8);
105 | _oslist.Add(Windows81);
106 | _oslist.Add(WindowsServer2012R2);
107 | _oslist.Add(Windows10);
108 | _oslist.Add(WindowsServerTechnicalPreview);
109 |
110 | }
111 | return _oslist;
112 | }
113 | ///
114 | /// Referencing list via index value
115 | ///
116 | ///
117 | ///
118 | public OperatingSystemConfiguration this[int index]
119 | {
120 | get { return this[index]; }
121 | set { _oslist.Insert(index, value); }
122 | }
123 |
124 | ///
125 | /// Send back list in context of collections
126 | ///
127 | ///
128 | public IEnumerator GetEnumerator()
129 | {
130 | return _oslist.GetEnumerator();
131 | }
132 |
133 | ///
134 | /// System.Collections.IEnumerator implementation
135 | ///
136 | ///
137 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
138 | {
139 | return this.GetEnumerator();
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/RegistryHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Text;
4 |
5 | namespace Microsoft.VS.ConfigurationManager.Support
6 | {
7 | ///
8 | /// SAM values for each set of commands and locations.
9 | ///
10 | public enum RegistrySAM
11 | {
12 | ///
13 | /// No value assigned
14 | ///
15 | None = 0x0000,
16 | ///
17 | /// Query verb
18 | ///
19 | QueryValue = 0x0001,
20 | ///
21 | /// Set verb
22 | ///
23 | SetValue = 0x0002,
24 | ///
25 | /// Create verb
26 | ///
27 | CreateSubKey = 0x0004,
28 | ///
29 | /// Enumerate verb
30 | ///
31 | EnumerateSubKeys = 0x0008,
32 | ///
33 | /// Notify verb
34 | ///
35 | Notify = 0x0010,
36 | ///
37 | /// Create link verb
38 | ///
39 | CreateLink = 0x0020,
40 | ///
41 | /// 32 bit registry location
42 | ///
43 | WOW64_32Key = 0x0200,
44 | ///
45 | /// 64 bit registry location
46 | ///
47 | WOW64_64Key = 0x0100,
48 | ///
49 | ///
50 | ///
51 | WOW64_Res = 0x0300,
52 | ///
53 | /// Read access permissions
54 | ///
55 | Read = 0x00020019,
56 | ///
57 | /// Write access permissions
58 | ///
59 | Write = 0x00020006,
60 | ///
61 | /// Execute access permissions
62 | ///
63 | Execute = 0x00020019,
64 | ///
65 | /// All access permissions
66 | ///
67 | AllAccess = 0x000f003f
68 | }
69 |
70 | ///
71 | /// Registry hive locations
72 | ///
73 | public static class RegHive
74 | {
75 | ///
76 | /// HKLM
77 | ///
78 | internal static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
79 | ///
80 | /// HKLU
81 | ///
82 | internal static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
83 | }
84 |
85 | ///
86 | /// Exposing class to read from the registry
87 | ///
88 | public static class RegistryHandler
89 | {
90 |
91 | private const string AppName = "RegistryHandler";
92 | #region Functions
93 | ///
94 | /// Reading from the 64 bit hive
95 | ///
96 | ///
97 | ///
98 | ///
99 | ///
100 | static public string GetRegistryKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
101 | {
102 | Logger.Log("Reading from 64 bit registry hive", Logger.MessageLevel.Verbose, AppName);
103 | return GetRegKey64(inHive, inKeyName, RegistrySAM.WOW64_64Key, inPropertyName);
104 | }
105 |
106 | ///
107 | /// Reading from the 32 bit hive
108 | ///
109 | ///
110 | ///
111 | ///
112 | ///
113 | static public string GetRegistryKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
114 | {
115 | Logger.Log("Reading from 32 bit registry hive", Logger.MessageLevel.Verbose, AppName);
116 | return GetRegKey64(inHive, inKeyName, RegistrySAM.WOW64_32Key, inPropertyName);
117 | }
118 |
119 | ///
120 | /// Get registry key call to imports
121 | ///
122 | ///
123 | ///
124 | ///
125 | ///
126 | ///
127 | static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegistrySAM in32or64key, String inPropertyName)
128 | {
129 | var hkey = 0;
130 | string Age;
131 | try
132 | {
133 | Logger.Log("Open registry handle", Logger.MessageLevel.Verbose, AppName);
134 | var lResult = NativeMethods.RegOpenKeyEx(inHive, inKeyName, 0, (int)RegistrySAM.QueryValue | (int)in32or64key, out hkey);
135 | if (0 != lResult) return null;
136 | uint lpType = 0;
137 | uint lpcbData = 1024;
138 | var AgeBuffer = new StringBuilder(1024);
139 | Logger.Log("Get value from registry", Logger.MessageLevel.Verbose, AppName);
140 | NativeMethods.RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
141 | Age = AgeBuffer.ToString();
142 | }
143 | finally
144 | {
145 | Logger.Log("Close registry handle", Logger.MessageLevel.Verbose, AppName);
146 | if (0 != hkey) NativeMethods.RegCloseKey(hkey);
147 | }
148 | return Age;
149 | }
150 | #endregion
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/Utility.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Security;
8 | using System.ServiceProcess;
9 |
10 | namespace Microsoft.VS.ConfigurationManager.Support
11 | {
12 | ///
13 | /// Functions and values to allow central logging and execution of processes
14 | ///
15 | public class Utility : IDisposable
16 | {
17 | private const string AppName = "Utility";
18 |
19 | ///
20 | /// Setting service state values
21 | ///
22 | public enum ServiceState
23 | {
24 | ///
25 | /// Do nothing
26 | ///
27 | None,
28 | ///
29 | /// Start the service
30 | ///
31 | Start,
32 | ///
33 | /// Stop the service
34 | ///
35 | Stop
36 | }
37 | /// Set properties as part of instantiation.
38 | public Utility()
39 | {
40 | Initialize();
41 | }
42 |
43 | private void Initialize() { }
44 |
45 | #region Public Methods
46 |
47 | ///
48 | /// Registry key reading function with call to native functions
49 | ///
50 | ///
51 | ///
52 | ///
53 | public static string ReadRegKey(string path, string findkey)
54 | {
55 | var value = string.Empty;
56 |
57 | try { value = RegistryHandler.GetRegistryKey32(RegHive.HKEY_LOCAL_MACHINE, path, findkey); }
58 | catch (Exception ex) {
59 | Logger.Log(ex, AppName);
60 | value = string.Empty;
61 | }
62 |
63 | return value;
64 | }
65 |
66 | #endregion Public Methods
67 |
68 | #region Internal Methods
69 |
70 |
71 | /// Launches a process and returns the error code. 0 is success.
72 | ///
73 | ///
74 | [SecurityCritical]
75 | public static int ExecuteProcess(string file, string args)
76 | {
77 | Logger.Log(String.Format(CultureInfo.InvariantCulture,"Creating process for {0} with arguments: {1}", file, args), Logger.MessageLevel.Information, AppName);
78 | var p = new Process();
79 | int exitcode = 1603;
80 | try
81 | {
82 | p.StartInfo.UseShellExecute = false;
83 | p.StartInfo.RedirectStandardOutput = true;
84 | p.StartInfo.FileName = file;
85 | p.StartInfo.Arguments = args;
86 | p.StartInfo.Verb = "runas";
87 | p.Start();
88 | p.WaitForExit();
89 | exitcode = p.ExitCode;
90 | }
91 | finally
92 | {
93 | p.Dispose();
94 | }
95 |
96 | return exitcode;
97 | }
98 |
99 | /// Stopping and starting services required to uninstall MSUs.
100 | ///
101 | ///
102 | ///
103 | public static bool ServiceAction(string ServiceName, ServiceState status)
104 | {
105 | var serviceaction = false;
106 |
107 | sc.ServiceName = ServiceName;
108 | var check = ServiceControllerStatus.Stopped;
109 | try
110 | {
111 | switch (status)
112 | {
113 | case ServiceState.Stop:
114 | check = ServiceControllerStatus.Stopped;
115 | sc.Stop();
116 | break;
117 |
118 | case ServiceState.Start:
119 | check = ServiceControllerStatus.Running;
120 | sc.Start();
121 | break;
122 | }
123 | sc.WaitForStatus(check);
124 | serviceaction = true;
125 | }
126 | catch (InvalidOperationException ex)
127 | {
128 | Logger.Log(ex, AppName);
129 | }
130 |
131 | return serviceaction;
132 | }
133 |
134 | #endregion Internal Methods
135 |
136 | #region Private Fields
137 |
138 | private const string FILETYPE_WIXPDB = "WixPdb";
139 | private const string FILETYPE_BIN = "BIN";
140 | private const string WIXBUNDLE = "WixBundle";
141 |
142 | static private string temp = System.IO.Path.GetTempPath();
143 | static private ServiceController sc = new ServiceController();
144 |
145 | #endregion Private Fields
146 |
147 | #region Private Methods
148 |
149 | /// Define where the temp directory is located.
150 | public static string TempDir
151 | {
152 | get { return temp; }
153 | set { temp = TrailingSlash(value); }
154 | }
155 |
156 | private static string TrailingSlash(string dir)
157 | {
158 | if (!dir.EndsWith("\\", StringComparison.OrdinalIgnoreCase)) dir += "\\";
159 | return dir;
160 | }
161 |
162 | #endregion Private Methods
163 |
164 | #region IDisposable Support
165 |
166 | private bool disposedValue; // To detect redundant calls
167 |
168 | /// Clean up objects explicitly
169 | ///
170 | protected virtual void Dispose(bool disposing)
171 | {
172 | if (!disposedValue)
173 | {
174 | Logger.Log("Disposing of objects", Logger.MessageLevel.Verbose, AppName);
175 | if (disposing)
176 | {
177 | sc.Dispose();
178 | // Logger.Dispose();
179 | }
180 |
181 | disposedValue = true;
182 | }
183 | sc.Dispose();
184 | }
185 |
186 | /// Dispose of resources utilitized by Utility item
187 | public void Dispose()
188 | {
189 | // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
190 | Dispose(true);
191 | // TODO: uncomment the following line if the finalizer is overridden above.
192 | GC.SuppressFinalize(this);
193 | }
194 |
195 | #endregion IDisposable Support
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/VS.ConfigurationManager.Support.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | AnyCPU
8 | {13C73873-A5ED-42DE-97F0-A3B2D7A1D76F}
9 | Library
10 | Properties
11 | VS.ConfigurationManager.Support
12 | VS.ConfigurationManager.Support
13 | v4.0
14 | 512
15 |
16 |
17 |
18 |
19 |
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | TRACE;DEBUG;DOTNETFRAMEWORK35;
25 | prompt
26 | 4
27 | ManagedMinimumRules.ruleset
28 | false
29 | false
30 |
31 |
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE;DOTNETFRAMEWORK35;
36 | prompt
37 | 4
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Microsoft
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager.Support/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/Bundle.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager.Support;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.IO;
6 | using System.Security.Permissions;
7 |
8 | namespace Microsoft.VS.ConfigurationManager
9 | {
10 | /// Representation of a Wix bundle that is serializable to disk
11 | [Serializable()]
12 | public class Bundle
13 | {
14 | private const string PackageCacheRegistryPath = @"Software\Policies\Microsoft\WiX\Burn";
15 | private const string PackageCacheValue = @"Package Cache";
16 | private const string AppName = "Bundle";
17 |
18 | // TODO: do these vars need to be static?
19 | private string Temp
20 | {
21 | get
22 | {
23 | return System.IO.Path.GetTempPath();
24 | }
25 | }
26 | private static string ProgramData
27 | {
28 | get
29 | {
30 | return Environment.GetEnvironmentVariable("ALLUSERSPROFILE");
31 | }
32 | }
33 | private string LogLocation
34 | {
35 | get
36 | {
37 | return System.IO.Path.Combine(Temp, @"dd_Uninstall");
38 | }
39 | }
40 | private static string PackageCache
41 | {
42 | get
43 | {
44 | if (!regcheck) // if there is no registry value for package cache, it will return an empty string resulting in all bundles requiring a registry read.
45 | {
46 | cache = String.IsNullOrEmpty(cache) && !regcheck ? Utility.ReadRegKey(PackageCacheRegistryPath, PackageCacheValue.Replace(" ", "")) : cache;
47 | regcheck = true;
48 | }
49 | return String.IsNullOrEmpty(cache) ? System.IO.Path.Combine(ProgramData, PackageCacheValue) : cache;
50 | }
51 | }
52 | private static string cache = string.Empty;
53 | private static bool regcheck;
54 |
55 | private System.Guid bundleid;
56 |
57 | // TODO: Refactor constructors to use defaults.
58 |
59 | /// Bundle creation forcing variables to be set.
60 | public Bundle()
61 | {
62 | SetObjectVariables();
63 | }
64 |
65 | /// Bundle creation with values being passed in before hand.
66 | ///
67 | ///
68 | ///
69 | public Bundle(System.Guid bundleid, string name, string version)
70 | {
71 | Initialize(bundleid, name, version);
72 | }
73 |
74 | /// Bundle creation for all parameters being passed in.
75 | ///
76 | ///
77 | ///
78 | ///
79 | ///
80 | ///
81 | ///
82 | ///
83 | public Bundle(System.Guid bundleid, string name, string version, string releasepdb, string path, string filetype, bool selected, ICollection packages)
84 | {
85 | Initialize(bundleid, name, version);
86 | FileType = filetype;
87 | Selected = selected;
88 | }
89 | ///
90 | /// Creating a bundle without passing package information
91 | ///
92 | ///
93 | ///
94 | ///
95 | ///
96 | ///
97 | ///
98 | ///
99 | public Bundle(System.Guid bundleid, string name, string version, string releasepdb, string path, string filetype, bool selected)
100 | {
101 | Initialize(bundleid, name, version);
102 | FileType = filetype;
103 | Selected = selected;
104 | }
105 |
106 | private void Initialize(System.Guid passedbundleid, string name, string version)
107 | {
108 | SetObjectVariables();
109 | BundleId = passedbundleid;
110 | Name = name;
111 | Version = version;
112 | _installed = Directory.Exists(LocalInstallLocation) ? true : false;
113 | }
114 |
115 | // TODO: does this need to be static.
116 | static private void SetObjectVariables()
117 | {
118 | }
119 |
120 | ///
121 | /// Override the command line for the bundle installation. The last parameter needs to be
122 | /// the log command line parameter.
123 | ///
124 | public string BundleUninstallArguments
125 | {
126 | get { return "/uninstall /force /Q /Log \"{0}\""; }
127 | }
128 | /// Location of the package cache on disk
129 | public string LocalInstallLocation { get; set; }
130 |
131 | /// Bundle product code
132 | public System.Guid BundleId
133 | {
134 | get { return bundleid; }
135 | set
136 | {
137 | bundleid = value;
138 | LocalInstallLocation = System.IO.Path.Combine(PackageCache, '{' + BundleId.ToString() + '}');
139 | }
140 | }
141 |
142 | /// WiX Bundle Product Name
143 | public string Name { get; set; }
144 |
145 | /// WiX Bundle Version
146 | public string Version { get; set; }
147 |
148 | internal string FileType { get; set; }
149 |
150 | /// Is the bundle installed?
151 | public bool Installed
152 | {
153 | get {
154 | LocalInstallLocation = System.IO.Path.Combine(PackageCache, '{' + BundleId.ToString() + '}');
155 | return Directory.Exists(LocalInstallLocation) ? true : false;
156 | }
157 | }
158 |
159 | /// Has the user selected this item for uninstall?
160 | public bool Selected { get; set; }
161 |
162 | private bool _installed;
163 |
164 | ///
165 | /// Initiating an uninstall from the bundle to ensure that force uninstall is first run.
166 | /// Once that has been completed, there can be MSIs that are left behind.
167 | ///
168 | ///
169 | [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust", Unrestricted = false)]
170 | public int Uninstall()
171 | {
172 | var exitcode = -1;
173 | try
174 | {
175 | Logger.Log("Bundle uninstall started.", Logger.MessageLevel.Information, AppName);
176 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "this.Installed: {0}", this.Installed), Logger.MessageLevel.Information, AppName);
177 | if (this.Installed)
178 | {
179 | Logger.Log("Bundle uninstall called and bundle is installed.", Logger.MessageLevel.Information, AppName);
180 | foreach (string file in Directory.GetFiles(LocalInstallLocation, "*.exe"))
181 | {
182 | var bundlelogfilename = LogLocation + "_" + System.IO.Path.ChangeExtension(System.IO.Path.GetFileNameWithoutExtension(file), "log");
183 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Installer: {0}", file), Logger.MessageLevel.Information, AppName);
184 | var args = String.Format(CultureInfo.InvariantCulture, BundleUninstallArguments, bundlelogfilename);
185 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Arguments: {0}", args), Logger.MessageLevel.Information, AppName);
186 |
187 | Logger.LogWithOutput(string.Format("Uninstalling: {0}", file));
188 | exitcode = Utility.ExecuteProcess(file, args);
189 | if (exitcode == 0)
190 | Logger.Log("Uninstall succeeded");
191 | else
192 | {
193 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Uninstall failed with error code: {0}", exitcode), Logger.MessageLevel.Warning, AppName);
194 | break;
195 | }
196 | }
197 | }
198 | }
199 | catch (Exception ex)
200 | {
201 | Logger.Log(ex);
202 | }
203 |
204 | Logger.Log("Bundle uninstall ended.", Logger.MessageLevel.Information, AppName);
205 |
206 | return exitcode;
207 | }
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/BundlesAndPackagesStore.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace Microsoft.VS.ConfigurationManager
8 | {
9 | ///
10 | /// Storing and loading list of bundles and packages.
11 | ///
12 | [Serializable()]
13 | public class BundlesAndPackagesStore
14 | {
15 | ///
16 | /// HashSet of UpgradeCode; we should use UpgradeCode to do package search.
17 | ///
18 | public HashSet UpgradeCodeHash { get; set; }
19 |
20 | ///
21 | /// HashSet of ProductCode; we should use ProductCode to do package search if there's no UpgradeCode is set.
22 | ///
23 | public HashSet NoUpgradeCodeProductCodeHash { get; set; }
24 |
25 | ///
26 | /// A list of bundles.
27 | ///
28 | public List Bundles
29 | {
30 | get; set;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/External/Microsoft.Deployment.WindowsInstaller.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/src/VS.ConfigurationManager/External/Microsoft.Deployment.WindowsInstaller.dll
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/External/wix.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/VisualStudioUninstaller/0444aa51bd221c67432a426ccf171ce329d6bf39/src/VS.ConfigurationManager/External/wix.dll
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/Filter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager.Support;
2 | using System;
3 | using System.Globalization;
4 |
5 | namespace Microsoft.VS.ConfigurationManager
6 | {
7 | ///
8 | /// This class supports search and replace of strings in bundles. It helps in shortening
9 | /// text for easier readability.
10 | ///
11 | public class Filter
12 | {
13 | private const string AppName = "Filter";
14 | #region Public Methods
15 | ///
16 | /// Create a filter class object with parameters added.
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | public static Filter CreateFilter(string name, string source, string target)
23 | {
24 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Creating Filter - name: {0}, source: {1}, target: {2}", name, source, target), Logger.MessageLevel.Information, AppName);
25 | var filter = new Filter
26 | {
27 | Name = name,
28 | ReplaceSource = source,
29 | ReplaceValue = target
30 | };
31 |
32 | return filter;
33 | }
34 | #endregion Public Methods
35 | #region Public Properties
36 | ///
37 | /// Name/description of what this text filter does.
38 | ///
39 | public string Name { get; set; }
40 | ///
41 | /// What would you like to search for to replace?
42 | ///
43 | public string ReplaceSource { get; set; }
44 | ///
45 | /// What are you going to replace the ReplaceSource with?
46 | ///
47 | public string ReplaceValue { get; set; }
48 |
49 | #endregion Public Properties
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/Package.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager.Support;
2 | using System;
3 | using System.Globalization;
4 | using System.Security.Permissions;
5 |
6 |
7 | namespace Microsoft.VS.ConfigurationManager
8 | {
9 | ///
10 | /// Representation of a WiX MSI with pertinent information for running an uninstall.
11 | ///
12 | [Serializable()]
13 | public class Package
14 | {
15 | private const string AppName = "Package";
16 |
17 | static private string systemdir;
18 | static private string temp;
19 | static private string LogLocation;
20 |
21 | ///
22 | /// Definition of what type of Package will be set. Uninstall directives will be different for each.
23 | ///
24 | public enum PackageType
25 | {
26 | ///
27 | /// MSI type
28 | ///
29 | MSI,
30 | ///
31 | /// MSU type
32 | ///
33 | MSU,
34 | ///
35 | /// Redistributables or other bundles
36 | ///
37 | EXE
38 | }
39 | #region Public Properties
40 |
41 | ///
42 | /// When was the MSI installed
43 | ///
44 | public DateTime InstallDate { get; set; }
45 | ///
46 | /// Location of file that initiated the installation
47 | ///
48 | public string InstallLocation { get; set; }
49 | ///
50 | /// WiX MSI product code
51 | ///
52 | public String ProductCode { get; set; }
53 | ///
54 | /// WiX MSI upgrade code
55 | ///
56 | public String UpgradeCode { get; set; }
57 | ///
58 | /// Wix MSI Product Name
59 | ///
60 | public string ProductName { get; set; }
61 | ///
62 | /// Wix MSI Product Version
63 | ///
64 | public string ProductVersion { get; set; }
65 | ///
66 | /// Wix MSI URL value in the case of download
67 | ///
68 | public System.Uri Url { get; set; }
69 | ///
70 | /// Wix MSI Chaining Package value
71 | ///
72 | public string ChainingPackage { get; set; }
73 | ///
74 | /// What set of uninstall instructions should be used is defined by the type of installer that was provided.
75 | ///
76 | public PackageType Type { get; set; }
77 |
78 | private string msiuninstallarguments = @"/qn /norestart IGNOREDEPENDENCIES=ALL ";
79 | private const string msiEXEname = @"msiexec.exe";
80 | private string msuuninstallarguments = @"/quiet /norestart /uninstall /kb:";
81 | private const string MSUEXEname = @"wusa.exe";
82 |
83 | #endregion Public Properties
84 |
85 | #region Public Constructors
86 | ///
87 | /// Constructor to initialize variables necessary for the rest of configuration
88 | ///
89 | public Package()
90 | {
91 | Initialize();
92 | }
93 |
94 | ///
95 | /// Passing in all fields on creation of an instance
96 | ///
97 | ///
98 | ///
99 | ///
100 | ///
101 | ///
102 | ///
103 | ///
104 | ///
105 | public Package(string upgradecode, string productcode, string productversion, string productname, string chainingpackage)
106 | {
107 | Initialize();
108 | Type = PackageType.MSI;
109 | UpgradeCode = upgradecode;
110 | ProductCode = productcode;
111 | ProductVersion = productversion;
112 | ProductName = productname;
113 | ChainingPackage = chainingpackage;
114 | }
115 |
116 | ///
117 | /// Passing in all fields on creation of an instance
118 | ///
119 | ///
120 | ///
121 | ///
122 | ///
123 | ///
124 | ///
125 | ///
126 | public Package(string productcode, string productversion, string productname, string chainingpackage)
127 | {
128 | Initialize();
129 | Type = PackageType.MSI;
130 | ProductCode = productcode;
131 | ProductVersion = productversion;
132 | ProductName = productname;
133 | ChainingPackage = chainingpackage;
134 | }
135 | ///
136 | /// Overloaded value to allow a different value for PackageType to be set.
137 | ///
138 | ///
139 | ///
140 | ///
141 | ///
142 | ///
143 | ///
144 | ///
145 | ///
146 | public Package(string productcode, string productversion, string productname, string chainingpackage, PackageType type)
147 | {
148 | Initialize();
149 | Type = type;
150 | ProductCode = productcode;
151 | ProductVersion = productversion;
152 | ProductName = productname;
153 | ChainingPackage = chainingpackage;
154 | }
155 | #endregion Public Constructors
156 |
157 | #region Public Methods
158 | ///
159 | /// Override for the MSI uninstall command line installation.
160 | /// - /x command is already in place.
161 | /// - /L*V command is already in place.
162 | ///
163 | public string MSUUninstallArguments
164 | {
165 | get { return msuuninstallarguments; }
166 | set { msuuninstallarguments = value.TrimEnd() + " "; }
167 | }
168 |
169 | ///
170 | /// Override for the MSI uninstall command line installation.
171 | /// - /x command is already in place.
172 | /// - /L*V command is already in place.
173 | ///
174 | public string MSIUninstallArguments
175 | {
176 | get { return msiuninstallarguments; }
177 | set { msiuninstallarguments = value.TrimEnd() + " "; }
178 | }
179 | ///
180 | /// Returns the product name of this instantiation
181 | ///
182 | ///
183 | public override string ToString()
184 | {
185 | return ProductName;
186 | }
187 |
188 | ///
189 | /// Initiating an uninstall from the MSI to ensure that force uninstall is first run.
190 | /// Once that has been completed, there can be MSIs that are left behind.
191 | ///
192 | ///
193 |
194 | [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust", Unrestricted = false)]
195 | public int Uninstall()
196 | {
197 | var exitcode = -1;
198 | var args = string.Empty;
199 | var file = string.Empty;
200 | switch (this.Type)
201 | {
202 | case PackageType.MSI:
203 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Installer: {0}", this.ProductName), Logger.MessageLevel.Information, AppName);
204 | var msilogfilename = LogLocation + "_" + System.IO.Path.ChangeExtension(this.NormalizeProductName(this.ProductName), "log");
205 | // Run msiexec from the system path only.
206 | file = System.IO.Path.Combine(systemdir, msiEXEname);
207 | // Quiet uninstall with no restart requested and logging enabled
208 | args = String.Format(CultureInfo.InvariantCulture, MSIUninstallArguments + "/x {0} /L*v \"{1}\"", this.ProductCode.ToString(), msilogfilename);
209 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Arguments: {0}", args));
210 |
211 | exitcode = Utility.ExecuteProcess(file, args);
212 | if (exitcode == 0)
213 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "MSI [{0}] Uninstall succeeded", this.ProductName), Logger.MessageLevel.Information, AppName);
214 | else
215 | {
216 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "MSI [{0}] Uninstall failed with error code: {1}", this.ProductName, exitcode), Logger.MessageLevel.Information, AppName);
217 | }
218 | break;
219 | case PackageType.MSU:
220 | Utility.ServiceAction("wuauserv", Utility.ServiceState.Stop);
221 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "KB{0} - {1}", this.ProductCode, this.ProductName), Logger.MessageLevel.Information, AppName);
222 | args = String.Format(CultureInfo.InvariantCulture, msuuninstallarguments.TrimEnd() + "{0}", this.ProductCode);
223 | file = System.IO.Path.Combine(systemdir, MSUEXEname);
224 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Arguments: {0}", args), Logger.MessageLevel.Information, AppName);
225 | exitcode = Utility.ExecuteProcess(file, args);
226 | if (
227 | (exitcode == 0) || // success
228 | (exitcode == 3010) || // reboot required
229 | (exitcode == 2359303) // already uninstalled
230 | )
231 | {
232 | var msg = String.Empty;
233 | switch (exitcode)
234 | {
235 | case 3010:
236 | msg = "(Reboot required)";
237 | break;
238 | case 2359303:
239 | exitcode = 0; // Override error message from the MSU to signal success
240 | msg = "(Previously uninstalled)";
241 | break;
242 | }
243 |
244 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "MSU [KB{0}] Uninstall succeeded {1}", this.ProductCode, msg), Logger.MessageLevel.Information, AppName);
245 | }
246 | else
247 | {
248 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "MSU [KB{0}] Uninstall failed with error code: {1}", this.ProductCode, exitcode), Logger.MessageLevel.Information, AppName);
249 | }
250 | Utility.ServiceAction("wuauserv", Utility.ServiceState.Stop);
251 | break;
252 | case PackageType.EXE:
253 | break;
254 | }
255 | return exitcode;
256 | }
257 |
258 | private string NormalizeProductName(string productName)
259 | {
260 | return productName.Replace(" ", string.Empty).Replace("/", string.Empty);
261 | }
262 |
263 | #endregion Public Methods
264 |
265 | static private void Initialize()
266 | {
267 | systemdir = Environment.SystemDirectory;
268 | temp = System.IO.Path.GetTempPath();
269 | LogLocation = System.IO.Path.Combine(temp, @"dd_Uninstall");
270 | }
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/Primitives.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager.Support;
2 | using Microsoft.Deployment.WindowsInstaller;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Security.Permissions;
9 | using System.Text;
10 | using Wix = Microsoft.Tools.WindowsInstallerXml;
11 |
12 | namespace Microsoft.VS.ConfigurationManager
13 | {
14 | ///
15 | /// Publically available actions for handling uninstall actions
16 | ///
17 | public class Primitives : IDisposable
18 | {
19 |
20 | #region Public Properties
21 | ///
22 | /// Current machine OS version
23 | ///
24 | public string MachineOSVersion { get; set; }
25 | ///
26 | /// Current machine architecture
27 | ///
28 | public ArchitectureConfiguration MachineArchitectureConfiguration { get; set; }
29 |
30 | public BundlesAndPackagesStore BundlesAndPackagesStore { get; set; }
31 |
32 | ///
33 | /// Flag for ensuring data is loaded successfully.
34 | ///
35 | public bool Processed { get; set; }
36 |
37 | ///
38 | /// Used to debug on development machine. Prevents execution of bundle uninstall and
39 | /// msi uninstalls.
40 | ///
41 | public bool DoNotExecuteProcess { get; set; }
42 |
43 | ///
44 | /// The location where you want files written to when creating output files.
45 | ///
46 | public string DataFilesPath { get; set; }
47 |
48 | ///
49 | /// string of releases that can be passed in to initiate an uninstall for.
50 | ///
51 | public bool DebugReporting
52 | {
53 | get { return debugreporting; }
54 | set
55 | {
56 | debugreporting = value;
57 | Logger.Debug = value;
58 | }
59 | }
60 | ///
61 | /// A set of uninstall actions that will be done either before or after the main uninstall process
62 | ///
63 | public ICollection UninstallActions
64 | {
65 | get { return uninstallactions; }
66 | }
67 | ///
68 | /// List of filters (search and replace) to be applied to text
69 | ///
70 | public ICollection Filters
71 | {
72 | get { return filters; }
73 | }
74 |
75 | ///
76 | /// Accepts a List of Filter (class) object that provides search and replace on for
77 | /// text in product and msi names. Helps shorten output. Progress
78 | /// indicator value when running an uninstall
79 | ///
80 | public decimal Progress { get; set; }
81 |
82 | ///
83 | /// Provides a string that reports on the releases supported and selected
84 | ///
85 | public string ReleaseOutput { get; set; }
86 |
87 | #endregion Public Properties
88 |
89 | #region Public Methods
90 |
91 | ///
92 | /// Constructor.
93 | ///
94 | public Primitives()
95 | {
96 | this.BundlesAndPackagesStore = new BundlesAndPackagesStore();
97 | this.BundlesAndPackagesStore.UpgradeCodeHash = new HashSet();
98 | this.BundlesAndPackagesStore.NoUpgradeCodeProductCodeHash = new HashSet();
99 | this.BundlesAndPackagesStore.Bundles = new List();
100 | }
101 |
102 | ///
103 | /// Using the List of Filter classes, do a replace of strings per the user's
104 | /// specification.
105 | ///
106 | ///
107 | ///
108 | public string ApplyFilter(string Source)
109 | {
110 | foreach (Filter fil in filters) { Source = Source.Replace(fil.ReplaceSource, fil.ReplaceValue); }
111 | return Source;
112 | }
113 |
114 | ///
115 | /// Explicit disposal of objects
116 | ///
117 | public void Dispose()
118 | {
119 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Disposing of {0}", AppName), Logger.MessageLevel.Verbose, AppName);
120 | Dispose(true);
121 | GC.SuppressFinalize(this);
122 | ut.Dispose();
123 | }
124 |
125 | ///
126 | /// GetInstalledItems lists all items that are installed on this machine.
127 | ///
128 | ///
129 | public ICollection GetAllInstalledItems()
130 | {
131 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Getting all installed items", AppName), Logger.MessageLevel.Information, AppName);
132 | ICollection installations = new List();
133 |
134 | try
135 | {
136 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Do we already have an object in memory?", AppName), Logger.MessageLevel.Verbose, AppName);
137 | if (installedmsis.FirstOrDefault() == null)
138 | {
139 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "No installpackages object found - creating", AppName), Logger.MessageLevel.Verbose, AppName);
140 |
141 | installations = ProductInstallation.GetProducts(null, null, UserContexts.All)
142 | .Select(ins => new Package(
143 | this.GetUpgradeCode(ins.LocalPackage),
144 | ins.ProductCode,
145 | ins.ProductVersion == null ? "0.0.0" : ins.ProductVersion.ToString(),
146 | ApplyFilter(string.IsNullOrEmpty(ins.ProductName) ? "(NOTDEFINED)" : ins.ProductName),
147 | null
148 | )
149 | )
150 | .OrderBy(ins => ins.ProductName).ToList();
151 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Packages installed: {0}", installations.Count().ToString(CultureInfo.InvariantCulture)));
152 | }
153 | else
154 | {
155 | Logger.Log("installedpackages is populated.");
156 | installations = (List)installedmsis;
157 | }
158 | }
159 | catch (Exception ex)
160 | {
161 | Logger.Log(ex.Message, Logger.MessageLevel.Error, AppName);
162 | }
163 | installedmsis = installations;
164 | return installations;
165 | }
166 |
167 | ///
168 | /// Clean up Visual Studio folders.
169 | ///
170 | ///
171 | public void CleanupVisualStudioFolders(IEnumerable vsInstallPaths)
172 | {
173 | foreach (var path in vsInstallPaths)
174 | {
175 | try
176 | {
177 | if (!string.IsNullOrEmpty(path) && Directory.Exists(path) && !this.DoNotExecuteProcess)
178 | {
179 | Logger.LogWithOutput(string.Format("Deleting: {0}", path));
180 | this.RecursivelyDeleteFolder(path);
181 | }
182 | }
183 | catch (Exception ex)
184 | {
185 | Logger.LogWithOutput(string.Format("Cannot delete Secondary Installer cache with error: {0}", ex.Message));
186 | }
187 | }
188 | }
189 |
190 | ///
191 | /// Clean up HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio
192 | /// Clean up HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio
193 | ///
194 | public void CleanupVisualStudioRegistryHives()
195 | {
196 | var keyPaths = new string[] {
197 | @"SOFTWARE\Microsoft\VisualStudio\12.0",
198 | @"SOFTWARE\Microsoft\VisualStudio\14.0",
199 | @"SOFTWARE\Microsoft\VisualStudio\15.0",
200 | @"SOFTWARE\Microsoft\VisualStudio\12.0_Config",
201 | @"SOFTWARE\Microsoft\VisualStudio\14.0_Config",
202 | @"SOFTWARE\Microsoft\VisualStudio\15.0_Config",
203 | @"SOFTWARE\Microsoft\DevDiv\vs\Servicing\12.0",
204 | @"SOFTWARE\Microsoft\DevDiv\vs\Servicing\14.0",
205 | @"SOFTWARE\Microsoft\DevDiv\vs\Servicing\15.0",
206 | };
207 |
208 | foreach(var keyPath in keyPaths)
209 | {
210 | if (!this.DoNotExecuteProcess)
211 | {
212 | Logger.LogWithOutput(string.Format("Deleting registry: {0}", keyPath));
213 | this.DeleteRegistryKey(keyPath);
214 | }
215 | }
216 |
217 | }
218 |
219 | private void DeleteRegistryKey(string keyPath)
220 | {
221 | try
222 | {
223 | var x86View = Win32.RegistryKey.OpenBaseKey(Win32.RegistryHive.LocalMachine, Win32.RegistryView.Registry32);
224 | x86View.DeleteSubKeyTree(keyPath, false);
225 |
226 | var x64View = Win32.RegistryKey.OpenBaseKey(Win32.RegistryHive.LocalMachine, Win32.RegistryView.Registry64);
227 | x64View.DeleteSubKeyTree(keyPath, false);
228 |
229 | x86View = Win32.RegistryKey.OpenBaseKey(Win32.RegistryHive.CurrentUser, Win32.RegistryView.Registry32);
230 | x86View.DeleteSubKeyTree(keyPath, false);
231 |
232 | x64View = Win32.RegistryKey.OpenBaseKey(Win32.RegistryHive.CurrentUser, Win32.RegistryView.Registry64);
233 | x64View.DeleteSubKeyTree(keyPath, false);
234 | }
235 | catch (Exception ex)
236 | {
237 | Logger.Log(string.Format("Cannot delete registry with error: {0}", ex.Message));
238 | }
239 | }
240 |
241 | ///
242 | /// Cleanup %ProgramData%\Microsoft\VisualStudioSecondaryInstaller
243 | ///
244 | public void CleanupSecondaryInstallerCache()
245 | {
246 | try
247 | {
248 | if (Directory.Exists(CommonApplicationDataDirectory) && !this.DoNotExecuteProcess)
249 | {
250 | Logger.LogWithOutput(string.Format("Deleting: {0}", CommonApplicationDataDirectory));
251 | this.RecursivelyDeleteFolder(CommonApplicationDataDirectory);
252 | }
253 | }
254 | catch (Exception ex)
255 | {
256 | Logger.LogWithOutput(string.Format("Cannot delete Secondary Installer cache with error: {0}", ex.Message));
257 | }
258 | }
259 |
260 | private static string CommonApplicationDataDirectory
261 | {
262 | get
263 | {
264 | return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
265 | Path.Combine(@"Microsoft", "VisualStudioSecondaryInstaller"));
266 | }
267 | }
268 |
269 | ///
270 | /// delete a folder and all its content
271 | ///
272 | ///
273 | private void RecursivelyDeleteFolder(string folder)
274 | {
275 | foreach (string subDirectory in Directory.GetDirectories(folder))
276 | {
277 | RecursivelyDeleteFolder(subDirectory);
278 | }
279 |
280 | foreach (string file in Directory.GetFiles(folder))
281 | {
282 | DeleteFileIfExists(file);
283 | }
284 |
285 | Directory.Delete(folder);
286 | }
287 |
288 |
289 | private void DeleteFileIfExists(string filePath)
290 | {
291 | if (string.IsNullOrEmpty(filePath))
292 | {
293 | throw new ArgumentNullException("filePath");
294 | }
295 |
296 | if (File.Exists(filePath))
297 | {
298 | try
299 | {
300 | File.Delete(filePath);
301 | }
302 | catch (IOException) // The specified file is in use. -or- ...
303 | {
304 | System.Threading.Thread.Sleep(500);
305 | File.Delete(filePath);
306 | }
307 | catch (UnauthorizedAccessException)
308 | {
309 | // see if it was because file is read only
310 | System.IO.FileAttributes copiedFileAttributes = File.GetAttributes(filePath);
311 | if ((copiedFileAttributes & System.IO.FileAttributes.ReadOnly).Equals(System.IO.FileAttributes.ReadOnly))
312 | {
313 | // remove read only flag
314 | File.SetAttributes(filePath, copiedFileAttributes & ~System.IO.FileAttributes.ReadOnly);
315 |
316 | // try again
317 | File.Delete(filePath);
318 | }
319 | }
320 | }
321 | }
322 |
323 | private string GetUpgradeCode(string installSource)
324 | {
325 | if (File.Exists(installSource))
326 | {
327 | try
328 | {
329 | using (var database = new Database(installSource, DatabaseOpenMode.ReadOnly))
330 | {
331 | using (var view = database.OpenView(database.Tables["Property"].SqlSelectString))
332 | {
333 | view.Execute();
334 | foreach (var rec in view)
335 | {
336 | if ("UpgradeCode".Equals(rec.GetString("Property"), StringComparison.OrdinalIgnoreCase))
337 | {
338 | return rec.GetString("Value");
339 | }
340 | }
341 | }
342 | }
343 | }
344 | catch(Exception e)
345 | {
346 | Logger.Log(e);
347 | }
348 | }
349 | else
350 | {
351 | Logger.Log(string.Format("The {0} doesn't exist, cannot find upgrade code.", installSource));
352 | }
353 |
354 | return string.Empty;
355 | }
356 |
357 | ///
358 | /// Locate PDB files on disk and store them in the release object
359 | ///
360 | public void Initialize()
361 | {
362 | try
363 | {
364 | // Get all files that are in the content directory. Record them as a Bundle for
365 | // later usage. Additionally, check the install state of each Bundle.
366 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Initialize called successfully."), Logger.MessageLevel.Information, AppName);
367 | Processed = false;
368 | }
369 | catch (Exception ex)
370 | {
371 | Logger.Log(ex.Message, Logger.MessageLevel.Error, AppName);
372 | }
373 | }
374 |
375 | ///
376 | /// Load from a data file.
377 | ///
378 | ///
379 | public void LoadFromDataFile(string path)
380 | {
381 | // Generate file name based on configuration and name of the wixpdb
382 | long position = 0;
383 | // create a new formatter instance
384 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
385 |
386 | using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
387 | {
388 | if (position < stream.Length)
389 | {
390 | stream.Seek(position, SeekOrigin.Begin);
391 | this.BundlesAndPackagesStore = (BundlesAndPackagesStore)formatter.Deserialize(stream);
392 | position = stream.Position;
393 | }
394 | }
395 | formatter = null;
396 | }
397 |
398 | ///
399 | /// Load from a data file stream.
400 | ///
401 | ///
402 | public void LoadFromDataFile(Stream stream)
403 | {
404 | // Generate file name based on configuration and name of the wixpdb
405 | long position = 0;
406 | // create a new formatter instance
407 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
408 |
409 | if (position < stream.Length)
410 | {
411 | stream.Seek(position, SeekOrigin.Begin);
412 | this.BundlesAndPackagesStore = (BundlesAndPackagesStore)formatter.Deserialize(stream);
413 | position = stream.Position;
414 | }
415 | formatter = null;
416 | }
417 |
418 | ///
419 | ///
420 | /// Given a file that has been serialized out, this will read in the file and
421 | /// hydrate the object model for a list of InstallableItem.
422 | ///
423 | ///
424 | /// It specifically takes a directory to read all BIN files associated. If an
425 | /// invalid BIN file is found, it will report an error and the loop will continue.
426 | ///
427 | ///
428 | ///
429 | ///
430 | public Bundle LoadFromFile(string value)
431 | {
432 | var outObj = FileToBundle(value);
433 | Processed = true;
434 | return outObj;
435 | }
436 |
437 | ///
438 | ///
439 | /// Takes a list of InstallableItem and converts it to binary output.
440 | ///
441 | ///
442 | /// This is used after data is extracted from a wixpdb using
443 | /// Primitive.GetDataFromPdb()
444 | ///
445 | ///
446 | ///
447 | public void Save(ICollection installable)
448 | {
449 | if (Processed)
450 | {
451 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "File path: {0} Files saved: {1}", this.DataFilesPath, installable.Count().ToString(CultureInfo.InvariantCulture)));
452 | BundlesToFiles(installable, this.DataFilesPath, FILETYPE_BIN);
453 | }
454 | else
455 | {
456 | Logger.Log("WixPdbs have not been processed or the configuration files have not been loaded. Nothing to save.", Logger.MessageLevel.Warning, AppName);
457 | }
458 | }
459 |
460 | ///
461 | /// Save BundlesAndPackageStore object to a data file.
462 | ///
463 | public void SaveToDataFile()
464 | {
465 | // create a new formatter instance
466 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
467 |
468 | string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
469 | Directory.CreateDirectory(tempDirectory);
470 |
471 | string fileName = Path.Combine(tempDirectory, "DataFile.bin");
472 |
473 | Console.WriteLine(@"Writing data file to " + fileName);
474 |
475 | try
476 | {
477 | // open a filestream
478 | using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
479 | {
480 | formatter.Serialize(stream, this.BundlesAndPackagesStore);
481 | }
482 | }catch(Exception e)
483 | {
484 | Console.WriteLine(@"Failed to write data file to " + fileName + " reason: " + e.Message);
485 | }
486 |
487 | Console.WriteLine(string.Format("Writing data file to {0}, completed. ", fileName));
488 | }
489 |
490 | ///
491 | /// Uninstall a specific WiX MSI
492 | ///
493 | ///
494 | ///
495 | [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust", Unrestricted = false)]
496 | public int Uninstall(Package package)
497 | {
498 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Package uninstall initiated: {0}", package.ProductName), Logger.MessageLevel.Information, AppName);
499 | var exitcode = -1;
500 |
501 | try
502 | {
503 | if (!DoNotExecuteProcess)
504 | {
505 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Package uninstall method called"), Logger.MessageLevel.Verbose, AppName);
506 | exitcode = package.Uninstall();
507 | }
508 | else
509 | {
510 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Package uninstall method bypassed - DoNotExecute is true"), Logger.MessageLevel.Verbose, AppName);
511 | exitcode = 0;
512 | }
513 | }
514 | catch (Exception ex)
515 | {
516 | Logger.Log(ex, AppName);
517 | }
518 |
519 | return exitcode;
520 | }
521 |
522 | ///
523 | /// Report what Visual Studio's were installed on this system.
524 | ///
525 | public void InstalledVisualStudioReport()
526 | {
527 | List installedBundles = new List(this.BundlesAndPackagesStore.Bundles.Where(b => b.Installed));
528 | var installedBundleStrings = installedBundles.Select(b =>
529 | String.Format("(Name: {0}, Version: {1}, BundleId: {2})", b.Name, b.Version, b.BundleId)).ToArray();
530 |
531 | if (installedBundleStrings.Count() > 0)
532 | {
533 | Logger.LogWithOutput(string.Format(@"The following bundles were detected on your system: "), Logger.MessageLevel.Information, AppName);
534 |
535 | foreach (var ib in installedBundleStrings)
536 | {
537 | Logger.LogWithOutput(string.Format(ib), Logger.MessageLevel.Information, AppName);
538 | }
539 | }
540 | else
541 | {
542 | Logger.LogWithOutput(string.Format(@"No bundle found. Uninstalling stale MSIs. "), Logger.MessageLevel.Information, AppName);
543 | }
544 | }
545 |
546 | ///
547 | /// Uninstall Visual Studio 2013/2015/vNext
548 | ///
549 | public int Uninstall()
550 | {
551 | List installedBundles = new List(this.BundlesAndPackagesStore.Bundles.Where(b => b.Installed));
552 |
553 | List orderedBundles = new List();
554 |
555 | foreach (var ib in installedBundles)
556 | {
557 | if (!ib.Name.ToLowerInvariant().Contains(@"(kb"))
558 | {
559 | orderedBundles.Add(ib);
560 | }
561 | }
562 |
563 | foreach (var ib in installedBundles)
564 | {
565 | if (ib.Name.ToLowerInvariant().Contains(@"(kb"))
566 | {
567 | orderedBundles.Add(ib);
568 | }
569 | }
570 |
571 | foreach (var ib in orderedBundles)
572 | {
573 | int exitCode = 0;
574 | if (!this.DoNotExecuteProcess)
575 | {
576 | try
577 | {
578 | exitCode = ib.Uninstall();
579 | }
580 | catch(Exception ex)
581 | {
582 | Logger.LogWithOutput(
583 | string.Format("Bundle: {0} uninstalled failed with exception: {1}. ", ib.Name, ex.Message));
584 | }
585 | }
586 | Logger.LogWithOutput(string.Format("Bundle: {0} has been uninstalled with exit code: {1}. ", ib.Name, exitCode));
587 |
588 | if (exitCode == 3010)
589 | {
590 | return exitCode;
591 | }
592 | }
593 |
594 | Logger.LogWithOutput("Normal Visual Studio Uninstall completed.");
595 | Logger.LogWithOutput("Searching for stale MSIs and clean up stale MSIs.");
596 |
597 | var installedPackages = this.GetAllInstalledItems();
598 | List packagesToBeUninstalled = new List();
599 |
600 | foreach(var ip in installedPackages)
601 | {
602 | if (this.BundlesAndPackagesStore.UpgradeCodeHash.Contains(ip.UpgradeCode))
603 | {
604 | packagesToBeUninstalled.Add(ip);
605 | }
606 | else if (this.BundlesAndPackagesStore.NoUpgradeCodeProductCodeHash.Contains(ip.ProductCode))
607 | {
608 | packagesToBeUninstalled.Add(ip);
609 | }
610 | }
611 |
612 | if (packagesToBeUninstalled.Count > 0)
613 | {
614 | Logger.LogWithOutput(string.Format("{0} stale MSIs found. Uninstalling them.", packagesToBeUninstalled.Count ));
615 |
616 | int count = packagesToBeUninstalled.Count;
617 | foreach (var p in packagesToBeUninstalled)
618 | {
619 | int rc = 0;
620 |
621 | if (!this.DoNotExecuteProcess)
622 | {
623 | try
624 | {
625 | rc = p.Uninstall();
626 | }
627 | catch(Exception ex)
628 | {
629 | Logger.LogWithOutput(
630 | string.Format("Msi: {0} uninstalled failed with exception: {1}. ", p.ProductName, ex.Message));
631 | }
632 | }
633 | count--;
634 | Logger.LogWithOutput(string.Format("Uninstalled {0} with exit code: {1}. {2}/{3}", p.ProductName, rc, count, packagesToBeUninstalled.Count));
635 | }
636 | }
637 |
638 | return 0;
639 | }
640 |
641 | #endregion Public Methods
642 |
643 | #region Protected Methods
644 |
645 | ///
646 | protected virtual void Dispose(bool disposing)
647 | {
648 | if (!disposed)
649 | {
650 | if (disposing) {
651 | BundlesAndPackagesStore.UpgradeCodeHash = null;
652 | BundlesAndPackagesStore.NoUpgradeCodeProductCodeHash = null;
653 | BundlesAndPackagesStore.Bundles = null;
654 | ut.Dispose();
655 | }
656 | }
657 | //dispose unmanaged resources
658 | disposed = true;
659 | }
660 |
661 | #endregion Protected Methods
662 |
663 | #region Private Fields
664 |
665 | private const string CHAINMSIPACKAGE = "ChainMsiPackage";
666 |
667 | private const string UXPACKAGEBEHAVIOR = "UxPackageBehavior";
668 |
669 | private const string FILETYPE_WIXPDB = "WixPdb";
670 |
671 | private const string FILETYPE_BIN = "BIN";
672 |
673 | private const string WIXBUNDLE = "WixBundle";
674 |
675 | private const string AppName = "Primitives";
676 |
677 | private bool debugreporting;
678 |
679 | private bool disposed;
680 |
681 | private ICollection filters = new List();
682 |
683 | private ICollection uninstallactions = new List();
684 |
685 | private ICollection installedmsis = new List();
686 |
687 | private string releaseoutput = string.Empty;
688 |
689 | private Utility ut = new Utility();
690 |
691 | #endregion Private Fields
692 |
693 | #region Private Methods
694 | private void GetUniquePackages(HashSet upgradeCodeHash,
695 | HashSet noUpgradeCodeProductCodeHash,
696 | Wix.Table chainmsipackageTable,
697 | Wix.Table uxPackageBehavior)
698 | {
699 | try
700 | {
701 | Dictionary uxPackageBehaviorDict = new Dictionary();
702 | if (uxPackageBehavior != null)
703 | {
704 | foreach (Wix.Row msirow in uxPackageBehavior.Rows)
705 | {
706 | string packageId = string.Empty;
707 | string reallyPerm = string.Empty;
708 | foreach (Wix.Field field in msirow.Fields)
709 | {
710 | switch (field.Column.Name.ToString(CultureInfo.InvariantCulture).ToUpperInvariant())
711 | {
712 | case "PackageId":
713 | packageId = field.Data.ToString();
714 | break;
715 | case "ReallyPermanent": // nullable.
716 | if (field.Data != null)
717 | {
718 | reallyPerm = field.Data.ToString();
719 | }
720 | break;
721 |
722 | }
723 | }
724 | if (!string.IsNullOrEmpty(packageId) && !uxPackageBehaviorDict.ContainsKey(packageId))
725 | {
726 | uxPackageBehaviorDict.Add(packageId, reallyPerm);
727 | }
728 | }
729 | }
730 |
731 | foreach (Wix.Row msirow in chainmsipackageTable.Rows)
732 | {
733 | var msi = new Package();
734 |
735 | foreach (Wix.Field field in msirow.Fields)
736 | {
737 | switch (field.Column.Name.ToString(CultureInfo.InvariantCulture).ToUpperInvariant())
738 | {
739 | case "CHAINPACKAGE_":
740 | msi.ChainingPackage = field.Data.ToString();
741 | break;
742 |
743 | case "PRODUCTCODE": // id 23
744 | msi.ProductCode = field.Data.ToString();
745 | break;
746 |
747 | case "UPGRADECODE": // nullable.
748 | if (field.Data != null)
749 | {
750 | msi.UpgradeCode = field.Data.ToString();
751 | }
752 | break;
753 | case "PRODUCTVERSION":
754 | msi.ProductVersion = field.Data.ToString();
755 | break;
756 |
757 | case "PRODUCTNAME":
758 | msi.ProductName = field.Data.ToString();
759 | break;
760 | case "PACKAGETYPE":
761 | msi.Type = Package.PackageType.MSI;
762 | break;
763 | default:
764 | break;
765 | }
766 | }
767 |
768 | // if the package is really perm, then, don't uninstall it.
769 | if (!string.IsNullOrEmpty(msi.ChainingPackage)
770 | && uxPackageBehaviorDict.ContainsKey(msi.ChainingPackage)
771 | && uxPackageBehaviorDict[msi.ChainingPackage].Equals("yes", StringComparison.OrdinalIgnoreCase))
772 | {
773 | continue;
774 | }
775 |
776 | if (string.IsNullOrEmpty(msi.UpgradeCode))
777 | {
778 | noUpgradeCodeProductCodeHash.Add(msi.ProductCode);
779 | }
780 | else
781 | {
782 | if (!upgradeCodeHash.Contains(msi.UpgradeCode))
783 | {
784 | upgradeCodeHash.Add(msi.UpgradeCode);
785 | }
786 | }
787 | }
788 | // We should not be uninstalling MSU because they are usually perm and they are windows comp.
789 | }
790 | catch (Exception ex)
791 | {
792 | Logger.Log(ex);
793 | }
794 | }
795 |
796 | static private Bundle FileToBundle(string file)
797 | {
798 | // Generate file name based on configuration and name of the wixpdb
799 | long position = 0;
800 | // create a new formatter instance
801 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
802 |
803 | // read the animal as position back
804 | Bundle installable = null;
805 | using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read))
806 | {
807 | if (position < stream.Length)
808 | {
809 | stream.Seek(position, SeekOrigin.Begin);
810 | installable = (Bundle)formatter.Deserialize(stream);
811 | position = stream.Position;
812 | }
813 | }
814 | formatter = null;
815 | return installable;
816 | }
817 |
818 | ///
819 | /// Load a wixpdb
820 | ///
821 | ///
822 | ///
823 | public bool LoadFromWixpdb(string path)
824 | {
825 | try
826 | {
827 | // Get all files associated with WixPDBs in directory
828 | Logger.Log(String.Format(CultureInfo.InvariantCulture, "Loading {0}", path), Logger.MessageLevel.Information, "Utility");
829 | var pdb = Wix.Pdb.Load(Path.GetFullPath(path), true, true);
830 | var bundlerowinfo = (Wix.WixBundleRow)GetBundlesFromWixPDB(pdb).Rows[0];
831 |
832 | var bundle = new Bundle(bundlerowinfo.BundleId, bundlerowinfo.Name, bundlerowinfo.Version, Path.GetFileNameWithoutExtension(path), Path.GetFullPath(path), FILETYPE_WIXPDB, false);
833 | if (!this.BundlesAndPackagesStore.Bundles.Any(b => b.BundleId == bundle.BundleId))
834 | {
835 | this.BundlesAndPackagesStore.Bundles.Add(bundle);
836 | }
837 |
838 | if (pdb.Output.Type == Wix.OutputType.Bundle)
839 | {
840 | var wixbundle = pdb.Output.Tables[WIXBUNDLE]; //Id: 32 in pdb.Output.Rows
841 | var chainmsipackageTable = pdb.Output.Tables[CHAINMSIPACKAGE]; //Id: 0 in pdb.Output.Rows
842 | var uxPackageBehavior = pdb.Output.Tables[UXPACKAGEBEHAVIOR]; //Id: 0 in pdb.Output.Rows
843 |
844 | if (wixbundle != null)
845 | {
846 | if (chainmsipackageTable != null)
847 | {
848 | this.GetUniquePackages(
849 | this.BundlesAndPackagesStore.UpgradeCodeHash,
850 | this.BundlesAndPackagesStore.NoUpgradeCodeProductCodeHash,
851 | chainmsipackageTable,
852 | uxPackageBehavior);
853 | }
854 | }
855 | }
856 |
857 | bundlerowinfo = null;
858 | }
859 | catch (Exception e)
860 | {
861 | Logger.Log("Unable to load wixpdb: " + path, Logger.MessageLevel.Error);
862 | Logger.Log(e);
863 | return false;
864 | }
865 | return true;
866 | }
867 |
868 | private static Wix.Table GetBundlesFromWixPDB(Microsoft.Tools.WindowsInstallerXml.Pdb pdb)
869 | {
870 | var wixbundle = pdb.Output.Tables[WIXBUNDLE]; //Id: 32 in pdb.Output.Rows
871 | return wixbundle;
872 | }
873 |
874 | private static void BundlesToFiles(ICollection installable, string DataFilesPath, string ext)
875 | {
876 | var path = DataFilesPath ?? System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "DataFiles");
877 | var di = new DirectoryInfo(path);
878 |
879 | if (!di.Exists)
880 | di.Create();
881 |
882 | string filename = null;
883 |
884 | foreach (Bundle insitem in installable)
885 | {
886 | // Generate file name based on configuration and name of the wixpdb
887 | filename = System.IO.Path.Combine(path, Path.ChangeExtension(insitem.Name, ext));
888 |
889 | // create a new formatter instance
890 | var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
891 |
892 | // open a filestream
893 | using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
894 | {
895 | formatter.Serialize(stream, insitem);
896 | }
897 | }
898 | }
899 |
900 | #endregion Private Methods
901 | }
902 | }
903 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Microsoft.VisualStudio.Setup.Properties")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | // Setting ComVisible to false makes the types in this assembly not visible
15 | // to COM components. If you need to access a type in this assembly from
16 | // COM, set the ComVisible attribute to true on that type.
17 | [assembly: ComVisible(false)]
18 |
19 | // The following GUID is for the ID of the typelib if this project is exposed to COM
20 | [assembly: Guid("a1d9e507-68cb-4e12-8ee3-a52d9921ee3b")]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 |
30 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/SystemSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 |
4 | namespace Microsoft.VS.ConfigurationManager
5 | {
6 | ///
7 | /// Getting version information and architecture information for use with UninstallAction
8 | /// class. This will define which items are applicable.
9 | ///
10 | /// Source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx
11 | /// Operating system Version number
12 | /// Windows 10 10.0*
13 | /// Windows Server Technical Preview 10.0*
14 | /// Windows 8.1 6.3*
15 | /// Windows Server 2012 R2 6.3*
16 | /// Windows 8 6.2
17 | /// Windows Server 2012 6.2
18 | /// Windows 7 6.1
19 | /// Windows Server 2008 R2 6.1
20 | /// Windows Server 2008 6.0
21 | /// Windows Vista 6.0
22 | /// Windows Server 2003 R2 5.2
23 | /// Windows Server 2003 5.2
24 | /// Windows XP 64-Bit Edition 5.2
25 | /// Windows XP 5.1
26 | /// Windows 2000 5.0
27 | ///
28 | public static class SystemSettings
29 | {
30 | static private string _version = string.Empty;
31 | ///
32 | /// Returns true for 64 bit system and false for x86.
33 | ///
34 | ///
35 | static public bool Is64()
36 | {
37 | return IntPtr.Size == 8 ? true : false;
38 | }
39 | ///
40 | /// Returns Major.Minor version as a string back to the caller.
41 | ///
42 | ///
43 | static public string Version()
44 | {
45 | if (string.IsNullOrEmpty(_version))
46 | {
47 | var _VersionMajor = Environment.OSVersion.Version.Major.ToString(CultureInfo.InvariantCulture);
48 | var _VersionMinor = Environment.OSVersion.Version.Minor.ToString(CultureInfo.InvariantCulture);
49 | _version = _VersionMajor + "." + _VersionMinor;
50 | }
51 | return _version;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/UninstallAction.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VS.ConfigurationManager.Support;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 | using System.Linq;
6 |
7 | namespace Microsoft.VS.ConfigurationManager
8 | {
9 | ///
10 | /// This class is being created to handle any post uninstall actions that are required. In the
11 | /// case of Dev14, this will handle the /force issues found. If multiple post uninstall
12 | /// actions are required, a list can be used to establish dependencies.
13 | ///
14 | public class UninstallAction
15 | {
16 | ///
17 | /// Constructor to evaluate all values to default values.
18 | ///
19 | public UninstallAction()
20 | {
21 | Template = TemplateType.Unset;
22 | Architectures = new List();
23 | ProductCode = null;
24 | WixObject = WixObjectType.Unset;
25 | OS = new List();
26 | }
27 | ///
28 | /// Constructor to handle the creation of an uninstall action with all information passed in.
29 | ///
30 | ///
31 | ///
32 | ///
33 | ///
34 | ///
35 | public UninstallAction(ICollection os, TemplateType template, ICollection arch, string productcode, WixObjectType wixobj)
36 | {
37 | Template = template;
38 | Architectures = arch;
39 | ProductCode = productcode;
40 | WixObject = wixobj;
41 | OS = os;
42 | }
43 |
44 | ///
45 | /// Defined to use either bundle or MSI exec installer
46 | ///
47 | public enum WixObjectType {
48 | ///
49 | /// Default value for Enum
50 | ///
51 | Unset,
52 | ///
53 | /// Represents a bundle for this step
54 | ///
55 | Bundle,
56 | ///
57 | /// Represents an MSI for this step
58 | ///
59 | MSI,
60 | ///
61 | /// Represents an MSU for this step
62 | ///
63 | MSU
64 | }
65 |
66 | ///
67 | /// Identify when this step should run; before or after the uninstall process
68 | ///
69 | public enum TemplateType {
70 | ///
71 | /// Default value for Enum
72 | ///
73 | Unset,
74 | ///
75 | /// Run this uninstall action before the main uninstall process
76 | ///
77 | Pre,
78 | ///
79 | /// Run this uninstall action after the main uninstall process
80 | ///
81 | Post
82 | }
83 |
84 | ///
85 | /// What architectures is this uninstall action valid for
86 | ///
87 | public enum Arch {
88 | ///
89 | /// Default value for Enum
90 | ///
91 | Unset,
92 | ///
93 | /// Only valid on x86 configurations
94 | ///
95 | x86,
96 | ///
97 | /// Only valid on 64-bit configurations
98 | ///
99 | x64
100 | }
101 |
102 | private string _productcode;
103 | ///
104 | /// Maps to the installed product code of the WixObjectType
105 | ///
106 | public string ProductCode {
107 | get
108 | {
109 | return _productcode;
110 | }
111 | set
112 | {
113 | _productcode = value == null ? String.Empty : value;
114 | }
115 | }
116 |
117 | ///
118 | /// Is this a bundle or an MSI
119 | ///
120 | public WixObjectType WixObject { get; set; }
121 |
122 | ///
123 | /// Does this run before or after the normal uninstall process
124 | ///
125 | public TemplateType Template { get; set; }
126 |
127 | ///
128 | /// What architectures is this valid on?
129 | ///
130 | public ICollection Architectures { get; set; }
131 |
132 | ///
133 | /// What OS version is this valid on?
134 | ///
135 | public ICollection OS { get; set; }
136 |
137 | ///
138 | /// Create an uninstall action with the given parameters
139 | ///
140 | ///
141 | ///
142 | ///
143 | ///
144 | ///
145 | ///
146 | public static UninstallAction CreateUninstallAction(ICollection archs, ICollection oses, string productcode, UninstallAction.TemplateType template, UninstallAction.WixObjectType objecttype)
147 | {
148 | var ua = new UninstallAction();
149 | foreach (ArchitectureConfiguration arch in archs) { ua.Architectures.Add(arch); }
150 | foreach (OperatingSystemConfiguration os in oses) { ua.OS.Add(os); }
151 | ua.ProductCode = productcode;
152 | ua.Template = template;
153 | ua.WixObject = objecttype;
154 |
155 | return ua;
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/VS.ConfigurationManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}
7 | v3.5
8 |
9 |
10 |
11 |
12 |
13 | Library
14 |
15 |
16 |
17 |
18 |
19 | TRACE;DEBUG;DOTNETFRAMEWORK35;
20 | ManagedMinimumRules.ruleset
21 | false
22 | false
23 |
24 |
25 | {CACCC6E1-FCB8-4DBE-9159-0F8EAA69D27A}
26 | v4.0
27 |
28 |
29 |
30 | TRACE;DOTNETFRAMEWORK35;
31 |
32 |
33 | Setup.VS.ConfigurationManager
34 |
35 |
36 |
37 | False
38 | $(SolutionDir)lib\wix37\Microsoft.Deployment.WindowsInstaller.dll
39 |
40 |
41 | False
42 | $(SolutionDir)lib\wix37\Microsoft.Deployment.WindowsInstaller.Package.dll
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Microsoft
68 |
69 |
70 |
71 |
72 | {13c73873-a5ed-42de-97f0-a3b2d7a1d76f}
73 | VS.ConfigurationManager.Support
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/src/VS.ConfigurationManager/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/tools/PreBuild.ps1:
--------------------------------------------------------------------------------
1 | # Set up solution paths.
2 | $ToolsDir = split-path -parent $MyInvocation.MyCommand.Path
3 | $SolutionDir = split-path -parent $ToolsDir
4 |
5 | # Restore NuGet packages prior to build.
6 | # This ensures ItemDefinitionGroups for native projects are read at the appropriate time.
7 | $NuGetCommand = join-path $SolutionDir '.nuget\nuget.exe'
8 | &$NuGetCommand restore
9 |
--------------------------------------------------------------------------------
/tools/Publish.proj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Release
5 | $(PublishDir)\
6 |
7 |
8 |
9 |
10 |
11 |
12 | Configuration=$(Configuration);Platform=$(Platform)
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | CheckRequirements;
24 | Build;
25 | $(PublishDependsOn);
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------