-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfrmMain.cs
288 lines (264 loc) · 13.4 KB
/
frmMain.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
61
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CheckPowerShell
{
public partial class frmMain : Form
{
private VersionInfo winVer;//Current windows version
private Dictionary<string, VersionInfo> WindowsVersions;
private bool net45Installed;
private VersionInfo netVersion;
private VersionInfo maxVerNet; //Maximum version of NETFX for this Windows
private const string psVersionCurrent = "7.4.2";
//double verWindowsMin =
public frmMain()
{
InitializeComponent();
}
private void frmMain_Load(object sender, EventArgs e)
{
winVer = new VersionInfo(Environment.OSVersion.Version);
//Minimal version for 4.5 is Windows Server 2008 SP2 and Windows Vista SP2
WindowsVersions = new Dictionary<string, VersionInfo>();
WindowsVersions.Add("win2008r2", new VersionInfo(6,1,0,0));//Windows 7 and Server 2008 R2
WindowsVersions.Add("win2008sp2", new VersionInfo(6,0,6002, 0));//Windows Vista SP2 and 2008 SP2
WindowsVersions.Add("win8", new VersionInfo(6,2));//Windows 8 and Windows Server 2012
WindowsVersions.Add("win81", new VersionInfo(6,3));//Windows 8.1, Windows Server 2012 R2, 6.3.9200. Update 1 is 6.3.9600
WindowsVersions.Add("win10", new VersionInfo("10.0.10240")); //Windows 10, first release
WindowsVersions.Add("win2016", new VersionInfo("10.0.1607.14393"));//Windows Server 2016 RTM
WindowsVersions.Add("win2019", new VersionInfo("10.0.1809.17763"));//Windows Server 2019 LTSC
string explanation = "";
if (winVer.LesserThan(WindowsVersions["win2008sp2"]))
{
MessageBox.Show("This application works for Windows Server 2008 R2 / Windows 7 and up. It appears that your operating system is older than that. Note, that minimum version required for PowerShell 7 / .NET Framework 4.5 is Windows Server 2008 SP2 / Windows Vista SP2.", "Windows version outdated", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
lblExplanation.Text = "Your Windows version is too old for this application.";
return;
}
//Check version of PowerShell
VersionInfo psVersion = null;
//1. Do we have PS7 and up?
bool newPSInstalled = RegHelper.BranchExists(@"SOFTWARE\Microsoft\PowerShellCore\InstalledVersions");
bool oldPSInstalled = RegHelper.BranchExists(@"SOFTWARE\Microsoft\PowerShell");
if (!newPSInstalled)
{
cmdUpgradePS.Enabled = true;
explanation += "New version of PowerShell was not found.";
//Check for version of old powershell
if (!oldPSInstalled)
{
explanation += " Old version of PowerShell wasn't found either.";
} else
{
if (RegHelper.BranchExists(@"SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine"))
{
psVersion = new VersionInfo(RegHelper.GetSettingStringEx(@"SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine", "PowerShellVersion"));
}
else if (RegHelper.BranchExists(@"SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine"))
{
psVersion = new VersionInfo(RegHelper.GetSettingStringEx(@"SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine", "PowerShellVersion"));
}
}
} else
{//We have new PS installed. Hurray!
psVersion = new VersionInfo(RegHelper.GetSettingStringEx(@"SOFTWARE\Microsoft\PowerShellCore\InstalledVersions\31ab5147-9a97-4452-8443-d9709f0516e1","SemanticVersion"));
explanation = "New version of PowerShell detected, update is not required.";
}
if (psVersion != null) lblVerPS.Text = psVersion.ToString();
//Check version of .NET Framework
net45Installed = RegHelper.BranchExists(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full");
if (!net45Installed)
{
explanation += " No .NET Framework 4.5 or higher is installed. This is prerequisite for PowerShell 7.";
//Since we don't have 4.5, perhaps we can install better one? Minimum for 4.5 is 7SP2, 4.6 is maximum for Vista/Win2008, 4.6.1 maximum for Win8, but not for Win7. Others can take everything
maxVerNet = new VersionInfo("4.7.2");
//if (VersionInfo.Equals(winVer, WindowsVersions["win2008sp2"])) maxVerNet.
} else
{
//Ok, what version do we have?
string netVersionID = RegHelper.GetSettingStringEx(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", "Version");
netVersion = new VersionInfo(netVersionID);
lblVerNET.Text = netVersionID;
explanation += " .NET Framework version is compatible with latest version of PowerShell.";
}
//Color code versions
ColourLabelVersion("4.5", "4.7.2", netVersion, ref lblVerNET);
//PS
ColourLabelVersion("5.1", psVersionCurrent, psVersion, ref lblVerPS);
//Display update buttons?
if (lblVerPS.ForeColor != Color.DarkGreen && net45Installed) cmdUpgradePS.Visible = true;
if (lblVerNET.ForeColor != Color.DarkGreen) cmdUpgradeNET.Visible = true;
//WMF?
if ((psVersion == null || psVersion.Major < 4) && winVer.LesserThan(WindowsVersions["win2016"]))
{
cmdWMF.Visible = true;
}
lblExplanation.Text = explanation;
//Execution policy
lblExPolValue.Text = GetPSPolicy();
}
private void ColourLabelVersion(string minVersion, string goodVersion, VersionInfo actualVersion, ref Label targetControl)
{
if (actualVersion.BetterOrEqual(minVersion)) targetControl.ForeColor = Color.DarkOrange;
else targetControl.ForeColor = Color.DarkRed;
if (actualVersion.BetterOrEqual(goodVersion)) targetControl.ForeColor = Color.DarkGreen;
}
private void cmdUpgradePS_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
string psSetupFile = $@"PowerShell-{psVersionCurrent}-win-x64.msi";
string psLink = $@"https://github.com/PowerShell/PowerShell/releases/download/v{psVersionCurrent}/PowerShell-{psVersionCurrent}-win-x64.msi";
//Detect local file
try
{
string setupFile = GetLocalFile(psSetupFile, psLink);
if (String.IsNullOrEmpty(setupFile)) return;
//Execute local file
//msiexec.exe /i file.msi /passive
RunMSI(setupFile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
private bool RunMSI(string setupFile)
{
string arg = setupFile;
if (setupFile.Contains(" ")) arg = "\"" + setupFile + "\"";
var cmd = new Command
{
Line = "msiexec.exe",
Arguments = $"-i {arg} -passive",
Shell = false,
Wait = false,
UI = ProcessWindowStyle.Normal
};
var result = (cmd.Execute() > 0);//this is process ID
if (result)
{
MessageBox.Show("Setup has started. Please wait for it to end, then restart this application, if further installations needed.\nIt may take a few minutes to complete installation.", "Setup started", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return result;
}
private string GetLocalFile(string fileName, string url)
{
//Do we have this file next to executable?
var appDir = GetAppDir();
bool isNetwork = PathIsNetworkPath(appDir);
var fullFileName = Path.Combine(appDir, fileName);
if (File.Exists(fullFileName) &! isNetwork) return fullFileName;
var tmpFileName = Path.Combine(Path.GetTempPath(), fileName);
if (File.Exists(tmpFileName)) return tmpFileName;//Already downloaded
//Are we running from network location? Then copy file to temporary directory locally... If that file doesn't exist here yet
if (File.Exists(fullFileName) && isNetwork)
{
File.Copy(fullFileName, tmpFileName);
return tmpFileName;
}
if (String.IsNullOrEmpty(url))
{
MessageBox.Show($"Couldn't find file {fileName} in {appDir} and don't know the url for it. Can't proceed.", "File not found", MessageBoxButtons.OK);
return "";
}
//If file doesn't exist - let's download it. Check that we have at least 200Mb free space on temp drive.
var sure = AskUser($"We couldn't find file {fileName} in {appDir}, but we can download it from {url}. Would you like to proceed with download and execution of that file? This might take some time.\n\nOtherwise you can copy required file to {fullFileName}");
if (sure != DialogResult.Yes) return "";
//Download the file
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
using (var client = new WebClient())
{
client.DownloadFile(url, tmpFileName);
}
if (!File.Exists(tmpFileName))
{
MessageBox.Show($"Error downloading file from {url}", "File not downloaded", MessageBoxButtons.OK, MessageBoxIcon.Error);
return "";
}
return tmpFileName;
}
internal DialogResult AskUser(string question, string title = "Confirmation")
{
return (MessageBox.Show(question, title, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1));
}
internal static string GetAppDir()
{
var ass = Assembly.GetEntryAssembly();
return ass == null ? "" : Path.GetDirectoryName (ass.Location);
}
[DllImport("shlwapi.dll")]
private static extern bool PathIsNetworkPath(string pszPath);
private void cmdUpgradeNET_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
string psSetupFile = @"NDP472-KB4054531-Web.exe";
string psLink = @"http://go.microsoft.com/fwlink/?LinkId=863262";
//Detect local file
try
{
string setupFile = GetLocalFile(psSetupFile, psLink);
if (String.IsNullOrEmpty(setupFile)) return;
//Execute local file
//msiexec.exe /i file.msi /passive
RunEXE(setupFile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
private void RunEXE(string setupFile)
{
//string arg = setupFile;
//if (setupFile.Contains(" ")) arg = "\"" + setupFile + "\"";
var cmd = new Command
{
Line = setupFile,
Arguments = $"/passive /showrmui /promptrestart",
Shell = false,
Wait = false,
UI = ProcessWindowStyle.Normal
};
var result = (cmd.Execute() > 0);//this is process ID
if (result)
{
MessageBox.Show("Setup has started. Please wait for it to end, then restart this application, if further installations needed.\nIt may take a few minutes to complete installation.", "Setup started", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return;
}
private void cmdWMF_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var cmd = new Command();
cmd.Line = "https://www.microsoft.com/en-us/download/details.aspx?id=54616";
cmd.Shell = true;
cmd.Execute();
}
private string GetPSPolicy()
{
try
{
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell");
if (key == null) return "Unknown";//Probably not installed
string executionPolicy = key.GetValue("ExecutionPolicy").ToString();
//if (executionPolicy == "Restricted" || executionPolicy == "AllSigned") return true;
return executionPolicy;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
return "Unknown";
}
}
}