Skip to content

Commit fe2bcfc

Browse files
committed
Implement Windows updates warnings and refactor Issues.
1 parent c8dd47a commit fe2bcfc

File tree

4 files changed

+242
-78
lines changed

4 files changed

+242
-78
lines changed

Protest/Tasks/Issues.cs

Lines changed: 28 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
using Protest.Http;
2-
using Protest.Protocols;
3-
using Protest.Tools;
4-
using System.Collections.Concurrent;
1+
using System.Collections.Concurrent;
52
using System.Collections.Generic;
63
using System.DirectoryServices;
74
using System.Net;
85
using System.Net.WebSockets;
6+
using System.Runtime.InteropServices;
97
using System.Runtime.Versioning;
108
using System.Text;
119
using System.Text.Json;
1210
using System.Text.RegularExpressions;
1311
using System.Threading;
1412
using System.Threading.Tasks;
13+
using Protest.Http;
14+
using Protest.Protocols;
15+
using Protest.Tools;
1516

1617
namespace Protest.Tasks;
1718

@@ -228,38 +229,45 @@ public static void ScanDevice(Database.Entry device) {
228229
issues.Add(issue.Value);
229230
}
230231

231-
if (CheckWindowsLifecycle(device, out Issue? lifecycleIssue) && lifecycleIssue.HasValue) {
232-
issues.Add(lifecycleIssue.Value);
233-
}
234-
235232
if (osAttribute?.value.Contains("windows", StringComparison.OrdinalIgnoreCase) == true) {
236233
string ipString = null;
237234
if (device.attributes.TryGetValue("ip", out Database.Attribute ip) && !String.IsNullOrEmpty(ip?.value)) {
238235
ipString = ip.value.Split(';').Select(o => o.Trim()).ToArray()[0];
239236
}
240237

241-
if (CheckCpu(device, ipString, out Issue ? cpuIssue)) {
238+
if (CheckCpuLifeline(device, ipString, out Issue ? cpuIssue)) {
242239
issues.Add(cpuIssue.Value);
243240
}
244241

245-
if (CheckMemory(device, ipString, out Issue? memoryIssue)) {
242+
if (CheckMemoryLifeline(device, ipString, out Issue? memoryIssue)) {
246243
issues.Add(memoryIssue.Value);
247244
}
248245

249-
if (CheckDiskSpace(device, ipString, out Issue[] diskIssues) && diskIssues is not null) {
246+
if (CheckDiskSpaceLifeline(device, ipString, out Issue[] diskIssues) && diskIssues is not null) {
250247
for (int i = 0; i < diskIssues.Length; i++) {
251248
issues.Add(diskIssues[i]);
252249
}
253250
}
254251

255-
if (CheckDiskIO(device, ipString, out Issue? diskIoIssue)) {
252+
if (CheckDiskIOLifeline(device, ipString, out Issue? diskIoIssue)) {
256253
issues.Add(diskIoIssue.Value);
257254
}
258255

259256
if (CheckNicSpeed(device, ipString, out Issue ? nicSpeedIssue)) {
260257
issues.Add(nicSpeedIssue.Value);
261258
}
262259

260+
if (OperatingSystem.IsWindows()) {
261+
if (WindowsLifecycle.CheckEntry(device, out Issue? lifecycleIssue) && lifecycleIssue.HasValue) {
262+
issues.Add(lifecycleIssue.Value);
263+
}
264+
265+
if (WindowsUpdate.CheckEntry(device, out List<Issue?> osUpdateIssues)) {
266+
for (int i = 0; i < osUpdateIssues.Count; i++) {
267+
issues.Add(osUpdateIssues[i].Value);
268+
}
269+
}
270+
}
263271

264272
}
265273
else if (Data.PRINTER_TYPES.Contains(typeAttribute?.value, StringComparer.OrdinalIgnoreCase)) {
@@ -415,7 +423,7 @@ public static bool CheckRtt(Database.Entry device, string host, out Issue? issue
415423
return false;
416424
}
417425

418-
public static bool CheckCpu(Database.Entry device, string host, out Issue? issue) {
426+
public static bool CheckCpuLifeline(Database.Entry device, string host, out Issue? issue) {
419427
byte[] lifeline = Lifeline.LoadFile(device.filename, 3, "cpu");
420428

421429
if (lifeline is null || lifeline.Length < 9 * MIN_LIFELINE_ENTRIES) {
@@ -463,7 +471,7 @@ public static bool CheckCpu(Database.Entry device, string host, out Issue? issue
463471
name = nameAttribute?.value ?? String.Empty,
464472
identifier = host,
465473
category = "CPU utilization",
466-
source = "WMI",
474+
source = "Lifeline",
467475
file = device.filename,
468476
isUser = false,
469477
};
@@ -474,7 +482,7 @@ public static bool CheckCpu(Database.Entry device, string host, out Issue? issue
474482
return false;
475483
}
476484

477-
public static bool CheckMemory(Database.Entry device, string host, out Issue? issue) {
485+
public static bool CheckMemoryLifeline(Database.Entry device, string host, out Issue? issue) {
478486
byte[] lifeline = Lifeline.LoadFile(device.filename, 3, "memory");
479487

480488
if (lifeline is null || lifeline.Length < 24 * MIN_LIFELINE_ENTRIES) {
@@ -529,7 +537,7 @@ public static bool CheckMemory(Database.Entry device, string host, out Issue? is
529537
name = nameAttribute?.value ?? String.Empty,
530538
identifier = host,
531539
category = "Memory usage",
532-
source = "WMI",
540+
source = "Lifeline",
533541
file = device.filename,
534542
isUser = false,
535543
};
@@ -540,7 +548,7 @@ public static bool CheckMemory(Database.Entry device, string host, out Issue? is
540548
return false;
541549
}
542550

543-
public static bool CheckDiskSpace(Database.Entry device, string host, out Issue[] issues) {
551+
public static bool CheckDiskSpaceLifeline(Database.Entry device, string host, out Issue[] issues) {
544552
byte[] lifeline = Lifeline.ViewFile(device.filename, DateTime.Now.ToString("yyyyMM"), "disk");
545553

546554
if (lifeline is null || lifeline.Length <= 12 + 17 * MIN_LIFELINE_ENTRIES) {
@@ -637,7 +645,7 @@ public static bool CheckDiskSpace(Database.Entry device, string host, out Issue[
637645
name = nameAttribute?.value ?? String.Empty,
638646
identifier = host,
639647
category = "Disk space",
640-
source = "WMI",
648+
source = "Lifeline",
641649
file = device.filename,
642650
isUser = false,
643651
});
@@ -653,7 +661,7 @@ public static bool CheckDiskSpace(Database.Entry device, string host, out Issue[
653661
return false;
654662
}
655663

656-
public static bool CheckDiskIO(Database.Entry device, string host, out Issue? issue) {
664+
public static bool CheckDiskIOLifeline(Database.Entry device, string host, out Issue? issue) {
657665
byte[] lifeline = Lifeline.LoadFile(device.filename, 3, "diskio");
658666

659667
if (lifeline is null || lifeline.Length < 9 * MIN_LIFELINE_ENTRIES) {
@@ -701,7 +709,7 @@ public static bool CheckDiskIO(Database.Entry device, string host, out Issue? is
701709
name = nameAttribute?.value ?? String.Empty,
702710
identifier = host,
703711
category = "Disk I/O",
704-
source = "WMI",
712+
source = "Lifeline",
705713
file = device.filename,
706714
isUser = false,
707715
};
@@ -958,62 +966,6 @@ public static bool CheckPasswordStrength(Database.Entry entry, bool isUser, out
958966
return false;
959967
}
960968

961-
public static bool CheckWindowsLifecycle(Database.Entry device, out Issue? issue) {
962-
issue = null;
963-
964-
if (device is null) {
965-
return false;
966-
}
967-
968-
device.attributes.TryGetValue("operating system", out Database.Attribute osAttribute);
969-
device.attributes.TryGetValue("os version", out Database.Attribute osVersionAttribute);
970-
971-
if (!WindowsLifecycle.TryAssess(osAttribute?.value, osVersionAttribute?.value, out WindowsLifecycle.Assessment assessment)) {
972-
return false;
973-
}
974-
975-
if (assessment.state != WindowsLifecycle.SupportState.expiringSoon
976-
&& assessment.state != WindowsLifecycle.SupportState.outOfSupport) {
977-
return false;
978-
}
979-
980-
device.attributes.TryGetValue("name", out Database.Attribute nameAttribute);
981-
982-
string osName = assessment.productName.Contains(assessment.release, StringComparison.OrdinalIgnoreCase)
983-
? assessment.productName
984-
: $"{assessment.productName} {assessment.release}";
985-
986-
string message = assessment.state == WindowsLifecycle.SupportState.outOfSupport
987-
? $"{osName} ({assessment.version}) has reached EOS"
988-
: $"{osName} ({assessment.version}) reaches EOS on {assessment.endOfSupport:yyyy-MM-dd} ({assessment.daysLeft} days left)";
989-
990-
string ipString = string.Empty;
991-
if (device.attributes.TryGetValue("ip", out Database.Attribute ip) && !String.IsNullOrEmpty(ip?.value)) {
992-
ipString = ip.value.Split(';').Select(o => o.Trim()).ToArray()[0];
993-
}
994-
995-
Issues.SeverityLevel severity;
996-
if (assessment.state == WindowsLifecycle.SupportState.outOfSupport) {
997-
severity = SeverityLevel.critical;
998-
}
999-
else {
1000-
severity = assessment.daysLeft < 30 ? SeverityLevel.error : SeverityLevel.warning;
1001-
}
1002-
1003-
issue = new Issue {
1004-
severity = severity,
1005-
message = message,
1006-
name = nameAttribute?.value ?? String.Empty,
1007-
identifier = ipString,
1008-
category = "Operating system",
1009-
source = "Record",
1010-
file = device.filename,
1011-
isUser = false
1012-
};
1013-
1014-
return true;
1015-
}
1016-
1017969
public static bool CheckDiskSpace(string file, string target, double percent, string diskCaption, out Issue? issue) {
1018970
string message = $"{Math.Round(percent, 1)}% free space on disk {Data.EscapeJsonText(diskCaption)}:";
1019971

Protest/Tools/LiveStats.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public static async void DeviceStats(HttpListenerContext ctx) {
132132

133133
Lock mutex = new Lock();
134134

135-
if (Issues.CheckWindowsLifecycle(entry, out Issues.Issue? windowsLifecycleIssue) && windowsLifecycleIssue.HasValue) {
135+
if (WindowsLifecycle.CheckEntry(entry, out Issues.Issue? windowsLifecycleIssue) && windowsLifecycleIssue.HasValue) {
136136
WsWriteText(ws, windowsLifecycleIssue.Value.ToLiveStatsJsonBytes(), mutex);
137137
}
138138

Protest/Tools/WindowsLifecycle.cs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Protest.Tasks;
2+
13
namespace Protest.Tools;
24

35
internal static class WindowsLifecycle {
@@ -75,7 +77,63 @@ private static readonly (string product, int build, DateOnly extendedEnd)[] wind
7577
("Windows Server 2025", 26100, new DateOnly(2034, 11, 14)),
7678
};
7779

78-
public static bool TryAssess(string osName, string osVersion, out Assessment assessment) {
80+
internal static bool CheckEntry(Database.Entry device, out Issues.Issue? issue) {
81+
issue = null;
82+
83+
if (device is null) {
84+
return false;
85+
}
86+
87+
device.attributes.TryGetValue("operating system", out Database.Attribute osAttribute);
88+
device.attributes.TryGetValue("os version", out Database.Attribute osVersionAttribute);
89+
90+
if (!WindowsLifecycle.TryAssess(osAttribute?.value, osVersionAttribute?.value, out WindowsLifecycle.Assessment assessment)) {
91+
return false;
92+
}
93+
94+
if (assessment.state != WindowsLifecycle.SupportState.expiringSoon
95+
&& assessment.state != WindowsLifecycle.SupportState.outOfSupport) {
96+
return false;
97+
}
98+
99+
device.attributes.TryGetValue("name", out Database.Attribute nameAttribute);
100+
101+
string osName = assessment.productName.Contains(assessment.release, StringComparison.OrdinalIgnoreCase)
102+
? assessment.productName
103+
: $"{assessment.productName} {assessment.release}";
104+
105+
string message = assessment.state == WindowsLifecycle.SupportState.outOfSupport
106+
? $"{osName} ({assessment.version}) has reached EOS"
107+
: $"{osName} ({assessment.version}) reaches EOS on {assessment.endOfSupport:yyyy-MM-dd} ({assessment.daysLeft} days left)";
108+
109+
string ipString = string.Empty;
110+
if (device.attributes.TryGetValue("ip", out Database.Attribute ip) && !String.IsNullOrEmpty(ip?.value)) {
111+
ipString = ip.value.Split(';').Select(o => o.Trim()).ToArray()[0];
112+
}
113+
114+
Issues.SeverityLevel severity;
115+
if (assessment.state == WindowsLifecycle.SupportState.outOfSupport) {
116+
severity = Issues.SeverityLevel.critical;
117+
}
118+
else {
119+
severity = assessment.daysLeft < 30 ? Issues.SeverityLevel.error : Issues.SeverityLevel.warning;
120+
}
121+
122+
issue = new Issues.Issue {
123+
severity = severity,
124+
message = message,
125+
name = nameAttribute?.value ?? String.Empty,
126+
identifier = ipString,
127+
category = "Operating system",
128+
source = "Record",
129+
file = device.filename,
130+
isUser = false
131+
};
132+
133+
return true;
134+
}
135+
136+
private static bool TryAssess(string osName, string osVersion, out Assessment assessment) {
79137
assessment = default;
80138

81139
if (String.IsNullOrWhiteSpace(osName) || !osName.Contains("windows", StringComparison.OrdinalIgnoreCase)) {

0 commit comments

Comments
 (0)