2022-04-11 17:46:20 -04:00
using Vanara.Management ;
2022-04-09 20:40:26 -04:00
2022-04-11 17:46:20 -04:00
namespace Vanara.IO ;
public partial class VirtualDisk
2022-04-09 20:40:26 -04:00
{
2023-09-06 11:14:25 -04:00
private static readonly System . Management . ManagementScope scope = new ( @"root\virtualization\v2" ) ;
2022-04-11 17:46:20 -04:00
/// <summary>Compaction options for <see cref="CompactAsync(CompactionMode, CancellationToken, IProgress{int})"/>.</summary>
public enum CompactionMode : ushort
{
/// <summary>Full.</summary>
Full = 0 ,
/// <summary>Quick.</summary>
Quick ,
/// <summary>Retrimmed</summary>
Retrim ,
/// <summary>Pretrimmed</summary>
Pretrimmed ,
/// <summary>Prezeroed</summary>
Prezeroed
}
/// <summary>
/// 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.
/// </summary>
/// <param name="path">
/// 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.
/// </param>
/// <param name="targetType">The format for the target virtual hard disk.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
2023-09-06 11:14:25 -04:00
public static async Task ConvertAsync ( string path , DeviceType targetType , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
2023-09-06 11:14:25 -04:00
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()}" ) ;
2022-04-11 17:46:20 -04:00
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 ) ;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sourcePath">
/// 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.
/// </param>
/// <param name="destinationSettings">The settings, including path, for the target virtual hard disk.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
2023-09-06 11:14:25 -04:00
public static async Task ConvertAsync ( string sourcePath , VirtualDiskSettingData destinationSettings , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
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 ) ;
}
}
/// <summary>Converts a virtual hard disk file by creating a new VHD Set file alongside the existing virtual hard disk.</summary>
/// <param name="path">The path to the virtual hard disk file. The new VHD Set file will have the same filename but with the .VHDS extension.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
/// <exception cref="System.InvalidOperationException">Failed to create virtual disk set file.</exception>
2023-09-06 11:14:25 -04:00
public static async Task ConvertToVHDSetAsync ( string path , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
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 ) ;
}
}
/// <summary>
/// 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.
/// <para>If the user executing this function does not have permission to update the virtual machines, then this function will fail.</para>
/// </summary>
/// <param name="sourcePath">A fully qualified path that specifies the location of the virtual hard disk file to merge.</param>
/// <param name="destPath">
/// 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.
/// </param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
2023-09-06 11:14:25 -04:00
public static async Task MergeAsync ( string sourcePath , string destPath , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
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 ) ;
}
}
/// <summary>Optimizes a VHD Set file to use less disk space.</summary>
/// <param name="path">A fully-qualified path that specifies the location of the VHD Set file.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
/// <exception cref="System.InvalidOperationException">Failed to create virtual disk set file.</exception>
2023-09-06 11:14:25 -04:00
public static async Task OptimizeVHDSetAsync ( string path , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-09 20:40:26 -04:00
{
2022-04-11 17:46:20 -04:00
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 ) ;
2022-04-09 20:40:26 -04:00
}
}
2022-04-11 17:46:20 -04:00
/// <summary>Determines whether a virtual hard disk file is valid.</summary>
/// <param name="path">
/// The fully qualified path of the virtual hard disk file to validate. This file will not be modified as a result of this operation.
/// </param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
/// <returns><c>true</c> if operation completed without error or cancellation; <c>false</c> otherwise.</returns>
2023-09-06 11:14:25 -04:00
public static async Task < bool > ValidateAsync ( string path , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
try
{
System . Management . ManagementBaseObject output = await scope . CallJobMethodAsync ( cancellationToken , progress , "Msvm_ImageManagementService" , "ValidateVirtualHardDisk" , ( "Path" , path ) ) ;
return output . GetResultOrThrow ( true ) ;
}
catch
{
return false ;
}
}
/// <summary>Validates whether a file system can support a virtual hard disk with persistent reservations enabled.</summary>
/// <param name="path">
/// 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.
/// </param>
/// <returns><see langword="true"/> if the file system can support a virtual hard disk with persistent reservations enabled.</returns>
public static bool ValidatePersistentReservationSupport ( string path )
{
try
{
return scope . CallJobMethodAsync ( default , default , "Msvm_ImageManagementService" , "ValidatePersistentReservationSupport" , ( "Path" , path ) ) . Result . GetResultOrThrow ( true ) ;
}
catch
{
return false ;
}
}
/// <summary>Reduces the size of a virtual hard disk (VHD) backing store file.</summary>
/// <param name="mode">The mode.</param>
/// <param name="cancellationToken">
/// A cancellation token that can be used to cancel the operation. This value can be <see cref="CancellationToken.None"/> to disable cancellation.
/// </param>
/// <param name="progress">
/// A class that implements <see cref="IProgress{T}"/> that can be used to report on progress. This value can be <c>null</c> to disable
/// progress reporting.
/// </param>
2023-09-06 11:14:25 -04:00
public async Task CompactAsync ( CompactionMode mode , CancellationToken cancellationToken = default , IProgress < int > ? progress = default )
2022-04-11 17:46:20 -04:00
{
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 ) ;
}
}
/// <summary>Retrieves information about a VHD Set file.</summary>
/// <returns>The information for the requested VHD Set file as an <see cref="VirtualDiskSetInformation"/> instance.</returns>
/// <exception cref="System.InvalidOperationException">Failed to get virtual disk set information.</exception>
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 ) ;
}
}
/// <summary>Retrieves information about a VHD Snapshot within a VHD Set file.</summary>
/// <param name="path">A fully-qualified path that specifies the location of the VHD Set file.</param>
/// <param name="snapshotId">The snapshot identifier.</param>
/// <returns>The information for the requested VHD Set file as an <see cref="VirtualDiskSnapshotInformation"/> instance.</returns>
/// <exception cref="System.InvalidOperationException">Failed to get virtual disk set information.</exception>
// 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 ) ;
}
}
/// <summary>Sets the snapshot information asynchronous.</summary>
/// <param name="info">The information.</param>
/// <exception cref="System.InvalidOperationException">Failed to set virtual disk snapshot information.</exception>
// 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
2022-04-09 20:40:26 -04:00
}