421 lines
17 KiB
C#
421 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Management;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net.Sockets;
|
|
using System.DirectoryServices.AccountManagement;
|
|
using System.Text.Json;
|
|
|
|
namespace Inventory.Core
|
|
{
|
|
public class SystemInfoCollector
|
|
{
|
|
public string GetComputerName()
|
|
{
|
|
return Environment.MachineName;
|
|
}
|
|
|
|
public string GetDeviceType()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
// Using Win32_SystemEnclosure to determine device type
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_SystemEnclosure");
|
|
foreach (ManagementObject mo in searcher.Get())
|
|
{
|
|
foreach (int chassisType in (ushort[])mo["ChassisTypes"])
|
|
{
|
|
switch (chassisType)
|
|
{
|
|
case 3: // Desktop
|
|
case 4: // Low Profile Desktop
|
|
case 5: // Pizza Box
|
|
case 6: // Mini Tower
|
|
case 7: // Tower
|
|
return "Desktop";
|
|
case 8: // Portable
|
|
case 9: // Laptop
|
|
case 10: // Notebook
|
|
case 11: // Hand Held
|
|
case 12: // Docking Station
|
|
case 14: // Sub Notebook
|
|
return "Laptop";
|
|
case 23: // Rack Mount Chassis
|
|
return "Server";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
|
|
// Fallback to checking for a battery
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Battery");
|
|
if (searcher.Get().Count > 0)
|
|
{
|
|
return "Laptop";
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
public string? GetSystemSerialNumber()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BIOS");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["SerialNumber"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public string? GetMotherboardSerialNumber()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["SerialNumber"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public string? GetSystemUUID()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["UUID"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public string? GetProcessor()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name FROM Win32_Processor");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["Name"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public string GetTotalRAM()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
if (mo != null)
|
|
{
|
|
ulong ramBytes = (ulong)mo["TotalPhysicalMemory"];
|
|
double ramGB = Math.Round(ramBytes / (1024.0 * 1024.0 * 1024.0));
|
|
return $"{ramGB} GB";
|
|
}
|
|
return "N/A";
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public List<string> GetGPUs()
|
|
{
|
|
var gpus = new List<string>();
|
|
if (!OperatingSystem.IsWindows()) return gpus;
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name FROM Win32_VideoController");
|
|
foreach (ManagementObject mo in searcher.Get())
|
|
{
|
|
gpus.Add(mo["Name"]?.ToString()?.Trim() ?? "");
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
return gpus;
|
|
}
|
|
|
|
public List<StorageDeviceInfo> GetStorage()
|
|
{
|
|
var drives = new List<StorageDeviceInfo>();
|
|
if (!OperatingSystem.IsWindows()) return drives;
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"root\Microsoft\Windows\Storage", "SELECT * FROM MSFT_PhysicalDisk");
|
|
foreach (ManagementObject mo in searcher.Get())
|
|
{
|
|
string mediaType = "Unknown";
|
|
switch ((ushort)mo["MediaType"])
|
|
{
|
|
case 3: mediaType = "HDD"; break;
|
|
case 4: mediaType = "SSD"; break;
|
|
}
|
|
|
|
drives.Add(new StorageDeviceInfo
|
|
{
|
|
Model = mo["Model"]?.ToString()?.Trim(),
|
|
SerialNumber = mo["SerialNumber"]?.ToString()?.Trim(),
|
|
MediaType = mediaType,
|
|
InterfaceType = mo["BusType"]?.ToString()?.Trim(),
|
|
Size = (ulong)mo["Size"]
|
|
});
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
return drives;
|
|
}
|
|
|
|
public List<PrinterInfo> GetPrinters()
|
|
{
|
|
var printers = new List<PrinterInfo>();
|
|
if (!OperatingSystem.IsWindows()) return printers;
|
|
try
|
|
{
|
|
var ignoredPrinters = new List<string>
|
|
{
|
|
// Microsoft standard virtual printers
|
|
"Microsoft Print to PDF",
|
|
"Microsoft XPS Document Writer",
|
|
"OneNote", // Catches "OneNote for Windows 10" and "OneNote (Desktop)"
|
|
"Fax",
|
|
"Send to OneNote",
|
|
|
|
// Common 3rd-party PDF printers
|
|
"Adobe PDF",
|
|
"CutePDF",
|
|
"Bullzip",
|
|
"doPDF",
|
|
"Foxit",
|
|
"PrimoPDF",
|
|
"PDF Architect",
|
|
|
|
// Other virtual/utility printers
|
|
"Snagit",
|
|
"WebEx",
|
|
"AnyDesk"
|
|
};
|
|
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
|
|
foreach (ManagementObject mo in searcher.Get())
|
|
{
|
|
string? name = mo["Name"]?.ToString()?.Trim();
|
|
if (name != null && !ignoredPrinters.Any(p => name.Contains(p, StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
string? serialNumber = null;
|
|
string? pnpDeviceId = mo["PNPDeviceID"]?.ToString();
|
|
|
|
// Attempt to extract serial number from PNPDeviceID for USB printers
|
|
// Example ID: "USBPRINT\HEWLETT-PACKARDHP_LASERJET_PROFESSIONAL_M1212NF_MFP\7&1B442418&0&USB001"
|
|
// The last part after the model name is often a unique identifier or serial.
|
|
if (!string.IsNullOrEmpty(pnpDeviceId) && pnpDeviceId.Contains("USB"))
|
|
{
|
|
var parts = pnpDeviceId.Split('\\');
|
|
if (parts.Length > 2)
|
|
{
|
|
serialNumber = parts[2]; // This is often the most unique part available
|
|
}
|
|
}
|
|
|
|
printers.Add(new PrinterInfo
|
|
{
|
|
Name = name,
|
|
DriverName = mo["DriverName"]?.ToString()?.Trim(),
|
|
IsShared = (bool)mo["Shared"],
|
|
IsNetwork = (bool)mo["Network"],
|
|
HostName = mo["SystemName"]?.ToString()?.Trim(),
|
|
PortName = mo["PortName"]?.ToString()?.Trim(),
|
|
SerialNumber = serialNumber
|
|
});
|
|
}
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
return printers;
|
|
}
|
|
|
|
public bool HasOpticalDrive()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return false;
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_CDROMDrive");
|
|
return searcher.Get().Count > 0;
|
|
}
|
|
catch { return false; }
|
|
}
|
|
|
|
public List<MonitorInfo> GetMonitors()
|
|
{
|
|
var monitors = new List<MonitorInfo>();
|
|
if (!OperatingSystem.IsWindows()) return monitors;
|
|
try
|
|
{
|
|
// Get PnPDeviceID from Win32_DesktopMonitor
|
|
var pnpDeviceIds = new Dictionary<string, string>();
|
|
ManagementObjectSearcher desktopMonitorSearcher = new ManagementObjectSearcher("SELECT PNPDeviceID, Name FROM Win32_DesktopMonitor");
|
|
foreach (ManagementObject mo in desktopMonitorSearcher.Get())
|
|
{
|
|
pnpDeviceIds[mo["Name"]?.ToString() ?? string.Empty] = mo["PNPDeviceID"]?.ToString() ?? "Unknown";
|
|
}
|
|
|
|
// Get Serial and Model from WmiMonitorID
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"root\wmi", "SELECT InstanceName, SerialNumberID, UserFriendlyName FROM WmiMonitorID");
|
|
foreach (ManagementObject mo in searcher.Get())
|
|
{
|
|
string model = "Unknown";
|
|
string serial = "Unknown";
|
|
string instanceName = mo["InstanceName"]?.ToString()?.TrimEnd('_', '0') ?? string.Empty;
|
|
|
|
if (mo["UserFriendlyName"] is ushort[] modelName)
|
|
{
|
|
model = System.Text.Encoding.ASCII.GetString(modelName.Select(c => (byte)c).ToArray()).Trim('\0');
|
|
}
|
|
|
|
if (mo["SerialNumberID"] is ushort[] serialNumberID)
|
|
{
|
|
serial = System.Text.Encoding.ASCII.GetString(serialNumberID.Select(c => (byte)c).ToArray()).Trim('\0');
|
|
}
|
|
|
|
monitors.Add(new MonitorInfo
|
|
{
|
|
Model = model,
|
|
SerialNumber = serial,
|
|
PnPDeviceID = pnpDeviceIds.Values.FirstOrDefault(pnp => instanceName.Contains(pnp)) ?? "N/A"
|
|
});
|
|
}
|
|
}
|
|
catch { /* Ignore WMI errors */ }
|
|
return monitors;
|
|
}
|
|
|
|
public string? GetOSVersion()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["Caption"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public DateTime? GetOSInstallDate()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return null;
|
|
try
|
|
{
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT InstallDate FROM Win32_OperatingSystem");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
var installDate = mo?["InstallDate"]?.ToString();
|
|
return installDate != null ? ManagementDateTimeConverter.ToDateTime(installDate) : null;
|
|
}
|
|
catch { return null; }
|
|
}
|
|
|
|
public string? GetOSLicenseKey()
|
|
{
|
|
if (!OperatingSystem.IsWindows()) return "N/A";
|
|
try
|
|
{
|
|
// This is a common method but may not work on all systems, especially with newer licensing methods.
|
|
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT OA3xOriginalProductKey FROM SoftwareLicensingService");
|
|
ManagementObject? mo = searcher.Get().OfType<ManagementObject>().FirstOrDefault();
|
|
return mo?["OA3xOriginalProductKey"]?.ToString()?.Trim();
|
|
}
|
|
catch { return "N/A"; }
|
|
}
|
|
|
|
public List<LocalAdminInfo> GetLocalAdmins()
|
|
{
|
|
var admins = new List<LocalAdminInfo>();
|
|
if (!OperatingSystem.IsWindows()) return admins;
|
|
|
|
try
|
|
{
|
|
using (var context = new PrincipalContext(ContextType.Machine))
|
|
{
|
|
var group = GroupPrincipal.FindByIdentity(context, "Administrators");
|
|
if (group != null)
|
|
{
|
|
// Perform a recursive search to find all members, including those in nested groups.
|
|
// Then, use DistinctBy to remove duplicates based on the unique SID.
|
|
#pragma warning disable CA1416 // Validate platform compatibility
|
|
|
|
var uniqueMembers = group.GetMembers(true).DistinctBy(p => p.Sid);
|
|
#pragma warning restore CA1416 // Validate platform compatibility
|
|
|
|
|
|
foreach (Principal principal in uniqueMembers)
|
|
{
|
|
var adminInfo = new LocalAdminInfo
|
|
{
|
|
Name = principal.Name,
|
|
Sid = principal.Sid.ToString(),
|
|
AccountType = principal is UserPrincipal ? "User" : "Group",
|
|
Source = principal.Context.ContextType == ContextType.Machine ? "Local" : "Domain"
|
|
};
|
|
|
|
if (principal is UserPrincipal user)
|
|
{
|
|
adminInfo.IsEnabled = user.Enabled;
|
|
adminInfo.IsLockedOut = user.IsAccountLockedOut();
|
|
}
|
|
admins.Add(adminInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch { /* Ignore errors, e.g. on non-domain machines */ }
|
|
return admins;
|
|
}
|
|
|
|
public (List<string> IPAddresses, string? MACAddress) GetNetworkInfo()
|
|
{
|
|
try
|
|
{
|
|
var allIps = new List<string>();
|
|
string? primaryMac = null;
|
|
|
|
var operationalNics = NetworkInterface.GetAllNetworkInterfaces()
|
|
.Where(ni => ni.OperationalStatus == OperationalStatus.Up &&
|
|
ni.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
|
|
ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
|
|
.Select(ni => new
|
|
{
|
|
Interface = ni,
|
|
IPProps = ni.GetIPProperties()
|
|
})
|
|
.Where(x => !(x.Interface.Description.Contains("Virtual") || x.Interface.Name.Contains("Virtual")));
|
|
|
|
foreach (var nic in operationalNics)
|
|
{
|
|
allIps.AddRange(nic.IPProps.UnicastAddresses
|
|
.Where(ua => ua.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
.Select(ua => ua.Address.ToString()));
|
|
}
|
|
|
|
// Find the primary MAC address from the interface with a gateway, ordered by speed
|
|
var primaryNic = operationalNics.Where(n => n.IPProps.GatewayAddresses.Any()).OrderByDescending(n => n.Interface.Speed).FirstOrDefault();
|
|
primaryMac = primaryNic?.Interface.GetPhysicalAddress().ToString();
|
|
|
|
return (allIps.Distinct().ToList(), primaryMac);
|
|
}
|
|
catch { /* Ignore errors */ }
|
|
|
|
return (new List<string>(), "N/A");
|
|
}
|
|
}
|
|
} |