using Insight.Domain.Interfaces; using Insight.Domain.Network; using Insight.Domain.Network.Agent.Messages; using System.Management; using System.Runtime.Versioning; using static Insight.Domain.Network.Agent.Messages.PhysicalDisk; using static Insight.Domain.Network.Agent.Messages.StoragePool; using static Insight.Domain.Network.Agent.Messages.VirtualDisk; namespace Insight.Agent.Network.Handlers; [SupportedOSPlatform("windows")] public class StoragePoolHandler : IMessageHandler { public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage { switch (message) { case InventoryRequest: { var result = new Collection(); result.AddRange(GetStoragePool()); await sender.SendAsync(result, cancellationToken); break; } } } private static List GetStoragePool() { if (Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) { throw new PlatformNotSupportedException(); } using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\microsoft\windows\storage"), Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname, resiliencysettingnamedefault, isprimordial, isreadonly, isclustered, size, allocatedsize, logicalsectorsize, operationalstatus, healthstatus from msft_storagepool") }; if (searcher.TryGet(out var collection) is false) { searcher.Query = new ObjectQuery("select * from msft_storagepool"); if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } var pools = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var pool = new StoragePool(); var properties = @object.GetPropertyHashes(); pool.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); pool.Name = @object.GetValue(properties, "name")?.Trim(); pool.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) { pool.States = operationals.Select(p => (StoragePool.OperationalState)p).ToList(); } pool.Health = (StoragePool.HealthState)@object.GetValue(properties, "healthstatus"); pool.RetireMissingPhysicalDisks = (RetireMissingPhysicalDisksEnum)@object.GetValue(properties, "retiremissingphysicaldisks"); pool.Resiliency = @object.GetValue(properties, "resiliencysettingnamedefault")?.Trim(); pool.IsPrimordial = @object.GetValue(properties, "isprimordial"); pool.IsReadOnly = @object.GetValue(properties, "isreadonly"); pool.IsClustered = @object.GetValue(properties, "isclustered"); pool.Size = @object.GetValue(properties, "size"); pool.AllocatedSize = @object.GetValue(properties, "allocatedsize"); pool.SectorSize = @object.GetValue(properties, "logicalsectorsize"); if (@object.GetValue(properties, "objectid") is string objectId) { pool.PhysicalDisks = QueryPhysicalDisksByStoragePool(objectId); pool.VirtualDisks = QueryVirtualDisksByStoragePool(objectId); } pools.Add(pool); } } return pools; } private static List QueryPhysicalDisksByStoragePool(string storagePoolObjectId) { using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\microsoft\windows\storage"), Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToPhysicalDisk") }; if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); var disks = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var disk = new PhysicalDisk(); var properties = @object.GetPropertyHashes(); disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); disk.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); disk.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); disk.Model = @object.GetValue(properties, "model")?.Trim(); disk.MediaType = @object.GetValue(properties, "mediatype"); disk.BusType = @object.GetValue(properties, "bustype"); if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) { disk.States = operationals.Select(p => (PhysicalDisk.OperationalState)p).ToList(); } disk.Health = (PhysicalDisk.HealthState)@object.GetValue(properties, "healthstatus"); if (@object.TryGetValue(properties, "supportedusages", out var supportedusages) && supportedusages is not null) { disk.SupportedUsages = supportedusages.Select(p => (SupportedUsagesEnum)p).ToList(); } disk.Usage = @object.GetValue(properties, "usage"); disk.PhysicalLocation = @object.GetValue(properties, "physicallocation")?.Trim(); disk.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); disk.FirmwareVersion = @object.GetValue(properties, "firmwareversion")?.Trim(); disk.Size = @object.GetValue(properties, "size"); disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); disk.LogicalSectorSize = @object.GetValue(properties, "logicalsectorsize"); disk.PhysicalSectorSize = @object.GetValue(properties, "physicalsectorsize"); disk.VirtualDiskFootprint = @object.GetValue(properties, "virtualdiskfootprint"); disks.Add(disk); } } return disks; } private static List QueryVirtualDisksByStoragePool(string storagePoolObjectId) { using var searcher = new ManagementObjectSearcher { Scope = new ManagementScope(@"root\microsoft\windows\storage"), Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToVirtualDisk") }; if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); var disks = new List(); using (collection) { foreach (ManagementObject @object in collection.Cast()) { var disk = new VirtualDisk(); var properties = @object.GetPropertyHashes(); disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); disk.Name = @object.GetValue(properties, "name")?.Trim(); disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); disk.AccessType = (AccessTypeEnum)@object.GetValue(properties, "access"); disk.ProvisioningType = (ProvisioningTypeEnum)@object.GetValue(properties, "provisioningtype"); disk.PhysicalDiskRedundancy = @object.GetValue(properties, "physicaldiskredundancy"); disk.ResiliencySettingName = @object.GetValue(properties, "resiliencysettingname")?.Trim(); disk.Deduplication = @object.GetValue(properties, "isdeduplicationenabled"); disk.IsSnapshot = @object.GetValue(properties, "issnapshot"); if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) { disk.States = operationals.Select(p => (VirtualDisk.OperationalState)p).ToList(); } disk.Health = (VirtualDisk.HealthState)@object.GetValue(properties, "healthstatus"); disk.Size = @object.GetValue(properties, "size"); disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); disk.FootprintOnPool = @object.GetValue(properties, "footprintonpool"); disk.ReadCacheSize = @object.GetValue(properties, "readcachesize"); disk.WriteCacheSize = @object.GetValue(properties, "writecachesize"); disks.Add(disk); } } return disks; } }