using System; using System.Collections.Generic; using System.IO; using System.Management.Automation; using PSProxmox.CloudImages; namespace PSProxmox.Cmdlets { /// /// Customizes a cloud image. /// The Invoke-ProxmoxCloudImageCustomization cmdlet customizes a cloud image by resizing it, adding packages, or running commands or scripts. /// /// /// Resize a cloud image to 20GB /// Invoke-ProxmoxCloudImageCustomization -ImagePath "C:\Images\ubuntu-22.04-server-cloudimg-amd64.img" -Resize 20 /// /// /// Convert a cloud image to qcow2 format /// Invoke-ProxmoxCloudImageCustomization -ImagePath "C:\Images\ubuntu-22.04-server-cloudimg-amd64.img" -ConvertTo "qcow2" /// [Cmdlet(VerbsLifecycle.Invoke, "ProxmoxCloudImageCustomization")] [OutputType(typeof(string))] public class InvokeProxmoxCloudImageCustomizationCmdlet : PSCmdlet { /// /// The path to the cloud image file. /// [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] public string ImagePath { get; set; } /// /// The new size of the image in GB. /// [Parameter(Mandatory = false)] public int? Resize { get; set; } /// /// The format to convert the image to (e.g., "qcow2", "raw"). /// [Parameter(Mandatory = false)] [ValidateSet("qcow2", "raw")] public string ConvertTo { get; set; } /// /// The packages to install in the image. /// [Parameter(Mandatory = false)] public string[] Packages { get; set; } /// /// The commands to run in the image. /// [Parameter(Mandatory = false)] public string[] Commands { get; set; } /// /// The scripts to run in the image. /// [Parameter(Mandatory = false)] public string[] Scripts { get; set; } /// /// The output path for the customized image. If not specified, the original image will be modified. /// [Parameter(Mandatory = false)] public string OutputPath { get; set; } /// /// Processes the cmdlet. /// protected override void ProcessRecord() { try { if (!File.Exists(ImagePath)) { throw new FileNotFoundException("Image file not found", ImagePath); } string resultPath = ImagePath; // Resize the image if requested if (Resize.HasValue) { WriteVerbose($"Resizing image to {Resize.Value}GB..."); var progressRecord = new ProgressRecord( 0, $"Resizing image to {Resize.Value}GB", "0% complete"); progressRecord.PercentComplete = 0; WriteProgress(progressRecord); resultPath = CloudImageCustomizer.ResizeImage( resultPath, Resize.Value, message => { progressRecord.StatusDescription = message; progressRecord.PercentComplete = 50; WriteProgress(progressRecord); }); progressRecord.PercentComplete = 100; progressRecord.StatusDescription = "Resize complete"; progressRecord.RecordType = ProgressRecordType.Completed; WriteProgress(progressRecord); WriteVerbose("Image resized successfully"); } // Convert the image if requested if (!string.IsNullOrEmpty(ConvertTo)) { WriteVerbose($"Converting image to {ConvertTo}..."); var progressRecord = new ProgressRecord( 1, $"Converting image to {ConvertTo}", "0% complete"); progressRecord.PercentComplete = 0; WriteProgress(progressRecord); resultPath = CloudImageCustomizer.ConvertImage( resultPath, ConvertTo, message => { progressRecord.StatusDescription = message; progressRecord.PercentComplete = 50; WriteProgress(progressRecord); }); progressRecord.PercentComplete = 100; progressRecord.StatusDescription = "Conversion complete"; progressRecord.RecordType = ProgressRecordType.Completed; WriteProgress(progressRecord); WriteVerbose("Image converted successfully"); } // Customize the image if requested if ((Packages != null && Packages.Length > 0) || (Commands != null && Commands.Length > 0) || (Scripts != null && Scripts.Length > 0)) { WriteVerbose("Customizing image..."); var progressRecord = new ProgressRecord( 2, "Customizing image", "0% complete"); progressRecord.PercentComplete = 0; WriteProgress(progressRecord); resultPath = CloudImageCustomizer.CustomizeImage( resultPath, Packages, Commands, Scripts, message => { progressRecord.StatusDescription = message; progressRecord.PercentComplete = 50; WriteProgress(progressRecord); }); progressRecord.PercentComplete = 100; progressRecord.StatusDescription = "Customization complete"; progressRecord.RecordType = ProgressRecordType.Completed; WriteProgress(progressRecord); WriteVerbose("Image customized successfully"); } // Copy to output path if specified if (!string.IsNullOrEmpty(OutputPath) && resultPath != OutputPath) { WriteVerbose($"Copying image to {OutputPath}..."); var outputDirectory = Path.GetDirectoryName(OutputPath); if (!string.IsNullOrEmpty(outputDirectory) && !Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } File.Copy(resultPath, OutputPath, true); resultPath = OutputPath; WriteVerbose("Image copied successfully"); } WriteObject(resultPath); } catch (Exception ex) { WriteError(new ErrorRecord( ex, "InvokeProxmoxCloudImageCustomizationError", ErrorCategory.NotSpecified, null)); } } } }