From 9d98785fb7e54794464b76896a4282ad8d605aa4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 16:42:55 +0000 Subject: [PATCH 1/4] Fix IP scanner export NullReferenceException and CSV format bug (#3290) * Initial plan * Fix IP scanner export issues - add null checks and fix CSV comma bug Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Address code review - use empty enumerable instead of null for XML ports Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Optimize JSON export - use Array.Empty for null/empty ports Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Docs: #3290 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../Export/ExportManager.IPScannerHostInfo.cs | 140 ++++++++++-------- Website/docs/changelog/next-release.md | 2 + 2 files changed, 82 insertions(+), 60 deletions(-) diff --git a/Source/NETworkManager.Models/Export/ExportManager.IPScannerHostInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.IPScannerHostInfo.cs index cf29ec38e0..ee73c15f40 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.IPScannerHostInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.IPScannerHostInfo.cs @@ -55,7 +55,7 @@ private static void CreateCsv(IEnumerable collection, string $"{nameof(PingInfo.Timestamp)}," + $"{nameof(PingInfo.Time)}," + $"{nameof(PingInfo.TTL)}," + - $"{nameof(PingInfo.Bytes)}" + + $"{nameof(PingInfo.Bytes)}," + $"PortStatus," + $"{nameof(IPScannerHostInfo.Ports)}," + $"NetBIOSIsReachable," + @@ -73,11 +73,18 @@ private static void CreateCsv(IEnumerable collection, string foreach (var info in collection) { + // Skip if critical data is null + if (info?.PingInfo == null) + continue; + var stringBuilderPorts = new StringBuilder(); - foreach (var port in info.Ports) - stringBuilderPorts.Append( - $"{port.Port}/{port.LookupInfo.Protocol}/{port.LookupInfo.Service}/{port.LookupInfo.Description}/{port.State};"); + if (info.Ports != null) + { + foreach (var port in info.Ports) + stringBuilderPorts.Append( + $"{port.Port}/{port.LookupInfo.Protocol}/{port.LookupInfo.Service}/{port.LookupInfo.Description}/{port.State};"); + } stringBuilder.AppendLine( $"{info.IsReachable}," + @@ -87,16 +94,16 @@ private static void CreateCsv(IEnumerable collection, string $"{DateTimeHelper.DateTimeToFullDateTimeString(info.PingInfo.Timestamp)}," + $"{Ping.TimeToString(info.PingInfo.Status, info.PingInfo.Time, true)}," + $"{info.PingInfo.TTL}," + - $"{info.PingInfo.Bytes}" + + $"{info.PingInfo.Bytes}," + $"{(info.IsAnyPortOpen ? PortState.Open : PortState.Closed)}," + $"\"{stringBuilderPorts.ToString().TrimEnd(';')}\"," + - $"{info.NetBIOSInfo.IsReachable}," + - $"{info.NetBIOSInfo.IPAddress}," + - $"{info.NetBIOSInfo.ComputerName}," + - $"{info.NetBIOSInfo.UserName}," + - $"{info.NetBIOSInfo.GroupName}," + - $"{info.NetBIOSInfo.MACAddress}," + - $"{info.NetBIOSInfo.Vendor}," + + $"{info.NetBIOSInfo?.IsReachable}," + + $"{info.NetBIOSInfo?.IPAddress}," + + $"{info.NetBIOSInfo?.ComputerName}," + + $"{info.NetBIOSInfo?.UserName}," + + $"{info.NetBIOSInfo?.GroupName}," + + $"{info.NetBIOSInfo?.MACAddress}," + + $"{info.NetBIOSInfo?.Vendor}," + $"{info.MACAddress}," + $"\"{info.Vendor}\"," + $"{info.ARPMACAddress}," + @@ -118,6 +125,7 @@ private static void CreateXml(IEnumerable collection, string new XElement(ApplicationName.IPScanner.ToString(), new XElement(nameof(IPScannerHostInfo) + "s", from info in collection + where info?.PingInfo != null select new XElement(nameof(IPScannerHostInfo), new XElement(nameof(IPScannerHostInfo.IsReachable), info.IsReachable), @@ -131,20 +139,22 @@ from info in collection new XElement(nameof(PingInfo.TTL), info.PingInfo.TTL), new XElement(nameof(PingInfo.Bytes), info.PingInfo.Bytes), new XElement("PortStatus", info.IsAnyPortOpen ? PortState.Open : PortState.Closed), - from port in info.Ports - select new XElement(nameof(PortInfo), - new XElement(nameof(PortInfo.Port), port.Port), - new XElement(nameof(PortInfo.LookupInfo.Protocol), port.LookupInfo.Protocol), - new XElement(nameof(PortInfo.LookupInfo.Service), port.LookupInfo.Service), - new XElement(nameof(PortInfo.LookupInfo.Description), port.LookupInfo.Description), - new XElement(nameof(PortInfo.State), port.State)), - new XElement("NetBIOSIsReachable", info.NetBIOSInfo.IsReachable), - new XElement("NetBIOSIPAddress", info.NetBIOSInfo.IPAddress), - new XElement("NetBIOSComputerName", info.NetBIOSInfo.ComputerName), - new XElement("NetBIOSUserName", info.NetBIOSInfo.UserName), - new XElement("NetBIOSGroupName", info.NetBIOSInfo.GroupName), - new XElement("NetBIOSMACAddress", info.NetBIOSInfo.MACAddress), - new XElement("NetBIOSVendor", info.NetBIOSInfo.Vendor), + info.Ports != null + ? from port in info.Ports + select new XElement(nameof(PortInfo), + new XElement(nameof(PortInfo.Port), port.Port), + new XElement(nameof(PortInfo.LookupInfo.Protocol), port.LookupInfo.Protocol), + new XElement(nameof(PortInfo.LookupInfo.Service), port.LookupInfo.Service), + new XElement(nameof(PortInfo.LookupInfo.Description), port.LookupInfo.Description), + new XElement(nameof(PortInfo.State), port.State)) + : Enumerable.Empty(), + new XElement("NetBIOSIsReachable", info.NetBIOSInfo?.IsReachable), + new XElement("NetBIOSIPAddress", info.NetBIOSInfo?.IPAddress), + new XElement("NetBIOSComputerName", info.NetBIOSInfo?.ComputerName), + new XElement("NetBIOSUserName", info.NetBIOSInfo?.UserName), + new XElement("NetBIOSGroupName", info.NetBIOSInfo?.GroupName), + new XElement("NetBIOSMACAddress", info.NetBIOSInfo?.MACAddress), + new XElement("NetBIOSVendor", info.NetBIOSInfo?.Vendor), new XElement(nameof(IPScannerHostInfo.MACAddress), info.MACAddress), new XElement(nameof(IPScannerHostInfo.Vendor), info.Vendor), new XElement(nameof(IPScannerHostInfo.ARPMACAddress), info.ARPMACAddress), @@ -164,46 +174,56 @@ from port in info.Ports /// Path to the export file. private static void CreateJson(IReadOnlyList collection, string filePath) { - var jsonData = new object[collection.Count]; + var validCollection = collection.Where(info => info?.PingInfo != null).ToList(); + var jsonData = new object[validCollection.Count]; - for (var i = 0; i < collection.Count; i++) + for (var i = 0; i < validCollection.Count; i++) { - var jsonDataPorts = new object[collection[i].Ports.Count]; - - for (var j = 0; j < collection[i].Ports.Count; j++) - jsonDataPorts[j] = new - { - collection[i].Ports[j].Port, - Protocol = collection[i].Ports[j].LookupInfo.Protocol.ToString(), - collection[i].Ports[j].LookupInfo.Service, - collection[i].Ports[j].LookupInfo.Description, - State = collection[i].Ports[j].State.ToString() - }; + var info = validCollection[i]; + object[] jsonDataPorts; + + if (info.Ports != null && info.Ports.Count > 0) + { + jsonDataPorts = new object[info.Ports.Count]; + for (var j = 0; j < info.Ports.Count; j++) + jsonDataPorts[j] = new + { + info.Ports[j].Port, + Protocol = info.Ports[j].LookupInfo.Protocol.ToString(), + info.Ports[j].LookupInfo.Service, + info.Ports[j].LookupInfo.Description, + State = info.Ports[j].State.ToString() + }; + } + else + { + jsonDataPorts = Array.Empty(); + } jsonData[i] = new { - collection[i].IsReachable, - IPAddress = collection[i].PingInfo.IPAddress.ToString(), - collection[i].Hostname, - PingStatus = collection[i].PingInfo.Status.ToString(), - Timestamp = DateTimeHelper.DateTimeToFullDateTimeString(collection[i].PingInfo.Timestamp), - Time = Ping.TimeToString(collection[i].PingInfo.Status, collection[i].PingInfo.Time, true), - collection[i].PingInfo.TTL, - collection[i].PingInfo.Bytes, - collection[i].DNSHostname, - PortStatus = collection[i].IsAnyPortOpen ? PortState.Open.ToString() : PortState.Closed.ToString(), + info.IsReachable, + IPAddress = info.PingInfo.IPAddress.ToString(), + info.Hostname, + PingStatus = info.PingInfo.Status.ToString(), + Timestamp = DateTimeHelper.DateTimeToFullDateTimeString(info.PingInfo.Timestamp), + Time = Ping.TimeToString(info.PingInfo.Status, info.PingInfo.Time, true), + info.PingInfo.TTL, + info.PingInfo.Bytes, + info.DNSHostname, + PortStatus = info.IsAnyPortOpen ? PortState.Open.ToString() : PortState.Closed.ToString(), Ports = jsonDataPorts, - NetBIOSIsReachable = collection[i].NetBIOSInfo.IsReachable, - NetBIOSIPAddress = collection[i].NetBIOSInfo.IPAddress?.ToString(), - NetBIOSComputerName = collection[i].NetBIOSInfo.ComputerName, - NetBIOSUserName = collection[i].NetBIOSInfo.UserName, - NetBIOSGroupName = collection[i].NetBIOSInfo.GroupName, - NetBIOSMACAddress = collection[i].NetBIOSInfo.MACAddress, - NetBIOSVendor = collection[i].NetBIOSInfo.Vendor, - collection[i].MACAddress, - collection[i].Vendor, - collection[i].ARPMACAddress, - collection[i].ARPVendor + NetBIOSIsReachable = info.NetBIOSInfo?.IsReachable, + NetBIOSIPAddress = info.NetBIOSInfo?.IPAddress?.ToString(), + NetBIOSComputerName = info.NetBIOSInfo?.ComputerName, + NetBIOSUserName = info.NetBIOSInfo?.UserName, + NetBIOSGroupName = info.NetBIOSInfo?.GroupName, + NetBIOSMACAddress = info.NetBIOSInfo?.MACAddress, + NetBIOSVendor = info.NetBIOSInfo?.Vendor, + info.MACAddress, + info.Vendor, + info.ARPMACAddress, + info.ARPVendor }; } diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 8c1fe195b9..1734328e88 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -91,6 +91,8 @@ Release date: **xx.xx.2025** **IP Scanner** - Fix race condition when scan is complete but not all results have been processed yet, causing a wrong error message to be displayed. [#3287](https://github.com/BornToBeRoot/NETworkManager/pull/3287) +- Fix potential error in export logic if some data is null. [#3290](https://github.com/BornToBeRoot/NETworkManager/pull/3290) +- Fix missing simicolon separators in CSV output. [#3290](https://github.com/BornToBeRoot/NETworkManager/pull/3290) **Port Scanner** From e750fc49409c35e66065f6ed9e36c549ad6eef0d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:23:12 +0100 Subject: [PATCH 2/4] Fix export logic issues in TracerouteHopInfo and WiFiNetworkInfo (#3291) * Initial plan * Fix export logic issues in TracerouteHopInfo and WiFiNetworkInfo Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Docs: #3291 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../Export/ExportManager.TracerouteHopInfo.cs | 52 +++++++++---------- .../Export/ExportManager.WiFiNetworkInfo.cs | 4 +- Website/docs/changelog/next-release.md | 10 ++++ 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Source/NETworkManager.Models/Export/ExportManager.TracerouteHopInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.TracerouteHopInfo.cs index 875d2b2d5f..6523b291e6 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.TracerouteHopInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.TracerouteHopInfo.cs @@ -47,11 +47,11 @@ private static void CreateCsv(IEnumerable collection, string var stringBuilder = new StringBuilder(); stringBuilder.AppendLine( - $"{nameof(TracerouteHopInfo.Hop)},{nameof(TracerouteHopInfo.Status1)},{nameof(TracerouteHopInfo.Time1)},{nameof(TracerouteHopInfo.Status2)},{nameof(TracerouteHopInfo.Time2)},{nameof(TracerouteHopInfo.Status3)}{nameof(TracerouteHopInfo.Time3)},{nameof(TracerouteHopInfo.IPAddress)},{nameof(TracerouteHopInfo.Hostname)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Continent)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Country)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Region)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.City)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.District)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Isp)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Org)}, {nameof(TracerouteHopInfo.IPGeolocationResult.Info.As)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Asname)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Hosting)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Proxy)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Mobile)}"); + $"{nameof(TracerouteHopInfo.Hop)},{nameof(TracerouteHopInfo.Status1)},{nameof(TracerouteHopInfo.Time1)},{nameof(TracerouteHopInfo.Status2)},{nameof(TracerouteHopInfo.Time2)},{nameof(TracerouteHopInfo.Status3)},{nameof(TracerouteHopInfo.Time3)},{nameof(TracerouteHopInfo.IPAddress)},{nameof(TracerouteHopInfo.Hostname)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Continent)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Country)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Region)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.City)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.District)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Isp)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Org)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.As)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Asname)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Hosting)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Proxy)},{nameof(TracerouteHopInfo.IPGeolocationResult.Info.Mobile)}"); foreach (var info in collection) stringBuilder.AppendLine( - $"{info.Hop},{info.Status1},{Ping.TimeToString(info.Status1, info.Time1, true)},{info.Status2},{Ping.TimeToString(info.Status2, info.Time2, true)},{info.Status3},{Ping.TimeToString(info.Status3, info.Time3, true)},{info.IPAddress},{info.Hostname},{info.IPGeolocationResult.Info.Continent},{info.IPGeolocationResult.Info.Country},{info.IPGeolocationResult.Info.Region},{info.IPGeolocationResult.Info.City},{info.IPGeolocationResult.Info.District},{info.IPGeolocationResult.Info.Isp?.Replace(",", "")},{info.IPGeolocationResult.Info.Org?.Replace(",", "")},{info.IPGeolocationResult.Info.As?.Replace(",", "")},{info.IPGeolocationResult.Info.Asname?.Replace(",", "")},{info.IPGeolocationResult.Info.Hosting},{info.IPGeolocationResult.Info.Proxy},{info.IPGeolocationResult.Info.Mobile}"); + $"{info.Hop},{info.Status1},{Ping.TimeToString(info.Status1, info.Time1, true)},{info.Status2},{Ping.TimeToString(info.Status2, info.Time2, true)},{info.Status3},{Ping.TimeToString(info.Status3, info.Time3, true)},{info.IPAddress},{info.Hostname},{info.IPGeolocationResult?.Info?.Continent},{info.IPGeolocationResult?.Info?.Country},{info.IPGeolocationResult?.Info?.Region},{info.IPGeolocationResult?.Info?.City},{info.IPGeolocationResult?.Info?.District},{info.IPGeolocationResult?.Info?.Isp?.Replace(",", "")},{info.IPGeolocationResult?.Info?.Org?.Replace(",", "")},{info.IPGeolocationResult?.Info?.As?.Replace(",", "")},{info.IPGeolocationResult?.Info?.Asname?.Replace(",", "")},{info.IPGeolocationResult?.Info?.Hosting},{info.IPGeolocationResult?.Info?.Proxy},{info.IPGeolocationResult?.Info?.Mobile}"); File.WriteAllText(filePath, stringBuilder.ToString()); } @@ -82,29 +82,29 @@ from info in collection new XElement(nameof(TracerouteHopInfo.IPAddress), info.IPAddress), new XElement(nameof(TracerouteHopInfo.Hostname), info.Hostname), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Continent), - info.IPGeolocationResult.Info.Continent), + info.IPGeolocationResult?.Info?.Continent), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Country), - info.IPGeolocationResult.Info.Country), + info.IPGeolocationResult?.Info?.Country), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Region), - info.IPGeolocationResult.Info.Region), + info.IPGeolocationResult?.Info?.Region), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.City), - info.IPGeolocationResult.Info.City), + info.IPGeolocationResult?.Info?.City), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.District), - info.IPGeolocationResult.Info.District), + info.IPGeolocationResult?.Info?.District), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Isp), - info.IPGeolocationResult.Info.Isp), + info.IPGeolocationResult?.Info?.Isp), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Org), - info.IPGeolocationResult.Info.Org), + info.IPGeolocationResult?.Info?.Org), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.As), - info.IPGeolocationResult.Info.As), + info.IPGeolocationResult?.Info?.As), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Asname), - info.IPGeolocationResult.Info.Asname), + info.IPGeolocationResult?.Info?.Asname), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Hosting), - info.IPGeolocationResult.Info.Hosting), + info.IPGeolocationResult?.Info?.Hosting), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Proxy), - info.IPGeolocationResult.Info.Proxy), + info.IPGeolocationResult?.Info?.Proxy), new XElement(nameof(TracerouteHopInfo.IPGeolocationResult.Info.Mobile), - info.IPGeolocationResult.Info.Mobile))))); + info.IPGeolocationResult?.Info?.Mobile))))); document.Save(filePath); } @@ -130,18 +130,18 @@ private static void CreateJson(IReadOnlyList collection, stri Time3 = Ping.TimeToString(collection[i].Status3, collection[i].Time3, true), IPAddress = collection[i].IPAddress?.ToString(), collection[i].Hostname, - collection[i].IPGeolocationResult.Info.Continent, - collection[i].IPGeolocationResult.Info.Country, - collection[i].IPGeolocationResult.Info.Region, - collection[i].IPGeolocationResult.Info.City, - collection[i].IPGeolocationResult.Info.District, - collection[i].IPGeolocationResult.Info.Isp, - collection[i].IPGeolocationResult.Info.Org, - collection[i].IPGeolocationResult.Info.As, - collection[i].IPGeolocationResult.Info.Asname, - collection[i].IPGeolocationResult.Info.Hosting, - collection[i].IPGeolocationResult.Info.Proxy, - collection[i].IPGeolocationResult.Info.Mobile + Continent = collection[i].IPGeolocationResult?.Info?.Continent, + Country = collection[i].IPGeolocationResult?.Info?.Country, + Region = collection[i].IPGeolocationResult?.Info?.Region, + City = collection[i].IPGeolocationResult?.Info?.City, + District = collection[i].IPGeolocationResult?.Info?.District, + Isp = collection[i].IPGeolocationResult?.Info?.Isp, + Org = collection[i].IPGeolocationResult?.Info?.Org, + As = collection[i].IPGeolocationResult?.Info?.As, + Asname = collection[i].IPGeolocationResult?.Info?.Asname, + Hosting = collection[i].IPGeolocationResult?.Info?.Hosting, + Proxy = collection[i].IPGeolocationResult?.Info?.Proxy, + Mobile = collection[i].IPGeolocationResult?.Info?.Mobile }; File.WriteAllText(filePath, JsonConvert.SerializeObject(jsonData, Formatting.Indented)); diff --git a/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs index 37a062527d..2730dcaa2c 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs @@ -47,7 +47,7 @@ private static void CreateCsv(IEnumerable collection, string fi var stringBuilder = new StringBuilder(); stringBuilder.AppendLine( - $"{nameof(WiFiNetworkInfo.AvailableNetwork.Bssid)},{nameof(WiFiNetworkInfo.AvailableNetwork.Ssid)},{nameof(WiFiNetworkInfo.AvailableNetwork.ChannelCenterFrequencyInKilohertz)},{nameof(WiFiNetworkInfo.AvailableNetwork.SignalBars)},{nameof(WiFiNetworkInfo.AvailableNetwork.IsWiFiDirect)},{nameof(WiFiNetworkInfo.AvailableNetwork.NetworkRssiInDecibelMilliwatts)},{nameof(WiFiNetworkInfo.AvailableNetwork.PhyKind)},{nameof(WiFiNetworkInfo.AvailableNetwork.NetworkKind)},{nameof(WiFiNetworkInfo.AvailableNetwork.SecuritySettings.NetworkAuthenticationType)},{nameof(WiFiNetworkInfo.AvailableNetwork.SecuritySettings.NetworkEncryptionType)},{nameof(WiFiNetworkInfo.AvailableNetwork.BeaconInterval)}.{nameof(WiFiNetworkInfo.AvailableNetwork.Uptime)}"); + $"{nameof(WiFiNetworkInfo.AvailableNetwork.Bssid)},{nameof(WiFiNetworkInfo.AvailableNetwork.Ssid)},{nameof(WiFiNetworkInfo.AvailableNetwork.ChannelCenterFrequencyInKilohertz)},{nameof(WiFiNetworkInfo.AvailableNetwork.SignalBars)},{nameof(WiFiNetworkInfo.AvailableNetwork.IsWiFiDirect)},{nameof(WiFiNetworkInfo.AvailableNetwork.NetworkRssiInDecibelMilliwatts)},{nameof(WiFiNetworkInfo.AvailableNetwork.PhyKind)},{nameof(WiFiNetworkInfo.AvailableNetwork.NetworkKind)},{nameof(WiFiNetworkInfo.AvailableNetwork.SecuritySettings.NetworkAuthenticationType)},{nameof(WiFiNetworkInfo.AvailableNetwork.SecuritySettings.NetworkEncryptionType)},{nameof(WiFiNetworkInfo.AvailableNetwork.BeaconInterval)},{nameof(WiFiNetworkInfo.AvailableNetwork.Uptime)}"); foreach (var info in collection) stringBuilder.AppendLine( @@ -111,7 +111,7 @@ private static void CreateJson(IReadOnlyList collection, string { collection[i].AvailableNetwork.Bssid, collection[i].AvailableNetwork.Ssid, - ChannelCenterFrequencyInKilohertz = collection[i].AvailableNetwork.Ssid, + ChannelCenterFrequencyInKilohertz = collection[i].AvailableNetwork.ChannelCenterFrequencyInKilohertz, SignalBars = collection[i].AvailableNetwork.SignalBars.ToString(), IsWiFiDirect = collection[i].AvailableNetwork.IsWiFiDirect.ToString(), NetworkRssiInDecibelMilliwatts = collection[i].AvailableNetwork.NetworkRssiInDecibelMilliwatts diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 1734328e88..ff6a040824 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -88,6 +88,11 @@ Release date: **xx.xx.2025** ## Bug Fixes +**WiFi** + +- Fix potential error in export logic if some data is null. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) +- Fix missing simicolon separators in CSV output. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) + **IP Scanner** - Fix race condition when scan is complete but not all results have been processed yet, causing a wrong error message to be displayed. [#3287](https://github.com/BornToBeRoot/NETworkManager/pull/3287) @@ -98,6 +103,11 @@ Release date: **xx.xx.2025** - Fix race condition when scan is complete but not all results have been processed yet, causing a wrong error message to be displayed. [#3287](https://github.com/BornToBeRoot/NETworkManager/pull/3287) +**Traceroute** + +- Fix potential error in export logic if some data is null. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) +- Fix missing simicolon separators in CSV output. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) + **PowerShell** - Resolve the actual path to `pwsh.exe` under `C:\Program Files\WindowsApps\` instead of relying on the stub located at `%LocalAppData%\Microsoft\WindowsApps\`. The stub simply redirects to the real executable, and settings such as themes are applied only to the real binary via the registry. [#3246](https://github.com/BornToBeRoot/NETworkManager/pull/3246) From 8419c26e16515c0879ed5099c7d91ace9b20c834 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:37:42 +0100 Subject: [PATCH 3/4] Fix: Minor export issues (#3293) * Fix: Minor export issues * Docs: #3293 --- .../Export/ExportManager.IPNetworkInfo.cs | 2 +- .../Export/ExportManager.SNTPLookupResultInfo.cs | 2 +- .../Export/ExportManager.WiFiNetworkInfo.cs | 8 ++++---- Website/docs/changelog/next-release.md | 9 +++++++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Source/NETworkManager.Models/Export/ExportManager.IPNetworkInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.IPNetworkInfo.cs index 3035290ac6..7af1f7de6b 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.IPNetworkInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.IPNetworkInfo.cs @@ -63,7 +63,7 @@ private static void CreateCsv(IEnumerable collection, string file private static void CreateXml(IEnumerable collection, string filePath) { var document = new XDocument(DefaultXDeclaration, - new XElement(ApplicationName.SNMP.ToString(), + new XElement(ApplicationName.SubnetCalculator.ToString(), new XElement(nameof(IPNetworkInfo) + "s", from info in collection select diff --git a/Source/NETworkManager.Models/Export/ExportManager.SNTPLookupResultInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.SNTPLookupResultInfo.cs index 92bd9b9407..d2b9a16064 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.SNTPLookupResultInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.SNTPLookupResultInfo.cs @@ -65,7 +65,7 @@ private static void CreateCsv(IEnumerable collection, string fil private static void CreateXml(IEnumerable collection, string filePath) { var document = new XDocument(DefaultXDeclaration, - new XElement(ApplicationName.SNMP.ToString(), + new XElement(ApplicationName.SNTPLookup.ToString(), new XElement(nameof(SNTPLookupInfo) + "s", from info in collection select diff --git a/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs b/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs index 2730dcaa2c..78e866df04 100644 --- a/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs +++ b/Source/NETworkManager.Models/Export/ExportManager.WiFiNetworkInfo.cs @@ -64,11 +64,11 @@ private static void CreateCsv(IEnumerable collection, string fi private static void CreateXml(IEnumerable collection, string filePath) { var document = new XDocument(DefaultXDeclaration, - new XElement(ApplicationName.IPScanner.ToString(), - new XElement(nameof(IPScannerHostInfo) + "s", + new XElement(ApplicationName.WiFi.ToString(), + new XElement(nameof(WiFiNetworkInfo) + "s", from info in collection select - new XElement(nameof(IPScannerHostInfo), + new XElement(nameof(WiFiNetworkInfo), new XElement(nameof(WiFiNetworkInfo.AvailableNetwork.Bssid), info.AvailableNetwork.Bssid), new XElement(nameof(WiFiNetworkInfo.AvailableNetwork.Ssid), info.AvailableNetwork.Ssid), new XElement(nameof(WiFiNetworkInfo.AvailableNetwork.ChannelCenterFrequencyInKilohertz), @@ -111,7 +111,7 @@ private static void CreateJson(IReadOnlyList collection, string { collection[i].AvailableNetwork.Bssid, collection[i].AvailableNetwork.Ssid, - ChannelCenterFrequencyInKilohertz = collection[i].AvailableNetwork.ChannelCenterFrequencyInKilohertz, + collection[i].AvailableNetwork.ChannelCenterFrequencyInKilohertz, SignalBars = collection[i].AvailableNetwork.SignalBars.ToString(), IsWiFiDirect = collection[i].AvailableNetwork.IsWiFiDirect.ToString(), NetworkRssiInDecibelMilliwatts = collection[i].AvailableNetwork.NetworkRssiInDecibelMilliwatts diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index ff6a040824..a0ea9553d6 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -92,6 +92,7 @@ Release date: **xx.xx.2025** - Fix potential error in export logic if some data is null. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) - Fix missing simicolon separators in CSV output. [#3291](https://github.com/BornToBeRoot/NETworkManager/pull/3291) +- Fix wrong name in xml export [#3293](https://github.com/BornToBeRoot/NETworkManager/pull/3293) **IP Scanner** @@ -121,6 +122,14 @@ Release date: **xx.xx.2025** - Fix `NullReferenceException` when no SNMP profile is selected in the DataGrid and `Return` key is pressed. [#3271](https://github.com/BornToBeRoot/NETworkManager/pull/3271) +**SNTP Lookup** + +- Fix wrong name in xml export [#3293](https://github.com/BornToBeRoot/NETworkManager/pull/3293) + +**Subnet Calculator** + +- Fix wrong name in xml export [#3293](https://github.com/BornToBeRoot/NETworkManager/pull/3293) + ## Dependencies, Refactoring & Documentation - Documentation updated From 51df9a7ce656565636b73fd2f99219043083f1cd Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 28 Dec 2025 20:16:53 +0100 Subject: [PATCH 4/4] Release: 2025.12.28.0 --- Website/docusaurus.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Website/docusaurus.config.js b/Website/docusaurus.config.js index 53273fcb9b..108fad11c7 100644 --- a/Website/docusaurus.config.js +++ b/Website/docusaurus.config.js @@ -166,6 +166,7 @@ const config = { "/docs/changelog/2025-11-30-0", "/docs/changelog/2025-12-13-0", "/docs/changelog/2025-12-20-0", + "/docs/changelog/2025-12-28-0", ], to: "/docs/changelog/next-release", },