6 |
7 | ## Instruction
8 |
9 | > Instruction below may inaccurate. Always adhere to [MSDN Manual][officialmanual] first.
10 |
11 | In order:
12 |
13 | 1. [Download][medown] and Run the software
14 | 2. Select the edition
15 | 3. Set options (recommended/optional and language)
16 | 4. (Optional) Fetch the updated workload data.
17 | 5. Choose (and review) selected workloads and component.
18 | 6. Download the [stub installer][installer]. Run with the provided download arguments from this software.
19 | 7. CLI will appear. Wait until all component downloaded.
20 | 8. Open wizard (see distribute section). This will open a new window.
21 |
22 | 
23 |
24 | 9. Check the paths, change if necessary.
25 | 10. `Save` the batch file. You'll use this as the starting point of VS 2017 installation.
26 | 11. After the save button, you'll see a confirmation. Click `Yes` to execute the batchfile. Next step you just need to follow the instruction.
27 | 12. (Optional) if you want to keep the layout file for future, hit the `Start` button to save it as an ISO file. Wait until it gets completed.
28 |
29 | ## Additional Notes
30 |
31 | > To run the installation with arguments:
32 |
33 |
34 |
35 | > CLI (Command line Interface) will appear when downloading layouts, but will show normal GUI during offline installation.
36 |
37 | > Before installation begin VS will show you list of workloads, even when you're offline. Following instruction above you only need to skip it (as cached layouts is already selected via arguments).
38 |
39 | > If a component are missing from downloaded layout, it'll redownloaded automatically at install. If you're on metered network you can turn off the internet during install to prevent it. The installation still can continue anyway (with prompts).
40 |
41 | ## How it works
42 |
43 | This software fetch list of workload and component IDs from [GitHub mirror][workloadsgit] of their [List of Workloads][workloadsdoc] in their documentation. This is necessary because you will always get updated list of workloads, and I don't know other way to do it.
44 |
45 | If Microsoft changes or move their documentation layout or path, there will be chance that this application fail to parse, or even crash. If this happen, tell me.
46 |
47 | This software always cache the downloaded package, so you don't have to spam the Github servers that kindly serve their docs to make this software possible.
48 |
49 | ## Disclaimer
50 |
51 | This is a third-party software and does not represent any Microsoft Products.
52 |
53 | License: [MIT](LICENSE)
54 |
55 | > 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.
56 |
57 | [medown]: https://github.com/willnode/Vs2017-LayoutInGUI/releases
58 | [installer]: https://docs.microsoft.com/en-us/visualstudio/install/install-vs-inconsistent-quality-network#step-1---download-the-visual-studio-bootstrapper
59 | [officialmanual]: https://docs.microsoft.com/en-us/visualstudio/install/install-vs-inconsistent-quality-network
60 | [workloadsdoc]: https://docs.microsoft.com/en-us/visualstudio/install/workload-and-component-ids
61 | [workloadsgit]: https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/install/workload-and-component-ids.md
62 | [certificates]: https://docs.microsoft.com/en-us/visualstudio/install/install-certificates-for-visual-studio-offline
63 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/IsoWizard.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | C:\vs2017Layout
34 |
35 |
36 | C:\vs2017Layout.iso
37 |
38 |
39 | VS 2017 Community
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | vs_Community.bat
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/Vs2017-LayoutInGUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E21D5673-8543-4130-89A1-90BF80352814}
8 | WinExe
9 | Vs2017LIGUI
10 | Vs2017LIGUI
11 | v4.5
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 |
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 | false
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 | false
38 |
39 |
40 | Icon.ico
41 |
42 |
43 |
44 | Properties\IsoCreatorLib.dll
45 |
46 |
47 | ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
48 | True
49 |
50 |
51 |
52 |
53 | 4.0
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | MSBuild:Compile
62 | Designer
63 |
64 |
65 | Designer
66 | MSBuild:Compile
67 |
68 |
69 | MSBuild:Compile
70 | Designer
71 |
72 |
73 | App.xaml
74 | Code
75 |
76 |
77 | IsoWizard.xaml
78 |
79 |
80 | MainWindow.xaml
81 | Code
82 |
83 |
84 |
85 |
86 |
87 | Code
88 |
89 |
90 | True
91 | True
92 | Resources.resx
93 |
94 |
95 | True
96 | Settings.settings
97 | True
98 |
99 |
100 | ResXFileCodeGenerator
101 | Resources.Designer.cs
102 |
103 |
104 |
105 | SettingsSingleFileGenerator
106 | Settings.Designer.cs
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/DocProcesser.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Vs2017LIGUI
6 | {
7 |
8 | public class Workload
9 | {
10 | public string Name { get; set; }
11 |
12 | [JsonIgnore]
13 | public string NameFull { get { return Name; } }
14 |
15 | public string ID { get; set; }
16 | public string Description { get; set; }
17 |
18 | public List Components { get; } = new List();
19 |
20 | [JsonIgnore]
21 | public bool Selectable { get { return !string.IsNullOrEmpty(ID); } }
22 |
23 | [JsonIgnore]
24 | public bool Selected { get; set; }
25 |
26 | [JsonIgnore]
27 | public bool Expanded { get; set; }
28 | }
29 |
30 | public static class ComponentSettings
31 | {
32 | public static bool UseRecommended;
33 | public static bool UseOptional;
34 | public static string Lang = "en-US";
35 |
36 | }
37 |
38 | public class Component
39 | {
40 |
41 | [JsonIgnore]
42 | public Workload TheWorkload;
43 |
44 | public string ID { get; set; }
45 |
46 | public string Name { get; set; }
47 |
48 | [JsonIgnore]
49 | public string NameFull { get { return Name + " - " + Depedency.ToString(); } }
50 |
51 | public string Version { get; set; }
52 |
53 | public Depedency Depedency { get; set; }
54 |
55 | [JsonIgnore]
56 | public bool Selectable { get { return !(!SelfSelected & SelectedFromWorkload()); } }
57 |
58 | [JsonIgnore]
59 | public bool Selected { get { return SelfSelected | SelectedFromWorkload(); } set { if (Selectable) SelfSelected = value; } }
60 |
61 | [JsonIgnore]
62 | public bool SelfSelected { get; set; }
63 |
64 | public bool SelectedFromWorkload()
65 | {
66 | switch (Depedency)
67 | {
68 | case Depedency.Required:
69 | return TheWorkload.Selected;
70 | case Depedency.Recommended:
71 | return TheWorkload.Selected & ComponentSettings.UseRecommended;
72 | case Depedency.Optional:
73 | return TheWorkload.Selected & ComponentSettings.UseOptional;
74 | case Depedency.Independent:
75 | default:
76 | return false;
77 | }
78 | }
79 | }
80 |
81 | public enum Depedency
82 | {
83 | Independent = 0,
84 | Required = 1,
85 | Recommended = 2,
86 | Optional = 3,
87 | }
88 |
89 | public class DocProcesser
90 | {
91 |
92 | // Markdown parsing starts here
93 | public void Process(string doc, List Workloads)
94 | {
95 | Workloads.Clear();
96 |
97 | Workload item = null;
98 |
99 | var lines = doc.Replace("\r", "").Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
100 |
101 | for (int i = 0; i < lines.Length;)
102 | {
103 | var line = lines[i].Trim();
104 | if (line.Length > 3 && line.Substring(0, 3) == "## ")
105 | {
106 | // title (H2)
107 | item = new Workload() { Name = line.Substring(3) };
108 |
109 | if (item.Name.ToLower() == "get support")
110 | break; // must be not
111 |
112 | var line2nd = lines[++i];
113 |
114 | if (line2nd.Substring(0, 8) == "**ID:** ")
115 | {
116 | item.ID = line2nd.Substring(7);
117 | item.Description = lines[++i].Replace("**Description:** ", "");
118 | }
119 | else
120 | item.Description = line2nd; // Other non-workload options
121 |
122 | while (i < lines.Length && lines[i++].Substring(0, 5) != "--- |")
123 | {
124 | // we're incrementing i
125 | }
126 |
127 | // begin fetching components
128 | while (i < lines.Length && lines[i].Substring(0, 3) != "## ")
129 | {
130 | var line3rd = lines[i++].Split('|');
131 |
132 | if (line3rd.Length < 3)
133 | continue; // NOT-A-TABLE line :/
134 |
135 | var component = new Component()
136 | {
137 | ID = line3rd[0].Trim(),
138 | Name = line3rd[1],
139 | Version = line3rd[2],
140 | Depedency = line3rd.Length > 3 ? (Depedency)Enum.Parse(typeof(Depedency), line3rd[3], true) : Depedency.Independent,
141 | TheWorkload = item,
142 | };
143 | item.Components.Add(component);
144 | }
145 |
146 | Workloads.Add(item);
147 | }
148 | else
149 | i++;
150 |
151 | }
152 | }
153 | }
154 |
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # Benchmark Results
46 | BenchmarkDotNet.Artifacts/
47 |
48 | # .NET Core
49 | project.lock.json
50 | project.fragment.lock.json
51 | artifacts/
52 | **/Properties/launchSettings.json
53 |
54 | *_i.c
55 | *_p.c
56 | *_i.h
57 | *.ilk
58 | *.meta
59 | *.obj
60 | *.pch
61 | *.pdb
62 | *.pgc
63 | *.pgd
64 | *.rsp
65 | *.sbr
66 | *.tlb
67 | *.tli
68 | *.tlh
69 | *.tmp
70 | *.tmp_proj
71 | *.log
72 | *.vspscc
73 | *.vssscc
74 | .builds
75 | *.pidb
76 | *.svclog
77 | *.scc
78 |
79 | # Chutzpah Test files
80 | _Chutzpah*
81 |
82 | # Visual C++ cache files
83 | ipch/
84 | *.aps
85 | *.ncb
86 | *.opendb
87 | *.opensdf
88 | *.sdf
89 | *.cachefile
90 | *.VC.db
91 | *.VC.VC.opendb
92 |
93 | # Visual Studio profiler
94 | *.psess
95 | *.vsp
96 | *.vspx
97 | *.sap
98 |
99 | # TFS 2012 Local Workspace
100 | $tf/
101 |
102 | # Guidance Automation Toolkit
103 | *.gpState
104 |
105 | # ReSharper is a .NET coding add-in
106 | _ReSharper*/
107 | *.[Rr]e[Ss]harper
108 | *.DotSettings.user
109 |
110 | # JustCode is a .NET coding add-in
111 | .JustCode
112 |
113 | # TeamCity is a build add-in
114 | _TeamCity*
115 |
116 | # DotCover is a Code Coverage Tool
117 | *.dotCover
118 |
119 | # AxoCover is a Code Coverage Tool
120 | .axoCover/*
121 | !.axoCover/settings.json
122 |
123 | # Visual Studio code coverage results
124 | *.coverage
125 | *.coveragexml
126 |
127 | # NCrunch
128 | _NCrunch_*
129 | .*crunch*.local.xml
130 | nCrunchTemp_*
131 |
132 | # MightyMoose
133 | *.mm.*
134 | AutoTest.Net/
135 |
136 | # Web workbench (sass)
137 | .sass-cache/
138 |
139 | # Installshield output folder
140 | [Ee]xpress/
141 |
142 | # DocProject is a documentation generator add-in
143 | DocProject/buildhelp/
144 | DocProject/Help/*.HxT
145 | DocProject/Help/*.HxC
146 | DocProject/Help/*.hhc
147 | DocProject/Help/*.hhk
148 | DocProject/Help/*.hhp
149 | DocProject/Help/Html2
150 | DocProject/Help/html
151 |
152 | # Click-Once directory
153 | publish/
154 |
155 | # Publish Web Output
156 | *.[Pp]ublish.xml
157 | *.azurePubxml
158 | # Note: Comment the next line if you want to checkin your web deploy settings,
159 | # but database connection strings (with potential passwords) will be unencrypted
160 | *.pubxml
161 | *.publishproj
162 |
163 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
164 | # checkin your Azure Web App publish settings, but sensitive information contained
165 | # in these scripts will be unencrypted
166 | PublishScripts/
167 |
168 | # NuGet Packages
169 | *.nupkg
170 | # The packages folder can be ignored because of Package Restore
171 | **/packages/*
172 | # except build/, which is used as an MSBuild target.
173 | !**/packages/build/
174 | # Uncomment if necessary however generally it will be regenerated when needed
175 | #!**/packages/repositories.config
176 | # NuGet v3's project.json files produces more ignorable files
177 | *.nuget.props
178 | *.nuget.targets
179 |
180 | # Microsoft Azure Build Output
181 | csx/
182 | *.build.csdef
183 |
184 | # Microsoft Azure Emulator
185 | ecf/
186 | rcf/
187 |
188 | # Windows Store app package directories and files
189 | AppPackages/
190 | BundleArtifacts/
191 | Package.StoreAssociation.xml
192 | _pkginfo.txt
193 | *.appx
194 |
195 | # Visual Studio cache files
196 | # files ending in .cache can be ignored
197 | *.[Cc]ache
198 | # but keep track of directories ending in .cache
199 | !*.[Cc]ache/
200 |
201 | # Others
202 | ClientBin/
203 | ~$*
204 | *~
205 | *.dbmdl
206 | *.dbproj.schemaview
207 | *.jfm
208 | *.pfx
209 | *.publishsettings
210 | orleans.codegen.cs
211 |
212 | # Since there are multiple workflows, uncomment next line to ignore bower_components
213 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
214 | #bower_components/
215 |
216 | # RIA/Silverlight projects
217 | Generated_Code/
218 |
219 | # Backup & report files from converting an old project file
220 | # to a newer Visual Studio version. Backup files are not needed,
221 | # because we have git ;-)
222 | _UpgradeReport_Files/
223 | Backup*/
224 | UpgradeLog*.XML
225 | UpgradeLog*.htm
226 |
227 | # SQL Server files
228 | *.mdf
229 | *.ldf
230 | *.ndf
231 |
232 | # Business Intelligence projects
233 | *.rdl.data
234 | *.bim.layout
235 | *.bim_*.settings
236 |
237 | # Microsoft Fakes
238 | FakesAssemblies/
239 |
240 | # GhostDoc plugin setting file
241 | *.GhostDoc.xml
242 |
243 | # Node.js Tools for Visual Studio
244 | .ntvs_analysis.dat
245 | node_modules/
246 |
247 | # Typescript v1 declaration files
248 | typings/
249 |
250 | # Visual Studio 6 build log
251 | *.plg
252 |
253 | # Visual Studio 6 workspace options file
254 | *.opt
255 |
256 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
257 | *.vbw
258 |
259 | # Visual Studio LightSwitch build output
260 | **/*.HTMLClient/GeneratedArtifacts
261 | **/*.DesktopClient/GeneratedArtifacts
262 | **/*.DesktopClient/ModelManifest.xml
263 | **/*.Server/GeneratedArtifacts
264 | **/*.Server/ModelManifest.xml
265 | _Pvt_Extensions
266 |
267 | # Paket dependency manager
268 | .paket/paket.exe
269 | paket-files/
270 |
271 | # FAKE - F# Make
272 | .fake/
273 |
274 | # JetBrains Rider
275 | .idea/
276 | *.sln.iml
277 |
278 | # CodeRush
279 | .cr/
280 |
281 | # Python Tools for Visual Studio (PTVS)
282 | __pycache__/
283 | *.pyc
284 |
285 | # Cake - Uncomment if you are using it
286 | # tools/**
287 | # !tools/packages.config
288 |
289 | # Tabs Studio
290 | *.tss
291 |
292 | # Telerik's JustMock configuration file
293 | *.jmconfig
294 |
295 | # BizTalk build output
296 | *.btp.cs
297 | *.btm.cs
298 | *.odx.cs
299 | *.xsd.cs
300 | *.db
301 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
13 |
16 |
17 |
18 |
19 |
20 |
21 | Community
22 | Professional
23 | Enterprise
24 |
25 |
26 |
27 |
28 | Install Recommended
29 | Install Optional
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 | To get information about each workload storage size please open the installer.
41 | Be advised selecting none workload will result to install ALL packages.
42 | First top workload (The core editor) must be included.
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 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
79 |
80 |
81 |
82 |
83 |
84 | (C) Wello Soft 2017. This is a third-party software and does not represent any of Microsoft Products. Fork me.
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/IsoWizard.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Windows;
4 | using System.Windows.Forms;
5 | using Path = System.IO.Path;
6 | using MessageBox = System.Windows.MessageBox;
7 | using IsoCreatorLib;
8 | using BER.CDCat.Export;
9 | using System.Threading;
10 | using System.Diagnostics;
11 |
12 | namespace Vs2017LIGUI
13 | {
14 | ///
15 | /// Interaction logic for IsoWizard.xaml
16 | ///
17 | public partial class IsoWizard : Window
18 | {
19 | public IsoWizard()
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | string batchtemplate;
25 | string batchproduct;
26 |
27 | Thread hotthread = null;
28 |
29 | public void Show(VSEdition template, Window parent)
30 | {
31 | _label.Text = "VS2017 " + template.Name;
32 | _batch.Text = "vs_" + template.Name + ".bat";
33 | template.GenerateCLIs();
34 | batchproduct = template.Name;
35 | batchtemplate = template.GeneratedInstall;
36 | Owner = parent;
37 | ShowDialog();
38 | }
39 |
40 | private void _hotbtn_Click(object sender, RoutedEventArgs e)
41 | {
42 | if (hotthread != null)
43 | {
44 | if (MessageBox.Show("Are you sure want to abort the operation?", "Confirmation", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
45 | hotthread?.Abort();
46 | }
47 | else
48 | StartJob(_layout.Text, _dest.Text, _label.Text);
49 | }
50 |
51 | private void _batchbtn_Click(object sender, RoutedEventArgs e)
52 | {
53 | if (!CheckValidity()) return;
54 |
55 | var path = Path.Combine(_layout.Text, _batch.Text);
56 | if (Path.GetExtension(path).ToLower() != ".bat") path += ".bat";
57 | File.WriteAllText(path, string.Format(BatContent, batchproduct, batchtemplate));
58 | if (MessageBox.Show("Batchfile has been written to " + path + "\r\nDo you want to start the installation?", "Succeed", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes)
59 | Process.Start(new ProcessStartInfo() {
60 | FileName = path,
61 | WorkingDirectory = _layout.Text
62 | });
63 | }
64 |
65 | private void _destbtn_Click(object sender, RoutedEventArgs e)
66 | {
67 | var dlg = new SaveFileDialog()
68 | {
69 | DefaultExt = "iso",
70 | FileName = _dest.Text,
71 | };
72 |
73 | if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
74 | {
75 | _dest.Text = dlg.FileName;
76 | }
77 |
78 | }
79 |
80 | private void _layoutbtn_Click(object sender, RoutedEventArgs e)
81 | {
82 | var dlg = new FolderBrowserDialog()
83 | {
84 | SelectedPath = _layout.Text,
85 | ShowNewFolderButton = true,
86 | };
87 | if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
88 | {
89 | _layout.Text = dlg.SelectedPath;
90 | }
91 | dlg.Dispose();
92 | }
93 |
94 | bool CheckValidity()
95 | {
96 | if (!IsValid(_dest.Text)) MessageBox.Show("Output ISO is not valid!", "", MessageBoxButton.OK, MessageBoxImage.Exclamation);
97 | else if (!IsValid(_batch.Text)) MessageBox.Show("Output Batchfile is not valid!", "", MessageBoxButton.OK, MessageBoxImage.Exclamation);
98 | else if (!IsValid(_layout.Text)) MessageBox.Show("Input Layout Directory is not valid!", "", MessageBoxButton.OK, MessageBoxImage.Exclamation);
99 | else return true;
100 | return false;
101 | }
102 |
103 | static bool IsValid(string path)
104 | {
105 | FileInfo fi = null;
106 | try
107 | {
108 | fi = new FileInfo(path);
109 | }
110 | catch (Exception) { }
111 |
112 | return fi != null;
113 | }
114 |
115 | void StartJob(string input, string output, string label)
116 | {
117 | var builder = new IsoCreator();
118 |
119 | builder.Progress += delegate (object sender, ProgressEventArgs e)
120 | {
121 | Dispatcher.Invoke(() =>
122 | {
123 | if (e.Maximum < 0)
124 | {
125 | if (e.Current >= _hotprog.Maximum)
126 | {
127 | // undetermined?
128 | _hottxt.Content = e.Action + " " + (e.Current).ToString("0");
129 | _hotprog.IsIndeterminate = true;
130 | } else
131 | {
132 | // use cache (weird?)
133 | _hottxt.Content = e.Action + " " + (e.Current / _hotprog.Maximum).ToString("P1");
134 | _hotprog.Value = e.Current;
135 | _hotprog.IsIndeterminate = false;
136 | }
137 | }
138 | else
139 | {
140 | _hottxt.Content = e.Action + " " + (e.Current / (double)e.Maximum).ToString("P1");
141 | _hotprog.Value = e.Current;
142 | _hotprog.Maximum = e.Maximum;
143 | _hotprog.IsIndeterminate = false;
144 | }
145 | });
146 | };
147 |
148 | builder.Abort += delegate (object sender, AbortEventArgs e)
149 | {
150 | Dispatcher.Invoke(() =>
151 | {
152 | _hottxt.Content = e.Message;
153 | _hotprog.Value = 0;
154 | _hotprog.Maximum = 1;
155 | _hotbtn.Content = "Start";
156 | _hotprog.IsIndeterminate = false;
157 | hotthread = null;
158 | });
159 | };
160 |
161 | builder.Finish += delegate (object sender, FinishEventArgs e)
162 | {
163 | Dispatcher.Invoke(() =>
164 | {
165 | _hottxt.Content = e.Message;
166 | _hotprog.Value = 1;
167 | _hotprog.Maximum = 1;
168 | _hotprog.IsIndeterminate = false;
169 | _hotbtn.Content = "Start";
170 | hotthread = null;
171 | });
172 | };
173 |
174 | _hotbtn.Content = "Abort";
175 |
176 | hotthread = new Thread(new ParameterizedThreadStart(builder.Folder2Iso));
177 | hotthread.IsBackground = true;
178 | hotthread.Start(new IsoCreator.IsoCreatorFolderArgs(input, output, label));
179 | }
180 |
181 | const string BatContent = @"@echo off
182 | REM Generated using github.com/willnode/Vs2017-LayoutInGUI
183 | REM This batch file will install certificates then launch VS installer with appopriate offline arguments
184 | echo:
185 | echo Welcome to Visual Studio {0} Offline Installation
186 | echo:
187 | echo Before installation begin, we need to install certificates first.
188 | echo:
189 | echo The process is not automatic. By pressing enter, we'll lauch three certificates and
190 | echo it's your job to next-clicking them until all wizards finished.
191 | pause>nul
192 | echo:
193 | echo Launching certificates ...
194 | forfiles /S /M *.p12 /C ""cmd /c explorer @file""
195 | echo Do not press enter until all certificates has been installed.
196 | pause>nul
197 | echo Enter again to start installation..
198 | pause>nul
199 | echo Launching Vs 2017 Offline Installation....
200 | {1}
201 | echo Installation will start soon. Hang tight :)
202 | timeout 5>nul
203 | ";
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/Vs2017-LIGUI/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Net;
7 | using System.Windows;
8 | using System.Windows.Controls;
9 | using System.Windows.Data;
10 | using System.Windows.Navigation;
11 | using System.Linq;
12 |
13 | namespace Vs2017LIGUI
14 | {
15 | ///
16 | /// Interaction logic for MainWindow.xaml
17 | ///
18 | public partial class MainWindow : Window
19 | {
20 |
21 | public string[] languages = new string[]
22 | {
23 | "cs-CZ",
24 | "de-DE",
25 | "en-US",
26 | "es-ES",
27 | "fr-FR",
28 | "it-IT",
29 | "ja-JP",
30 | "ko-KR",
31 | "pl-PL",
32 | "pt-BR",
33 | "ru-RU",
34 | "tr-TR",
35 | "zh-CN",
36 | "zh-TW",
37 | };
38 |
39 | public VSEdition[] editions = new VSEdition[]
40 | {
41 | new VSEdition() {
42 | Name = "Community",
43 | DownloadExe = "https://aka.ms/vs/15/release/vs_community.exe",
44 | WorkloadDoc = "https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-community",
45 | WorkloadRaw = "https://raw.githubusercontent.com/MicrosoftDocs/visualstudio-docs/master/docs/install/workload-component-id-vs-community.md",
46 | },
47 |
48 | new VSEdition() {
49 | Name = "Professional",
50 | DownloadExe = "https://aka.ms/vs/15/release/vs_professional.exe",
51 | WorkloadDoc = "https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-professional",
52 | WorkloadRaw = "https://raw.githubusercontent.com/MicrosoftDocs/visualstudio-docs/master/docs/install/workload-component-id-vs-professional.md",
53 | },
54 |
55 | new VSEdition() {
56 | Name = "Enterprise",
57 | DownloadExe = "https://aka.ms/vs/15/release/vs_enterprise.exe",
58 | WorkloadDoc = "https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-enterprise",
59 | WorkloadRaw = "https://raw.githubusercontent.com/MicrosoftDocs/visualstudio-docs/master/docs/install/workload-component-id-vs-enterprise.md",
60 | },
61 | };
62 |
63 | public VSEdition ActiveEdition;
64 |
65 | public DocProcesser Processor = new DocProcesser();
66 |
67 | public MainWindow()
68 | {
69 | InitializeComponent();
70 | ActiveEdition = editions[0];
71 | ActiveEdition.LoadJSON();
72 | RebuildWorkload();
73 | PrintFetchStamp();
74 | _ed0.IsChecked = true;
75 | _lang.ItemsSource = languages;
76 | _lang.SelectedItem = "en-US";
77 | }
78 |
79 | private void _fetch_Click(object sender, RoutedEventArgs e)
80 | {
81 | string x = null;
82 | try
83 | {
84 | x = new WebClient().DownloadString(ActiveEdition.WorkloadRaw);
85 |
86 | }
87 | catch (Exception ex)
88 | {
89 | MessageBox.Show("An " + ex.GetType().ToString() + " When fetching URL. Is Internet OK?", "", MessageBoxButton.OK, MessageBoxImage.Error);
90 | return;
91 | }
92 | Processor.Process(x, ActiveEdition.metadata.Workloads);
93 | RebuildWorkload();
94 | ActiveEdition.SaveJSON();
95 | PrintFetchStamp();
96 | }
97 |
98 | private void _param_change(object sender, RoutedEventArgs e)
99 | {
100 | RebuildWorkload();
101 |
102 |
103 | BuildCLIOut();
104 | }
105 |
106 | private void _pkg_Changed(object sender, RoutedEventArgs e)
107 | {
108 | ComponentSettings.UseOptional = _pkgopt.IsChecked ?? false;
109 | ComponentSettings.UseRecommended = _pkgrec.IsChecked ?? false;
110 |
111 | RebuildWorkload();
112 | BuildCLIOut();
113 | }
114 |
115 | private void _lang_SelectionChanged(object sender, SelectionChangedEventArgs e)
116 | {
117 | ComponentSettings.Lang = (string)_lang.SelectedValue;
118 | BuildCLIOut();
119 | }
120 |
121 | public void RebuildWorkload()
122 | {
123 | // well, must be a better way to do this ...
124 |
125 | _workloads.SetBinding(ItemsControl.ItemsSourceProperty, "");
126 | _workloads.SetBinding(ItemsControl.ItemsSourceProperty, new Binding()
127 | {
128 | Source = ActiveEdition.metadata.Workloads,
129 | Mode = BindingMode.Default,
130 |
131 | UpdateSourceTrigger = UpdateSourceTrigger.Default
132 | });
133 | }
134 |
135 | public void BuildCLIOut()
136 | {
137 | ActiveEdition.GenerateCLIs();
138 | _clidown.Text = ActiveEdition.GeneratedFetch;
139 | _cliinst.Text = ActiveEdition.GeneratedInstall;
140 |
141 | }
142 |
143 | public void PrintFetchStamp()
144 | {
145 | _fetch.Content = ActiveEdition.metadata.Workloads.Count == 0 ? "Fetch Layout Info" : "Fetch Layout Info ( last update: " + ActiveEdition.metadata.FetchTime.ToShortDateString() + " )";
146 |
147 | }
148 |
149 | private void _edition_change(object sender, RoutedEventArgs e)
150 | {
151 | if (_ed0.IsChecked == true)
152 | ActiveEdition = editions[0];
153 | if (_ed1.IsChecked == true)
154 | ActiveEdition = editions[1];
155 | if (_ed2.IsChecked == true)
156 | ActiveEdition = editions[2];
157 | ActiveEdition.LoadJSON();
158 | RebuildWorkload();
159 | PrintFetchStamp();
160 | BuildCLIOut();
161 | }
162 |
163 | private void _manual_click(object sender, RoutedEventArgs e)
164 | {
165 | Process.Start("https://docs.microsoft.com/en-us/visualstudio/install/install-vs-inconsistent-quality-network");
166 | }
167 |
168 | private void _opwiz_Click(object sender, RoutedEventArgs e)
169 | {
170 | new IsoWizard().Show(ActiveEdition, this);
171 | }
172 |
173 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
174 | {
175 | Process.Start(e.Uri.AbsoluteUri);
176 | e.Handled = true;
177 | }
178 |
179 | private void _workloads_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
180 | {
181 | e.Handled = true;
182 | _app.ScrollToVerticalOffset(_app.VerticalOffset - e.Delta * 0.5);
183 | }
184 | }
185 |
186 |
187 |
188 | public class VSEdition
189 | {
190 | public string Name;
191 | public string WorkloadRaw;
192 | public string WorkloadDoc;
193 | public string DownloadExe;
194 |
195 | public Metadata metadata = new Metadata();
196 |
197 | public string GeneratedFetch, GeneratedInstall;
198 |
199 | public void LoadJSON()
200 | {
201 | var path = Environment.CurrentDirectory + "/" + Name + ".json";
202 | if (File.Exists(path))
203 | metadata = JsonConvert.DeserializeObject(File.ReadAllText(path));
204 |
205 | // sync existing tree
206 | foreach (var load in metadata.Workloads)
207 | foreach (var comp in load.Components)
208 | comp.TheWorkload = load;
209 |
210 | }
211 |
212 | public void SaveJSON()
213 | {
214 | metadata.FetchTime = DateTime.Now;
215 | var path = Environment.CurrentDirectory + "/" + Name + ".json";
216 | File.WriteAllText(path, JsonConvert.SerializeObject(metadata, Formatting.Indented));
217 | }
218 |
219 | public void GenerateCLIs()
220 | {
221 | var exe = "vs_" + Name + ".exe ";
222 | var layout = "--layout C:\\vs2017Layout ";
223 | var body = new List();
224 | var foot = "";
225 | var lang = "--lang " + ComponentSettings.Lang;
226 | foreach (var loads in metadata.Workloads)
227 | {
228 | if (!string.IsNullOrEmpty(loads.ID) && loads.Selected)
229 | body.Add("--add " + loads.ID + " ");
230 |
231 | foreach (var comp in loads.Components)
232 | if (comp.SelfSelected && !comp.SelectedFromWorkload())
233 | body.Add("--add " + comp.ID + " ");
234 | }
235 |
236 | if (ComponentSettings.UseRecommended)
237 | foot = "--includeRecommended " + foot;
238 |
239 | if (ComponentSettings.UseOptional)
240 | foot = "--includeOptional " + foot;
241 |
242 | var bodystr = string.Join("", body.Distinct());
243 | GeneratedFetch = (exe + layout + bodystr + foot + lang).Replace(" ", " ");
244 | GeneratedInstall = exe + bodystr + foot + (Name == "Enterprise" ? "--noWeb" : "");
245 | }
246 |
247 |
248 | }
249 |
250 | public class Metadata
251 | {
252 | public DateTime FetchTime;
253 | public List Workloads = new List();
254 | }
255 | }
256 |
--------------------------------------------------------------------------------