using Vanara.Management; namespace Vanara.IO; public partial class VirtualDisk { private static readonly System.Management.ManagementScope scope = new(@"root\virtualization\v2"); /// Compaction options for . public enum CompactionMode : ushort { /// Full. Full = 0, /// Quick. Quick, /// Retrimmed Retrim, /// Pretrimmed Pretrimmed, /// Prezeroed Prezeroed } /// /// Converts an existing virtual hard disk to a different type or format. This method creates a new virtual hard disk and does not /// convert the source virtual hard disk in place. /// /// /// The fully qualified path of the source virtual hard disk file to convert. This file will not be modified as a result of this operation. /// /// The format for the target virtual hard disk. /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// public static async Task ConvertAsync(string path, DeviceType targetType, CancellationToken cancellationToken = default, IProgress? progress = default) { var dest = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(path) ?? throw new ArgumentException("A full path to a virtual disk is required.", nameof(path)), $"{System.IO.Path.GetFileNameWithoutExtension(path)}.{targetType.ToString().ToLower()}"); if (string.Equals(path, dest, StringComparison.InvariantCultureIgnoreCase)) return; VirtualDisk vhd = Open(path, true, true); Subtype subType = vhd.ProviderSubtype; vhd.Close(); var data = new VirtualDiskSettingData(subType, targetType, dest); await ConvertAsync(path, data, cancellationToken, progress); } /// /// Converts an existing virtual hard disk to a different type or format. This method creates a new virtual hard disk and does not /// convert the source virtual hard disk in place. /// /// /// The fully qualified path of the source virtual hard disk file to convert. This file will not be modified as a result of this operation. /// /// The settings, including path, for the target virtual hard disk. /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// public static async Task ConvertAsync(string sourcePath, VirtualDiskSettingData destinationSettings, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "ConvertVirtualHardDisk", ("SourcePath", sourcePath), ("VirtualDiskSettingData", destinationSettings.GetInstanceText())); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to convert virtual disk.", ex); } } /// Converts a virtual hard disk file by creating a new VHD Set file alongside the existing virtual hard disk. /// The path to the virtual hard disk file. The new VHD Set file will have the same filename but with the .VHDS extension. /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// /// Failed to create virtual disk set file. public static async Task ConvertToVHDSetAsync(string path, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "ConvertVirtualHardDiskToVHDSet", ("VirtualHardDiskPath", path)); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to create virtual disk set file.", ex); } } /// /// Merges a child virtual hard disk in a differencing chain with one or more parent virtual hard disks in the chain. See Remarks for /// usage restrictions for this method. /// If the user executing this function does not have permission to update the virtual machines, then this function will fail. /// /// A fully qualified path that specifies the location of the virtual hard disk file to merge. /// /// A fully qualified path that specifies the location of the parent virtual hard disk file into which data is to be merged. This could /// be the immediate parent virtual hard disk of the merging file or the parent disk image a few levels up the differencing chain. /// /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// public static async Task MergeAsync(string sourcePath, string destPath, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "MergeVirtualHardDisk", ("SourcePath", sourcePath), ("DestinationPath", destPath)); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to merge virtual disks.", ex); } } /// Optimizes a VHD Set file to use less disk space. /// A fully-qualified path that specifies the location of the VHD Set file. /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// /// Failed to create virtual disk set file. public static async Task OptimizeVHDSetAsync(string path, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "OptimizeVHDSet", ("VHDSetPath", path)); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to optimize virtual disk set file.", ex); } } /// Determines whether a virtual hard disk file is valid. /// /// The fully qualified path of the virtual hard disk file to validate. This file will not be modified as a result of this operation. /// /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// /// true if operation completed without error or cancellation; false otherwise. public static async Task ValidateAsync(string path, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "ValidateVirtualHardDisk", ("Path", path)); return output.GetResultOrThrow(true); } catch { return false; } } /// Validates whether a file system can support a virtual hard disk with persistent reservations enabled. /// /// A fully-qualified path that specifies the location of a disk image file or a directory in which a disk image file might be placed. /// /// if the file system can support a virtual hard disk with persistent reservations enabled. public static bool ValidatePersistentReservationSupport(string path) { try { return scope.CallJobMethodAsync(default, default, "Msvm_ImageManagementService", "ValidatePersistentReservationSupport", ("Path", path)).Result.GetResultOrThrow(true); } catch { return false; } } /// Reduces the size of a virtual hard disk (VHD) backing store file. /// The mode. /// /// A cancellation token that can be used to cancel the operation. This value can be to disable cancellation. /// /// /// A class that implements that can be used to report on progress. This value can be null to disable /// progress reporting. /// public async Task CompactAsync(CompactionMode mode, CancellationToken cancellationToken = default, IProgress? progress = default) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(cancellationToken, progress, "Msvm_ImageManagementService", "CompactVirtualHardDisk", ("Path", ImagePath), ("Mode", (ushort)mode)); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to compact virtual disk.", ex); } } /// Retrieves information about a VHD Set file. /// The information for the requested VHD Set file as an instance. /// Failed to get virtual disk set information. public VirtualDiskSetInformation GetVHDSetInformation() { try { var info = new uint[] { 0, 1, 2 }; System.Management.ManagementBaseObject output = scope.CallJobMethodAsync(default, default, "Msvm_ImageManagementService", "GetVHDSetInformation", ("VHDSetPath", ImagePath), ("AdditionalInformation", info)).Result; output.GetResultOrThrow(true); return VirtualDiskSetInformation.Parse(Convert.ToString(output.Properties["Information"].Value)); } catch (Exception ex) { throw new InvalidOperationException("Failed to get virtual disk set information.", ex); } } /// Retrieves information about a VHD Snapshot within a VHD Set file. /// A fully-qualified path that specifies the location of the VHD Set file. /// The snapshot identifier. /// The information for the requested VHD Set file as an instance. /// Failed to get virtual disk set information. // TODO: Fix problem with it failing regardless of what parameters are supplied internal static VirtualDiskSnapshotInformation GetSnapshotInformation(string path, Guid snapshotId) { try { var info = new uint[] { 2 }; System.Management.ManagementBaseObject output = scope.CallJobMethodAsync(default, default, "Msvm_ImageManagementService", "GetVHDSnapshotInformation", ("VHDSetPath", path), ("AdditionalInformation", info), ("SnapshotIds", new[] { snapshotId.ToString("D") })).Result; output.GetResultOrThrow(true); return VirtualDiskSnapshotInformation.Parse(Convert.ToString(output.Properties["SnapshotInformation"].Value)); } catch (Exception ex) { throw new InvalidOperationException("Failed to get virtual disk snapshot information.", ex); } } /// Sets the snapshot information asynchronous. /// The information. /// Failed to set virtual disk snapshot information. // TODO: Fix problem with it failing regardless of what parameters are supplied internal static async Task SetSnapshotInformationAsync(VirtualDiskSnapshotInformation info) { try { System.Management.ManagementBaseObject output = await scope.CallJobMethodAsync(default, default, "Msvm_ImageManagementService", "SetVHDSnapshotInformation", ("Information", info.GetInstanceText())); output.GetResultOrThrow(true); } catch (Exception ex) { throw new InvalidOperationException("Failed to set virtual disk snapshot information.", ex); } } // TODO: Create listener events for states in RequestStateChange }