diff --git a/src/PSProxmoxVE/Cmdlets/CloudInit/GetPveCloudInitConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/CloudInit/GetPveCloudInitConfigCmdlet.cs
index 691a149..8022413 100644
--- a/src/PSProxmoxVE/Cmdlets/CloudInit/GetPveCloudInitConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/CloudInit/GetPveCloudInitConfigCmdlet.cs
@@ -18,11 +18,12 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
public class GetPveCloudInitConfigCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
protected override void ProcessRecord()
@@ -30,6 +31,7 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Getting cloud-init config for VM {VmId}...");
var json = client.GetAsync($"nodes/{Node}/qemu/{VmId}/config").GetAwaiter().GetResult();
var root = JObject.Parse(json);
var data = root["data"];
diff --git a/src/PSProxmoxVE/Cmdlets/CloudInit/InvokePveCloudInitRegenerateCmdlet.cs b/src/PSProxmoxVE/Cmdlets/CloudInit/InvokePveCloudInitRegenerateCmdlet.cs
index 4fbf998..c56146f 100644
--- a/src/PSProxmoxVE/Cmdlets/CloudInit/InvokePveCloudInitRegenerateCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/CloudInit/InvokePveCloudInitRegenerateCmdlet.cs
@@ -18,15 +18,16 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
public class InvokePveCloudInitRegenerateCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// When specified, waits for the regeneration task to complete before returning.
- [Parameter]
+ [Parameter(HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -35,6 +36,8 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
return;
var session = GetSession();
+
+ WriteVerbose($"Regenerating cloud-init drive for VM {VmId}...");
var service = new CloudInitService();
var upid = service.RegenerateCloudInitImage(session, Node, VmId);
diff --git a/src/PSProxmoxVE/Cmdlets/CloudInit/SetPveCloudInitConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/CloudInit/SetPveCloudInitConfigCmdlet.cs
index 6978072..b7df92a 100644
--- a/src/PSProxmoxVE/Cmdlets/CloudInit/SetPveCloudInitConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/CloudInit/SetPveCloudInitConfigCmdlet.cs
@@ -21,47 +21,48 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
public class SetPveCloudInitConfigCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// Cloud-init hostname override.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Cloud-init hostname override.")]
public string? Hostname { get; set; }
/// Cloud-init default username. Alias: User.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Cloud-init default username.")]
[Alias("User")]
public string? CiUser { get; set; }
/// Cloud-init default user password. Accepts a SecureString.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Cloud-init default user password.")]
public System.Security.SecureString? Password { get; set; }
/// SSH public keys to inject (one key per element).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "SSH public keys to inject.")]
public string[]? SshKeys { get; set; }
///
/// IP configuration string (e.g., "ip=192.168.1.50/24,gw=192.168.1.1").
/// Maps to ipconfig0 on the VM.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IP config string (e.g. ip=192.168.1.50/24,gw=...).")]
public string? IpConfig0 { get; set; }
/// DNS nameserver(s) to inject (space or comma separated).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS nameserver(s) to inject.")]
public string? Nameserver { get; set; }
/// DNS search domain to inject.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS search domain to inject.")]
public string? Searchdomain { get; set; }
/// When specified, waits for the config update task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -71,6 +72,7 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
if (!ShouldProcess($"VM {VmId} on {Node}", "Set PVE Cloud-Init Config"))
return;
+ WriteVerbose($"Setting cloud-init config for VM {VmId}...");
var config = new Dictionary();
if (!string.IsNullOrEmpty(CiUser)) config["ciuser"] = CiUser!;
diff --git a/src/PSProxmoxVE/Cmdlets/Connection/ConnectPveServerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Connection/ConnectPveServerCmdlet.cs
index c418f1d..d62e4cf 100644
--- a/src/PSProxmoxVE/Cmdlets/Connection/ConnectPveServerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Connection/ConnectPveServerCmdlet.cs
@@ -21,17 +21,17 @@ namespace PSProxmoxVE.Cmdlets.Connection
private const string ParameterSetApiToken = "ApiToken";
/// Hostname or IP address of the Proxmox VE server.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "Hostname or IP of the Proxmox VE server.")]
[ValidateNotNullOrEmpty]
public string Server { get; set; } = string.Empty;
/// API port. Defaults to 8006.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "API port. Defaults to 8006.")]
[ValidateRange(1, 65535)]
public int Port { get; set; } = 8006;
/// Username and password credential. Username must include a realm, e.g. root@pam.
- [Parameter(Mandatory = true, ParameterSetName = ParameterSetCredential)]
+ [Parameter(Mandatory = true, ParameterSetName = ParameterSetCredential, HelpMessage = "Username and password. Username must include realm (e.g. root@pam).")]
[ValidateNotNull]
public PSCredential? Credential { get; set; }
@@ -39,16 +39,16 @@ namespace PSProxmoxVE.Cmdlets.Connection
/// Proxmox VE API token in the format USER@REALM!TOKENID=UUID,
/// e.g. root@pam!mytoken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
///
- [Parameter(Mandatory = true, ParameterSetName = ParameterSetApiToken)]
+ [Parameter(Mandatory = true, ParameterSetName = ParameterSetApiToken, HelpMessage = "API token in USER@REALM!TOKENID=UUID format.")]
[ValidateNotNullOrEmpty]
public string? ApiToken { get; set; }
/// When specified, skips TLS certificate validation for the server.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Skip TLS certificate validation.")]
public SwitchParameter SkipCertificateCheck { get; set; }
/// When specified, writes the resulting PveSession object to the pipeline.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Output the session object to the pipeline.")]
public SwitchParameter PassThru { get; set; }
protected override void ProcessRecord()
@@ -116,6 +116,9 @@ namespace PSProxmoxVE.Cmdlets.Connection
ModuleState.ActiveSession = session;
+ if (SkipCertificateCheck.IsPresent)
+ WriteWarning("TLS certificate validation is disabled for this session. Connections are susceptible to man-in-the-middle attacks. Use only in trusted networks or test environments.");
+
WriteVerbose($"Connected to {Server}:{Port} as {session.AuthMode} (PVE {session.ServerVersion}).");
if (PassThru.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Connection/TestPveConnectionCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Connection/TestPveConnectionCmdlet.cs
index 77bac3e..7f50a18 100644
--- a/src/PSProxmoxVE/Cmdlets/Connection/TestPveConnectionCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Connection/TestPveConnectionCmdlet.cs
@@ -19,7 +19,7 @@ namespace PSProxmoxVE.Cmdlets.Connection
/// When specified, writes the PveSession object instead of a boolean.
/// Nothing is written if no session is active.
///
- [Parameter(Mandatory = false, ParameterSetName = "Detailed")]
+ [Parameter(Mandatory = false, ParameterSetName = "Detailed", HelpMessage = "Return the session object instead of a boolean.")]
public SwitchParameter Detailed { get; set; }
protected override void ProcessRecord()
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/CopyPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/CopyPveContainerCmdlet.cs
index f505adb..fdc0a17 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/CopyPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/CopyPveContainerCmdlet.cs
@@ -20,31 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Containers
///
/// The node on which the source container resides.
///
- [Parameter(Mandatory = true)]
+ [Parameter(Mandatory = true, HelpMessage = "The node where the source container resides.")]
public string SourceNode { get; set; } = string.Empty;
///
/// The ID of the source container to clone. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The container ID to assign to the new clone. When omitted, the next available ID is used.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Container ID for the new clone.")]
+ [ValidateRange(100, 999999999)]
public int? NewVmId { get; set; }
///
/// The hostname for the new clone.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Hostname for the new clone.")]
public string? NewName { get; set; }
///
/// The target node for the clone. Defaults to the source node.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Target node for the clone.")]
public string? TargetNode { get; set; }
///
@@ -53,19 +55,19 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// A full clone is required when the source container is not a template.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
public SwitchParameter Full { get; set; }
///
/// Target storage pool for the full clone root filesystem.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
public string? Storage { get; set; }
///
/// When specified, waits for the clone task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -77,6 +79,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Cloning container {VmId}...");
var task = containerService.CloneContainer(
session,
SourceNode,
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerCmdlet.cs
index 9709284..dd7b0b1 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerCmdlet.cs
@@ -23,36 +23,39 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// When omitted, containers from all nodes are returned.
///
///
- [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string? Node { get; set; }
///
/// Filter results to the container with this ID.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int? VmId { get; set; }
///
/// Filter results to containers whose name matches this value (case-insensitive, contains match).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by name.")]
public string? Name { get; set; }
///
/// Filter results to containers in the specified status (e.g., "running", "stopped").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by status (e.g. running, stopped).")]
public string? Status { get; set; }
///
/// Filter results to containers that have the specified tag (substring match against the semicolon-separated tags field).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by tag.")]
public string? Tag { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose("Getting containers...");
var service = new ContainerService();
IEnumerable containers = service.GetContainers(session, Node);
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerConfigCmdlet.cs
index 5cafd67..de3d263 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerConfigCmdlet.cs
@@ -20,13 +20,14 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container whose configuration to retrieve. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
protected override void ProcessRecord()
@@ -34,6 +35,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Getting config for container {VmId} on node '{Node}'...");
var config = containerService.GetContainerConfig(session, Node, VmId);
WriteObject(config);
}
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerSnapshotCmdlet.cs
new file mode 100644
index 0000000..9dfd7ee
--- /dev/null
+++ b/src/PSProxmoxVE/Cmdlets/Containers/GetPveContainerSnapshotCmdlet.cs
@@ -0,0 +1,54 @@
+using System.Linq;
+using System.Management.Automation;
+using PSProxmoxVE.Core.Models.Vms;
+using PSProxmoxVE.Core.Services;
+
+namespace PSProxmoxVE.Cmdlets.Containers
+{
+ ///
+ /// Lists snapshots for a Proxmox VE container.
+ ///
+ /// Returns all snapshots for the specified LXC container on the given node.
+ /// VmId can be piped from Get-PveContainer.
+ ///
+ ///
+ [Cmdlet(VerbsCommon.Get, "PveContainerSnapshot")]
+ [OutputType(typeof(PveSnapshot))]
+ public class GetPveContainerSnapshotCmdlet : PveCmdletBase
+ {
+ /// The Proxmox VE node name.
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
+ public string Node { get; set; } = string.Empty;
+
+ ///
+ /// The container identifier. Accepts pipeline input from Get-PveContainer (PveContainer.VmId).
+ ///
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
+ public int VmId { get; set; }
+
+ /// Optional filter: return only the snapshot with this name.
+ [Parameter(Mandatory = false, HelpMessage = "Filter by snapshot name.")]
+ public string? Name { get; set; }
+
+ protected override void ProcessRecord()
+ {
+ var session = GetSession();
+
+ WriteVerbose($"Getting snapshots for container {VmId} on node '{Node}'...");
+ var service = new ContainerService();
+
+ var snapshots = service.GetContainerSnapshots(session, Node, VmId);
+
+ if (!string.IsNullOrEmpty(Name))
+ snapshots = snapshots.Where(s => s.Name == Name).ToArray();
+
+ foreach (var snapshot in snapshots)
+ {
+ snapshot.VmId = VmId;
+ snapshot.Node = Node;
+ WriteObject(snapshot);
+ }
+ }
+ }
+}
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerCmdlet.cs
index 6d87b8d..30274db 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerCmdlet.cs
@@ -22,49 +22,50 @@ namespace PSProxmoxVE.Cmdlets.Containers
///
/// The node on which to create the container.
///
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The container ID to assign. When omitted, the next available ID is used.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int? VmId { get; set; }
///
/// The hostname to assign to the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The hostname for the container.")]
public string? Hostname { get; set; }
///
/// Memory limit in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Memory limit in MiB.")]
public int? Memory { get; set; }
///
/// Swap size in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Swap size in MiB.")]
public int? Swap { get; set; }
///
/// Number of CPU cores to allocate to the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU cores to allocate.")]
public int? Cores { get; set; }
///
/// Size of the root filesystem (e.g., "8G").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Size of the root filesystem (e.g. 8G).")]
public string? RootFsSize { get; set; }
///
/// Storage pool for the root filesystem (e.g., "local-lvm").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Storage pool for the root filesystem.")]
public string? RootFsStorage { get; set; }
///
@@ -72,19 +73,19 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The OS template to use (e.g., "local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst").
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "OS template to use for the container.")]
public string? OsTemplate { get; set; }
///
/// Root password for the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Root password for the container.")]
public System.Security.SecureString? Password { get; set; }
///
/// SSH public keys to inject for the root user (newline-separated).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "SSH public keys for the root user.")]
public string? SshPublicKeys { get; set; }
///
@@ -93,31 +94,31 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// To create a privileged container, explicitly set this to $false.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Run in unprivileged mode (default true).")]
public SwitchParameter Unprivileged { get; set; } = new SwitchParameter(true);
///
/// Network interface model (e.g., "eth0").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Network interface name (e.g. eth0).")]
public string? Network { get; set; }
///
/// Network bridge to attach to (e.g., "vmbr0").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Network bridge to attach to (e.g. vmbr0).")]
public string? Bridge { get; set; }
///
/// When specified, starts the container after creation.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Start the container after creation.")]
public SwitchParameter Start { get; set; }
///
/// When specified, waits for the creation task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -128,6 +129,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Creating container on node '{Node}'...");
var config = new Dictionary();
if (VmId.HasValue)
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerSnapshotCmdlet.cs
new file mode 100644
index 0000000..309c084
--- /dev/null
+++ b/src/PSProxmoxVE/Cmdlets/Containers/NewPveContainerSnapshotCmdlet.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Management.Automation;
+using Newtonsoft.Json.Linq;
+using PSProxmoxVE.Core.Client;
+using PSProxmoxVE.Core.Models.Vms;
+
+namespace PSProxmoxVE.Cmdlets.Containers
+{
+ ///
+ /// Creates a snapshot of a Proxmox VE container.
+ ///
+ /// Takes a snapshot of the specified LXC container.
+ /// Returns a PveTask. Use -Wait to block until the snapshot completes.
+ ///
+ ///
+ [Cmdlet(VerbsCommon.New, "PveContainerSnapshot", SupportsShouldProcess = true)]
+ [OutputType(typeof(PveTask))]
+ public class NewPveContainerSnapshotCmdlet : PveCmdletBase
+ {
+ /// The Proxmox VE node name.
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
+ public string Node { get; set; } = string.Empty;
+
+ /// The container identifier. Accepts pipeline input from Get-PveContainer (PveContainer.VmId).
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
+ public int VmId { get; set; }
+
+ /// The snapshot name (alphanumeric, hyphens and underscores).
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The snapshot name.")]
+ public string Name { get; set; } = string.Empty;
+
+ /// Optional human-readable description for the snapshot.
+ [Parameter(Mandatory = false, HelpMessage = "Description for the snapshot.")]
+ public string? Description { get; set; }
+
+ /// When specified, waits for the snapshot task to complete before returning.
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
+ public SwitchParameter Wait { get; set; }
+
+ protected override void ProcessRecord()
+ {
+ if (!ShouldProcess($"Container {VmId} on {Node}", $"Create snapshot '{Name}'"))
+ return;
+
+ var session = GetSession();
+ using var client = new PveHttpClient(session);
+
+ WriteVerbose($"Creating snapshot '{Name}' for container {VmId}...");
+ var data = new Dictionary
+ {
+ ["snapname"] = Name
+ };
+ if (!string.IsNullOrEmpty(Description)) data["description"] = Description!;
+
+ var json = client.PostAsync($"nodes/{Node}/lxc/{VmId}/snapshot", data).GetAwaiter().GetResult();
+ var root = JObject.Parse(json);
+ var upid = root["data"]?.ToString() ?? string.Empty;
+
+ var task = new PveTask { Upid = upid, Node = Node, Status = "running" };
+
+ if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
+ {
+ task = WaitForTask(client, Node, upid);
+ }
+
+ WriteObject(task);
+ }
+
+ private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
+ {
+ var encodedUpid = Uri.EscapeDataString(upid);
+ var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
+ while (true)
+ {
+ System.Threading.Thread.Sleep(2000);
+ var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
+ var statusRoot = JObject.Parse(statusJson);
+ var d = statusRoot["data"];
+ if (d?["status"]?.ToString() == "stopped")
+ return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
+ }
+ }
+ }
+}
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerCmdlet.cs
index f7b38a7..58fdfcd 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerCmdlet.cs
@@ -22,13 +22,14 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container to remove. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
@@ -36,7 +37,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// When specified, also removes the container from HA resource configuration and replication jobs.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
public SwitchParameter Purge { get; set; }
///
@@ -44,13 +45,13 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// When specified, bypasses locks and forces removal even if a lock is set on the container.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Force the operation without additional checks.")]
public SwitchParameter Force { get; set; }
///
/// When specified, waits for the removal task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -61,6 +62,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Removing container {VmId} from node '{Node}'...");
var task = containerService.RemoveContainer(session, Node, VmId, Purge.IsPresent);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerSnapshotCmdlet.cs
new file mode 100644
index 0000000..f4f0b9d
--- /dev/null
+++ b/src/PSProxmoxVE/Cmdlets/Containers/RemovePveContainerSnapshotCmdlet.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Management.Automation;
+using Newtonsoft.Json.Linq;
+using PSProxmoxVE.Core.Client;
+using PSProxmoxVE.Core.Models.Vms;
+
+namespace PSProxmoxVE.Cmdlets.Containers
+{
+ ///
+ /// Removes a snapshot from a Proxmox VE container.
+ ///
+ /// Deletes the specified snapshot from the LXC container.
+ /// Returns a PveTask. Use -Wait to block until removal completes.
+ ///
+ ///
+ [Cmdlet(VerbsCommon.Remove, "PveContainerSnapshot", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
+ [OutputType(typeof(PveTask))]
+ public class RemovePveContainerSnapshotCmdlet : PveCmdletBase
+ {
+ /// The Proxmox VE node name.
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
+ public string Node { get; set; } = string.Empty;
+
+ /// The container identifier.
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
+ public int VmId { get; set; }
+
+ ///
+ /// The snapshot name to remove. Accepts pipeline input from Get-PveContainerSnapshot (PveSnapshot.Name).
+ ///
+ [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to remove.")]
+ public string Name { get; set; } = string.Empty;
+
+ /// When specified, waits for the removal task to complete before returning.
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
+ public SwitchParameter Wait { get; set; }
+
+ protected override void ProcessRecord()
+ {
+ var session = GetSession();
+
+ if (!ShouldProcess($"Container {VmId} snapshot '{Name}' on {Node}", "Remove container snapshot"))
+ return;
+
+ WriteVerbose($"Removing snapshot '{Name}' from container {VmId}...");
+ using var client = new PveHttpClient(session);
+
+ var json = client.DeleteAsync($"nodes/{Node}/lxc/{VmId}/snapshot/{Name}").GetAwaiter().GetResult();
+ var root = JObject.Parse(json);
+ var upid = root["data"]?.ToString() ?? string.Empty;
+
+ var task = new PveTask { Upid = upid, Node = Node, Status = "running" };
+
+ if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
+ {
+ task = WaitForTask(client, Node, upid);
+ }
+
+ WriteObject(task);
+ }
+
+ private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
+ {
+ var encodedUpid = Uri.EscapeDataString(upid);
+ var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
+ while (true)
+ {
+ System.Threading.Thread.Sleep(2000);
+ var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
+ var statusRoot = JObject.Parse(statusJson);
+ var d = statusRoot["data"];
+ if (d?["status"]?.ToString() == "stopped")
+ return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
+ }
+ }
+ }
+}
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/RestartPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/RestartPveContainerCmdlet.cs
index c7e3986..c171f9d 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/RestartPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/RestartPveContainerCmdlet.cs
@@ -21,13 +21,14 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container to restart. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
@@ -35,13 +36,13 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// Timeout in seconds for the graceful shutdown phase. Defaults to 60 seconds.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
public int Timeout { get; set; } = 60;
///
/// When specified, waits for both shutdown and start tasks to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -53,6 +54,8 @@ namespace PSProxmoxVE.Cmdlets.Containers
var containerService = new ContainerService();
var taskService = new TaskService();
+ WriteVerbose($"Restarting container {VmId} on node '{Node}'...");
+
// Graceful shutdown
var shutdownTask = containerService.ShutdownContainer(session, Node, VmId, Timeout);
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/RestorePveContainerSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/RestorePveContainerSnapshotCmdlet.cs
new file mode 100644
index 0000000..d5977fb
--- /dev/null
+++ b/src/PSProxmoxVE/Cmdlets/Containers/RestorePveContainerSnapshotCmdlet.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Management.Automation;
+using Newtonsoft.Json.Linq;
+using PSProxmoxVE.Core.Client;
+using PSProxmoxVE.Core.Models.Vms;
+
+namespace PSProxmoxVE.Cmdlets.Containers
+{
+ ///
+ /// Rolls back a Proxmox VE container to a snapshot.
+ ///
+ /// Restores the container state to the specified snapshot, discarding all changes made since
+ /// the snapshot was taken. This is a destructive operation. Returns a PveTask.
+ /// Use -Wait to block until rollback completes.
+ ///
+ ///
+ [Cmdlet(VerbsData.Restore, "PveContainerSnapshot",
+ SupportsShouldProcess = true,
+ ConfirmImpact = ConfirmImpact.High)]
+ [OutputType(typeof(PveTask))]
+ public class RestorePveContainerSnapshotCmdlet : PveCmdletBase
+ {
+ /// The Proxmox VE node name.
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
+ public string Node { get; set; } = string.Empty;
+
+ /// The container identifier.
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
+ public int VmId { get; set; }
+
+ ///
+ /// The snapshot name to roll back to. Accepts pipeline input from Get-PveContainerSnapshot (PveSnapshot.Name).
+ ///
+ [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to roll back to.")]
+ public string Name { get; set; } = string.Empty;
+
+ /// When specified, waits for the rollback task to complete before returning.
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
+ public SwitchParameter Wait { get; set; }
+
+ protected override void ProcessRecord()
+ {
+ var session = GetSession();
+
+ if (!ShouldProcess($"Container {VmId} on {Node}", $"Restore snapshot '{Name}' (current state will be lost)"))
+ return;
+
+ WriteVerbose($"Restoring snapshot '{Name}' on container {VmId}...");
+ using var client = new PveHttpClient(session);
+
+ var json = client.PostAsync($"nodes/{Node}/lxc/{VmId}/snapshot/{Name}/rollback").GetAwaiter().GetResult();
+ var root = JObject.Parse(json);
+ var upid = root["data"]?.ToString() ?? string.Empty;
+
+ var task = new PveTask { Upid = upid, Node = Node, Status = "running" };
+
+ if (Wait.IsPresent && !string.IsNullOrEmpty(upid))
+ {
+ task = WaitForTask(client, Node, upid);
+ }
+
+ WriteObject(task);
+ }
+
+ private static PveTask WaitForTask(PveHttpClient client, string node, string upid)
+ {
+ var encodedUpid = Uri.EscapeDataString(upid);
+ var statusResource = $"nodes/{node}/tasks/{encodedUpid}/status";
+ while (true)
+ {
+ System.Threading.Thread.Sleep(2000);
+ var statusJson = client.GetAsync(statusResource).GetAwaiter().GetResult();
+ var statusRoot = JObject.Parse(statusJson);
+ var d = statusRoot["data"];
+ if (d?["status"]?.ToString() == "stopped")
+ return new PveTask { Upid = upid, Node = node, Status = "stopped", ExitStatus = d["exitstatus"]?.ToString() };
+ }
+ }
+ }
+}
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/SetPveContainerConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/SetPveContainerConfigCmdlet.cs
index 822e0a2..d1a9abd 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/SetPveContainerConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/SetPveContainerConfigCmdlet.cs
@@ -21,61 +21,62 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container to configure. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The hostname to assign to the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The hostname for the container.")]
public string? Hostname { get; set; }
///
/// Number of CPU cores to allocate to the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU cores to allocate.")]
public int? Cores { get; set; }
///
/// Memory limit in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Memory limit in MiB.")]
public int? Memory { get; set; }
///
/// Swap size in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Swap size in MiB.")]
public int? Swap { get; set; }
///
/// Human-readable description / notes for the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Description or notes for the container.")]
public string? Description { get; set; }
///
/// Semicolon-separated list of tags to assign to the container.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Semicolon-separated list of tags.")]
public string? Tags { get; set; }
///
/// DNS nameservers (space-separated).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS nameservers (space-separated).")]
public string? Nameserver { get; set; }
///
/// DNS search domain.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS search domain.")]
public string? SearchDomain { get; set; }
///
@@ -85,7 +86,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// Values are merged after named parameters and can override them.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Extra config keys as a hashtable.")]
public Hashtable? AdditionalConfig { get; set; }
///
@@ -94,7 +95,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// Maps to the PVE API "delete" parameter.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comma-separated config keys to delete.")]
public string? Delete { get; set; }
protected override void ProcessRecord()
@@ -105,6 +106,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Updating config for container {VmId} on node '{Node}'...");
var config = new Dictionary();
if (!string.IsNullOrEmpty(Hostname))
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/StartPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/StartPveContainerCmdlet.cs
index 6cceea7..9bd21f7 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/StartPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/StartPveContainerCmdlet.cs
@@ -20,19 +20,20 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container to start. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the start task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -43,6 +44,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Starting container {VmId} on node '{Node}'...");
var task = containerService.StartContainer(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/StopPveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/StopPveContainerCmdlet.cs
index 70c2129..b964338 100644
--- a/src/PSProxmoxVE/Cmdlets/Containers/StopPveContainerCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Containers/StopPveContainerCmdlet.cs
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// Use -Wait to block until the stop task completes.
///
///
- [Cmdlet(VerbsLifecycle.Stop, "PveContainer", SupportsShouldProcess = true)]
+ [Cmdlet(VerbsLifecycle.Stop, "PveContainer", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
[OutputType(typeof(PveTask))]
public sealed class StopPveContainerCmdlet : PveCmdletBase
{
@@ -22,19 +22,20 @@ namespace PSProxmoxVE.Cmdlets.Containers
/// The node on which the container resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the container to stop. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the stop task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -45,6 +46,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
var session = GetSession();
var containerService = new ContainerService();
+ WriteVerbose($"Stopping container {VmId} on node '{Node}'...");
var task = containerService.StopContainer(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveNetworkCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveNetworkCmdlet.cs
index 31c0bdd..7bd7bd9 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/GetPveNetworkCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveNetworkCmdlet.cs
@@ -20,16 +20,16 @@ namespace PSProxmoxVE.Cmdlets.Network
///
/// The Proxmox VE node name. Accepts pipeline input from Get-PveNode (PveNode.Name).
///
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
[Alias("NodeName")]
public string Node { get; set; } = string.Empty;
/// Filter results to this specific interface name (e.g., "vmbr0").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The network interface name.")]
public string? Iface { get; set; }
/// Filter by interface type (e.g., "bridge", "bond", "eth", "vlan").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by interface type (e.g. bridge, bond).")]
[ValidateSet("bridge", "bond", "eth", "alias", "vlan", "OVSBridge", "OVSBond",
"OVSPort", "OVSIntPort", "any_bridge", "any_local_bridge", IgnoreCase = true)]
public string? Type { get; set; }
@@ -39,6 +39,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Getting network interfaces on node '{Node}'...");
var resource = $"nodes/{Node}/network";
if (!string.IsNullOrEmpty(Type))
resource += $"?type={Uri.EscapeDataString(Type)}";
diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs
index 450c7c3..f8a629d 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnVnetCmdlet.cs
@@ -17,11 +17,11 @@ namespace PSProxmoxVE.Cmdlets.Network
public class GetPveSdnVnetCmdlet : PveCmdletBase
{
/// Filter VNets to a specific zone.
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "The SDN zone name.")]
public string? Zone { get; set; }
/// Optional VNet identifier to retrieve a specific VNet.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The SDN VNet name.")]
public string? Vnet { get; set; }
protected override void ProcessRecord()
@@ -29,6 +29,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose("Getting SDN VNets...");
var json = client.GetAsync("cluster/sdn/vnets").GetAwaiter().GetResult();
var root = JObject.Parse(json);
var data = root["data"] as JArray ?? new JArray();
diff --git a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs
index 8772187..f53277c 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/GetPveSdnZoneCmdlet.cs
@@ -16,7 +16,7 @@ namespace PSProxmoxVE.Cmdlets.Network
public class GetPveSdnZoneCmdlet : PveCmdletBase
{
/// Optional zone identifier to retrieve a specific zone.
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "The SDN zone name.")]
public string? Zone { get; set; }
protected override void ProcessRecord()
@@ -24,6 +24,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose("Getting SDN zones...");
var resource = "cluster/sdn/zones";
var json = client.GetAsync(resource).GetAwaiter().GetResult();
var root = JObject.Parse(json);
diff --git a/src/PSProxmoxVE/Cmdlets/Network/InvokePveNetworkApplyCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/InvokePveNetworkApplyCmdlet.cs
index d4c03f3..d82b1c3 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/InvokePveNetworkApplyCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/InvokePveNetworkApplyCmdlet.cs
@@ -19,11 +19,11 @@ namespace PSProxmoxVE.Cmdlets.Network
public class InvokePveNetworkApplyCmdlet : PveCmdletBase
{
/// The Proxmox VE node on which to apply network changes.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// When specified, waits for the apply task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -34,6 +34,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Applying network configuration on node '{Node}'...");
var json = client.PutAsync($"nodes/{Node}/network").GetAwaiter().GetResult();
var root = JObject.Parse(json);
var upid = root["data"]?.ToString() ?? string.Empty;
diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveNetworkCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveNetworkCmdlet.cs
index bb65721..83675e3 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/NewPveNetworkCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveNetworkCmdlet.cs
@@ -15,53 +15,53 @@ namespace PSProxmoxVE.Cmdlets.Network
public class NewPveNetworkCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The interface name (e.g., "vmbr1", "bond0").
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The network interface name.")]
public string Iface { get; set; } = string.Empty;
/// The interface type.
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The interface type (e.g. bridge, bond, vlan).")]
[ValidateSet("bridge", "bond", "eth", "alias", "vlan", "OVSBridge", "OVSBond",
"OVSPort", "OVSIntPort", IgnoreCase = true)]
public string Type { get; set; } = string.Empty;
/// IPv4 address for the interface.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 address for the interface.")]
public string? Address { get; set; }
/// IPv4 subnet mask.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 subnet mask.")]
public string? Netmask { get; set; }
/// IPv4 gateway address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 gateway address.")]
public string? Gateway { get; set; }
/// Bridge ports (space-separated interface names, for bridge type).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Bridge ports (space-separated interface names).")]
public string? BridgePorts { get; set; }
/// Bond slave interfaces (space-separated names, for bond type).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Bond slave interfaces (space-separated names).")]
public string? BondSlaves { get; set; }
/// VLAN tag ID (for vlan type).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "VLAN tag ID.")]
public int? VlanId { get; set; }
/// MTU override.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "MTU override.")]
public int? Mtu { get; set; }
/// Configure this interface to start automatically at boot.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Start interface automatically at boot.")]
public SwitchParameter Autostart { get; set; }
/// Optional comments/notes for this interface.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comments or notes for this interface.")]
public string? Comments { get; set; }
protected override void ProcessRecord()
@@ -72,6 +72,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating network interface '{Iface}' on node '{Node}'...");
var data = new Dictionary
{
["iface"] = Iface,
diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs
index b6cb1bd..f9d7011 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnVnetCmdlet.cs
@@ -14,23 +14,23 @@ namespace PSProxmoxVE.Cmdlets.Network
public class NewPveSdnVnetCmdlet : PveCmdletBase
{
/// The VNet identifier (alphanumeric, up to 8 characters).
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The SDN VNet name.")]
public string Vnet { get; set; } = string.Empty;
/// The SDN zone this VNet belongs to.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The SDN zone name.")]
public string Zone { get; set; } = string.Empty;
/// VLAN tag for VLAN-type zones.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "VLAN tag for VLAN-type zones.")]
public int? Tag { get; set; }
/// Optional alias/description for the VNet.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Alias or description for the VNet.")]
public string? Alias { get; set; }
/// Enable VLAN awareness on this VNet.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Enable VLAN awareness on this VNet.")]
public SwitchParameter VlanAware { get; set; }
protected override void ProcessRecord()
@@ -41,6 +41,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating SDN VNet '{Vnet}'...");
var data = new Dictionary
{
["vnet"] = Vnet,
diff --git a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs
index 1f4b3be..1ba4193 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/NewPveSdnZoneCmdlet.cs
@@ -14,40 +14,40 @@ namespace PSProxmoxVE.Cmdlets.Network
public class NewPveSdnZoneCmdlet : PveCmdletBase
{
/// The zone identifier (alphanumeric, hyphens allowed).
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The SDN zone name.")]
public string Zone { get; set; } = string.Empty;
/// The zone type.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The zone type (e.g. vlan, vxlan, evpn, simple).")]
[ValidateSet("vlan", "vxlan", "evpn", "simple", "qinq", IgnoreCase = true)]
public string Type { get; set; } = string.Empty;
/// VXLAN peer list or multicast address (for vxlan/evpn types).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "VXLAN peer list or multicast address.")]
public string? Peers { get; set; }
/// Bridge interface this zone attaches to (for vlan/qinq types).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Bridge interface for this zone.")]
public string? Bridge { get; set; }
/// MTU override for this zone.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "MTU override for this zone.")]
public int? Mtu { get; set; }
/// DNS server for automatic DNS registration.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS server for automatic registration.")]
public string? Dns { get; set; }
/// Reverse DNS server.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Reverse DNS server.")]
public string? ReverseDns { get; set; }
/// DNS zone name for registration.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "DNS zone name for registration.")]
public string? DnsZone { get; set; }
/// IPAM plugin to use for this zone.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPAM plugin to use.")]
public string? Ipam { get; set; }
protected override void ProcessRecord()
@@ -58,6 +58,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating SDN zone '{Zone}'...");
var data = new Dictionary
{
["zone"] = Zone,
diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveNetworkCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveNetworkCmdlet.cs
index ef0416d..99a0061 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveNetworkCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveNetworkCmdlet.cs
@@ -14,11 +14,11 @@ namespace PSProxmoxVE.Cmdlets.Network
public class RemovePveNetworkCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The interface name to remove.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The network interface name.")]
public string Iface { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -29,6 +29,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Removing network interface '{Iface}' on node '{Node}'...");
client.DeleteAsync($"nodes/{Node}/network/{Iface}").GetAwaiter().GetResult();
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs
index 679f79a..11e08ca 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnVnetCmdlet.cs
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Network
public class RemovePveSdnVnetCmdlet : PveCmdletBase
{
/// The VNet identifier to remove.
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The SDN VNet name.")]
public string Vnet { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -24,6 +24,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Removing SDN VNet '{Vnet}'...");
client.DeleteAsync($"cluster/sdn/vnets/{Vnet}").GetAwaiter().GetResult();
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs
index 02d7c5c..5702eab 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/RemovePveSdnZoneCmdlet.cs
@@ -14,7 +14,7 @@ namespace PSProxmoxVE.Cmdlets.Network
public class RemovePveSdnZoneCmdlet : PveCmdletBase
{
/// The zone identifier to remove.
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The SDN zone name.")]
public string Zone { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -25,6 +25,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Removing SDN zone '{Zone}'...");
client.DeleteAsync($"cluster/sdn/zones/{Zone}").GetAwaiter().GetResult();
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Network/SetPveNetworkCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Network/SetPveNetworkCmdlet.cs
index 91a5457..090f23f 100644
--- a/src/PSProxmoxVE/Cmdlets/Network/SetPveNetworkCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Network/SetPveNetworkCmdlet.cs
@@ -15,55 +15,55 @@ namespace PSProxmoxVE.Cmdlets.Network
public class SetPveNetworkCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The interface name to modify.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The network interface name.")]
public string Iface { get; set; } = string.Empty;
/// IPv4 address for the interface.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 address for the interface.")]
public string? Address { get; set; }
/// IPv4 subnet mask.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 subnet mask.")]
public string? Netmask { get; set; }
/// IPv4 gateway address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv4 gateway address.")]
public string? Gateway { get; set; }
/// IPv6 address for the interface.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv6 address for the interface.")]
public string? Address6 { get; set; }
/// IPv6 prefix length.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv6 prefix length.")]
public int? Netmask6 { get; set; }
/// IPv6 gateway address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "IPv6 gateway address.")]
public string? Gateway6 { get; set; }
/// Bridge ports (space-separated interface names).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Bridge ports (space-separated interface names).")]
public string? BridgePorts { get; set; }
/// Bond slave interfaces (space-separated names).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Bond slave interfaces (space-separated names).")]
public string? BondSlaves { get; set; }
/// MTU override.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "MTU override.")]
public int? Mtu { get; set; }
/// Configure this interface to start automatically at boot.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Start interface automatically at boot.")]
public SwitchParameter Autostart { get; set; }
/// Optional comments/notes for this interface.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comments or notes for this interface.")]
public string? Comments { get; set; }
protected override void ProcessRecord()
@@ -74,6 +74,7 @@ namespace PSProxmoxVE.Cmdlets.Network
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Updating network interface '{Iface}' on node '{Node}'...");
var data = new Dictionary();
if (!string.IsNullOrEmpty(Address)) data["address"] = Address!;
diff --git a/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeCmdlet.cs
index a8c63f1..bc9038c 100644
--- a/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeCmdlet.cs
@@ -20,7 +20,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
public sealed class GetPveNodeCmdlet : PveCmdletBase
{
/// Optional node name filter. When specified, only the matching node is returned.
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "Filter by node name.")]
[ValidateNotNullOrEmpty]
public string? Name { get; set; }
@@ -28,6 +28,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
{
var session = GetSession();
+ WriteVerbose("Getting cluster nodes...");
string responseBody;
try
{
diff --git a/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeStatusCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeStatusCmdlet.cs
index d618fd2..7215fe1 100644
--- a/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeStatusCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Nodes/GetPveNodeStatusCmdlet.cs
@@ -23,7 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
///
/// Name of the node to query. Accepts pipeline input via the PveNode.Name property.
///
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
[ValidateNotNullOrEmpty]
public string Node { get; set; } = string.Empty;
@@ -31,6 +31,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
{
var session = GetSession();
+ WriteVerbose($"Getting status for node '{Node}'...");
var resource = $"nodes/{Uri.EscapeDataString(Node)}/status";
string responseBody;
diff --git a/src/PSProxmoxVE/Cmdlets/Snapshots/GetPveSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Snapshots/GetPveSnapshotCmdlet.cs
index 6f506b6..9339409 100644
--- a/src/PSProxmoxVE/Cmdlets/Snapshots/GetPveSnapshotCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Snapshots/GetPveSnapshotCmdlet.cs
@@ -17,22 +17,25 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
public class GetPveSnapshotCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
///
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// Optional filter: return only the snapshot with this name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by snapshot name.")]
public string? Name { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Getting snapshots for VM {VmId} on node '{Node}'...");
var service = new SnapshotService();
var snapshots = service.GetSnapshots(session, Node, VmId);
diff --git a/src/PSProxmoxVE/Cmdlets/Snapshots/NewPveSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Snapshots/NewPveSnapshotCmdlet.cs
index 85e827e..c144e76 100644
--- a/src/PSProxmoxVE/Cmdlets/Snapshots/NewPveSnapshotCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Snapshots/NewPveSnapshotCmdlet.cs
@@ -19,27 +19,28 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
public class NewPveSnapshotCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// The snapshot name (alphanumeric, hyphens and underscores).
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The snapshot name.")]
public string Name { get; set; } = string.Empty;
/// Optional human-readable description for the snapshot.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Description for the snapshot.")]
public string? Description { get; set; }
/// When specified, includes the VM memory state in the snapshot.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Include VM memory state in the snapshot.")]
public SwitchParameter IncludeVmState { get; set; }
/// When specified, waits for the snapshot task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -50,6 +51,7 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating snapshot '{Name}' for VM {VmId}...");
var data = new Dictionary
{
["snapname"] = Name
diff --git a/src/PSProxmoxVE/Cmdlets/Snapshots/RemovePveSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Snapshots/RemovePveSnapshotCmdlet.cs
index c961b36..86dfd6b 100644
--- a/src/PSProxmoxVE/Cmdlets/Snapshots/RemovePveSnapshotCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Snapshots/RemovePveSnapshotCmdlet.cs
@@ -18,21 +18,22 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
public class RemovePveSnapshotCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The snapshot name to remove. Accepts pipeline input from Get-PveSnapshot (PveSnapshot.Name).
///
- [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to remove.")]
public string Name { get; set; } = string.Empty;
/// When specified, waits for the removal task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -41,6 +42,8 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
if (!ShouldProcess($"VM {VmId} snapshot '{Name}' on {Node}", "Remove PVE Snapshot"))
return;
+
+ WriteVerbose($"Removing snapshot '{Name}' from VM {VmId}...");
using var client = new PveHttpClient(session);
var json = client.DeleteAsync($"nodes/{Node}/qemu/{VmId}/snapshot/{Name}").GetAwaiter().GetResult();
diff --git a/src/PSProxmoxVE/Cmdlets/Snapshots/RestorePveSnapshotCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Snapshots/RestorePveSnapshotCmdlet.cs
index 8146ffd..2897432 100644
--- a/src/PSProxmoxVE/Cmdlets/Snapshots/RestorePveSnapshotCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Snapshots/RestorePveSnapshotCmdlet.cs
@@ -21,21 +21,22 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
public class RestorePveSnapshotCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The snapshot name to roll back to. Accepts pipeline input from Get-PveSnapshot (PveSnapshot.Name).
///
- [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to roll back to.")]
public string Name { get; set; } = string.Empty;
/// When specified, waits for the rollback task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -44,6 +45,8 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
if (!ShouldProcess($"VM {VmId} on {Node}", $"Restore snapshot '{Name}' (current state will be lost)"))
return;
+
+ WriteVerbose($"Restoring snapshot '{Name}' on VM {VmId}...");
using var client = new PveHttpClient(session);
var json = client.PostAsync($"nodes/{Node}/qemu/{VmId}/snapshot/{Name}/rollback").GetAwaiter().GetResult();
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageCmdlet.cs
index 0cac730..770e757 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageCmdlet.cs
@@ -20,25 +20,27 @@ namespace PSProxmoxVE.Cmdlets.Storage
/// The Proxmox VE node name. Accepts pipeline input from Get-PveNode (PveNode.Name).
/// When omitted the cluster-wide storage list is used.
///
- [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
[Alias("NodeName")]
public string? Node { get; set; }
/// Filter results to a specific storage name (e.g., "local", "local-lvm").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
public string? Storage { get; set; }
/// Filter results to a specific storage type (e.g., "dir", "nfs", "zfspool").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by storage type (e.g. dir, nfs, zfspool).")]
public string? Type { get; set; }
/// Filter results to storages that support the given content type (e.g., "iso", "backup").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by content type (e.g. iso, backup).")]
public string? ContentType { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose("Getting storage pools...");
var service = new StorageService();
var storages = service.GetStorages(session, Node);
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageContentCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageContentCmdlet.cs
index 7382fbb..7387a71 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageContentCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/GetPveStorageContentCmdlet.cs
@@ -16,22 +16,24 @@ namespace PSProxmoxVE.Cmdlets.Storage
public class GetPveStorageContentCmdlet : PveCmdletBase
{
/// The Proxmox VE node name that hosts the storage.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The storage identifier. Accepts pipeline input from Get-PveStorage (PveStorage.Storage).
///
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The storage pool name.")]
public string Storage { get; set; } = string.Empty;
/// Filter results to a specific content type (e.g., "iso", "vztmpl", "backup", "images").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by content type (e.g. iso, vztmpl, backup).")]
public string? ContentType { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Getting content for storage '{Storage}' on node '{Node}'...");
var service = new StorageService();
var items = service.GetStorageContent(session, Node, Storage, ContentType);
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/InvokePveStorageDownloadCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/InvokePveStorageDownloadCmdlet.cs
index 69414d3..c04a5d6 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/InvokePveStorageDownloadCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/InvokePveStorageDownloadCmdlet.cs
@@ -19,28 +19,28 @@ namespace PSProxmoxVE.Cmdlets.Storage
public class InvokePveStorageDownloadCmdlet : PveCmdletBase
{
/// The Proxmox VE node that will perform the download.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The target storage identifier.
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The storage pool name.")]
public string Storage { get; set; } = string.Empty;
/// The URL to download the file from.
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The URL to download the file from.")]
public string Url { get; set; } = string.Empty;
/// The filename to save the downloaded file as on the storage.
- [Parameter(Mandatory = true, Position = 3)]
+ [Parameter(Mandatory = true, Position = 3, HelpMessage = "Filename to save the download as.")]
public string Filename { get; set; } = string.Empty;
/// The content type category for the downloaded file. Defaults to "iso".
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Content type category. Defaults to iso.")]
[ValidateSet("iso", "vztmpl", "backup", "import", IgnoreCase = true)]
public string ContentType { get; set; } = "iso";
/// When specified, waits for the download task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -51,6 +51,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Downloading '{Url}' to {Node}/{Storage}...");
var resource = $"nodes/{Node}/storage/{Storage}/download-url";
var data = new Dictionary
{
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/NewPveStorageCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/NewPveStorageCmdlet.cs
index 4a9b69f..8e321f1 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/NewPveStorageCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/NewPveStorageCmdlet.cs
@@ -18,61 +18,61 @@ namespace PSProxmoxVE.Cmdlets.Storage
public class NewPveStorageCmdlet : PveCmdletBase
{
/// The unique storage identifier/name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The storage pool name.")]
public string Storage { get; set; } = string.Empty;
/// The storage type (e.g., "dir", "nfs", "lvm", "zfspool", "cephfs", "rbd").
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The storage type (e.g. dir, nfs, lvm, zfspool).")]
[ValidateSet("dir", "nfs", "lvm", "lvmthin", "zfspool", "zfs", "cephfs", "rbd",
"iscsi", "iscsidirect", "glusterfs", "cifs", "pbs", IgnoreCase = true)]
public string Type { get; set; } = string.Empty;
/// Comma-separated list of content types to support (e.g., "iso,vztmpl,backup").
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comma-separated content types to support.")]
public string? Content { get; set; }
/// Base directory path (for "dir" type storages).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Base directory path (for dir type).")]
public string? Path { get; set; }
/// NFS/CIFS server hostname or IP address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "NFS/CIFS server hostname or IP.")]
public string? Server { get; set; }
/// NFS export path or CIFS share name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "NFS export path or CIFS share name.")]
public string? Export { get; set; }
/// LVM volume group name (for "lvm"/"lvmthin" types).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "LVM volume group name.")]
public string? VgName { get; set; }
/// LVM thin pool name (for "lvmthin" type).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "LVM thin pool name.")]
public string? ThinPool { get; set; }
/// ZFS pool name (for "zfspool" type).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "ZFS pool name.")]
public string? Pool { get; set; }
/// Ceph pool name (for "rbd"/"cephfs" types).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Ceph pool name.")]
public string? CephPool { get; set; }
/// Monitor list for Ceph storages (comma-separated host:port pairs).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Ceph monitor host list.")]
public string? MonHost { get; set; }
/// Whether this storage is shared across cluster nodes.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Storage is shared across cluster nodes.")]
public SwitchParameter Shared { get; set; }
/// Whether this storage is enabled. Defaults to enabled.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Create the storage in disabled state.")]
public SwitchParameter Disable { get; set; }
/// Limit nodes that can access this storage (comma-separated node names).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Limit access to these nodes (comma-separated).")]
public string? Nodes { get; set; }
protected override void ProcessRecord()
@@ -83,6 +83,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating storage '{Storage}'...");
var data = new Dictionary
{
["storage"] = Storage,
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/RemovePveStorageCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/RemovePveStorageCmdlet.cs
index 4399113..9393ed3 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/RemovePveStorageCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/RemovePveStorageCmdlet.cs
@@ -16,7 +16,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
public class RemovePveStorageCmdlet : PveCmdletBase
{
/// The storage identifier to remove.
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The storage pool name.")]
public string Storage { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -27,6 +27,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Removing storage '{Storage}'...");
client.DeleteAsync($"storage/{Storage}").GetAwaiter().GetResult();
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Storage/SendPveIsoCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Storage/SendPveIsoCmdlet.cs
index f4a71ba..3281e5e 100644
--- a/src/PSProxmoxVE/Cmdlets/Storage/SendPveIsoCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Storage/SendPveIsoCmdlet.cs
@@ -20,33 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Storage
public class SendPveIsoCmdlet : PveCmdletBase
{
/// The Proxmox VE node to upload to.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The target storage identifier (must support "iso" content).
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The storage pool name.")]
public string Storage { get; set; } = string.Empty;
///
/// The full local path to the ISO file to upload. The file must exist.
///
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "Local path to the ISO file to upload.")]
[FileExistsValidation]
public string Path { get; set; } = string.Empty;
/// Optional checksum value to verify the uploaded file.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Checksum value to verify the upload.")]
public string? Checksum { get; set; }
/// Checksum algorithm used for verification.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Checksum algorithm (md5, sha1, sha256, sha512).")]
[ValidateSet("md5", "sha1", "sha256", "sha512", IgnoreCase = true)]
public string? ChecksumAlgorithm { get; set; }
///
/// When specified, waits for the upload task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -58,6 +58,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Uploading ISO to {Node}/{Storage}...");
var resource = $"nodes/{Node}/storage/{Storage}/upload";
var totalBytes = new System.IO.FileInfo(Path).Length;
diff --git a/src/PSProxmoxVE/Cmdlets/Tasks/GetPveTaskCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Tasks/GetPveTaskCmdlet.cs
index e953709..77da2f2 100644
--- a/src/PSProxmoxVE/Cmdlets/Tasks/GetPveTaskCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Tasks/GetPveTaskCmdlet.cs
@@ -17,16 +17,18 @@ namespace PSProxmoxVE.Cmdlets.Tasks
public class GetPveTaskCmdlet : PveCmdletBase
{
/// The node on which the task ran.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The UPID of the task to query.
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The task UPID.")]
public string Upid { get; set; } = string.Empty;
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Getting task status for UPID on node '{Node}'...");
var service = new TaskService();
var task = service.GetTask(session, Node, Upid);
WriteObject(task);
diff --git a/src/PSProxmoxVE/Cmdlets/Tasks/WaitPveTaskCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Tasks/WaitPveTaskCmdlet.cs
index a907bdf..8c68b97 100644
--- a/src/PSProxmoxVE/Cmdlets/Tasks/WaitPveTaskCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Tasks/WaitPveTaskCmdlet.cs
@@ -21,27 +21,27 @@ namespace PSProxmoxVE.Cmdlets.Tasks
public class WaitPveTaskCmdlet : PveCmdletBase
{
/// The node on which the task is running.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The UPID of the task to wait for. Accepts pipeline input from PveTask (PveTask.Upid).
///
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The task UPID.")]
public string Upid { get; set; } = string.Empty;
///
/// Maximum time to wait for the task. Defaults to no timeout.
/// Example: -Timeout (New-TimeSpan -Minutes 10)
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
public TimeSpan? Timeout { get; set; }
///
/// How frequently to poll the task status. Defaults to 2 seconds.
/// Example: -PollInterval (New-TimeSpan -Seconds 5)
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "How often to poll task status.")]
public TimeSpan? PollInterval { get; set; }
protected override void ProcessRecord()
diff --git a/src/PSProxmoxVE/Cmdlets/Templates/GetPveTemplateCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Templates/GetPveTemplateCmdlet.cs
index 2ad98d8..dd152b0 100644
--- a/src/PSProxmoxVE/Cmdlets/Templates/GetPveTemplateCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Templates/GetPveTemplateCmdlet.cs
@@ -17,11 +17,11 @@ namespace PSProxmoxVE.Cmdlets.Templates
public class GetPveTemplateCmdlet : PveCmdletBase
{
/// The Proxmox VE node name. When omitted, queries all nodes in the cluster.
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "The PVE node name.")]
public string? Node { get; set; }
/// Filter results by template name. Supports wildcard (*) matching.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by template name (supports wildcards).")]
public string? Name { get; set; }
protected override void ProcessRecord()
@@ -29,6 +29,7 @@ namespace PSProxmoxVE.Cmdlets.Templates
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose("Getting templates...");
var nodesToQuery = new System.Collections.Generic.List();
if (!string.IsNullOrEmpty(Node))
diff --git a/src/PSProxmoxVE/Cmdlets/Templates/NewPveTemplateCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Templates/NewPveTemplateCmdlet.cs
index 237d421..9b6f109 100644
--- a/src/PSProxmoxVE/Cmdlets/Templates/NewPveTemplateCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Templates/NewPveTemplateCmdlet.cs
@@ -17,15 +17,16 @@ namespace PSProxmoxVE.Cmdlets.Templates
public class NewPveTemplateCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier to convert. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// When specified, waits for the conversion task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -34,6 +35,8 @@ namespace PSProxmoxVE.Cmdlets.Templates
if (!ShouldProcess($"VM {VmId} on {Node}", "Convert to PVE Template (irreversible)"))
return;
+
+ WriteVerbose($"Converting VM {VmId} to template...");
var service = new TemplateService();
var task = service.CreateTemplate(session, Node, VmId);
diff --git a/src/PSProxmoxVE/Cmdlets/Templates/NewPveVmFromTemplateCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Templates/NewPveVmFromTemplateCmdlet.cs
index 8de4e73..1d5bdff 100644
--- a/src/PSProxmoxVE/Cmdlets/Templates/NewPveVmFromTemplateCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Templates/NewPveVmFromTemplateCmdlet.cs
@@ -18,27 +18,29 @@ namespace PSProxmoxVE.Cmdlets.Templates
public class NewPveVmFromTemplateCmdlet : PveCmdletBase
{
/// The node where the source template resides. Alias: Node.
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The node where the template resides.")]
[Alias("Node")]
public string TemplateNode { get; set; } = string.Empty;
/// The source template VM ID. Accepts pipeline input from Get-PveTemplate (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// The VM ID for the new cloned VM.
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "VM ID for the new cloned VM.")]
+ [ValidateRange(100, 999999999)]
public int NewVmId { get; set; }
/// Optional name for the new VM.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Name for the new VM.")]
public string? NewName { get; set; }
///
/// The target node for the new VM. When omitted, the new VM is created on the same node
/// as the template.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Target node for the new VM.")]
public string? TargetNode { get; set; }
///
@@ -46,11 +48,11 @@ namespace PSProxmoxVE.Cmdlets.Templates
/// When omitted, creates a linked clone (shares base disk with template).
/// Linked clones require the template to reside on shared storage.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
public SwitchParameter Full { get; set; }
/// When specified, waits for the clone task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -60,6 +62,8 @@ namespace PSProxmoxVE.Cmdlets.Templates
var session = GetSession();
var service = new VmService();
+
+ WriteVerbose($"Cloning VM from template {VmId}...");
var task = service.CloneVm(
session,
TemplateNode,
diff --git a/src/PSProxmoxVE/Cmdlets/Templates/RemovePveTemplateCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Templates/RemovePveTemplateCmdlet.cs
index edf58ca..07a2391 100644
--- a/src/PSProxmoxVE/Cmdlets/Templates/RemovePveTemplateCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Templates/RemovePveTemplateCmdlet.cs
@@ -18,19 +18,20 @@ namespace PSProxmoxVE.Cmdlets.Templates
public class RemovePveTemplateCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM/template identifier to remove. Accepts pipeline input from Get-PveVm (PveVm.VmId).
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// When specified, also removes all associated backup files and jobs.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
public SwitchParameter Purge { get; set; }
/// When specified, waits for the deletion task to complete before returning.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -40,6 +41,8 @@ namespace PSProxmoxVE.Cmdlets.Templates
var session = GetSession();
var service = new TemplateService();
+
+ WriteVerbose($"Removing template {VmId}...");
var task = service.RemoveTemplate(session, Node, VmId, Purge.IsPresent);
if (Wait.IsPresent && !string.IsNullOrEmpty(task.Upid))
diff --git a/src/PSProxmoxVE/Cmdlets/Users/GetPveApiTokenCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/GetPveApiTokenCmdlet.cs
index 3a0d320..d892739 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/GetPveApiTokenCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/GetPveApiTokenCmdlet.cs
@@ -21,16 +21,18 @@ namespace PSProxmoxVE.Cmdlets.Users
/// The user ID whose tokens to list, in "username@realm" format (e.g., "admin@pam").
/// Accepts pipeline input from Get-PveUser (PveUser.UserId).
///
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
/// Filter to a specific token identifier (e.g., "automation").
- [Parameter(Mandatory = false, Position = 1)]
+ [Parameter(Mandatory = false, Position = 1, HelpMessage = "The API token identifier.")]
public string? TokenId { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Getting API tokens for user '{UserId}'...");
var service = new UserService();
var tokens = service.GetApiTokens(session, UserId);
diff --git a/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
index c9f98dc..71da372 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
@@ -17,16 +17,18 @@ namespace PSProxmoxVE.Cmdlets.Users
public class GetPvePermissionCmdlet : PveCmdletBase
{
/// Filter results to a specific resource path (e.g., "/", "/vms/100").
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "Filter by resource path (e.g. /, /vms/100).")]
public string? Path { get; set; }
/// Filter results to a specific user or group ID.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The user ID in user@realm format.")]
public string? UserId { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose("Getting permissions...");
var service = new UserService();
var permissions = service.GetPermissions(session);
diff --git a/src/PSProxmoxVE/Cmdlets/Users/GetPveRoleCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/GetPveRoleCmdlet.cs
index 3369680..21f7ca8 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/GetPveRoleCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/GetPveRoleCmdlet.cs
@@ -17,7 +17,7 @@ namespace PSProxmoxVE.Cmdlets.Users
public class GetPveRoleCmdlet : PveCmdletBase
{
/// Optional role identifier to retrieve a specific role.
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "The role identifier.")]
public string? RoleId { get; set; }
protected override void ProcessRecord()
@@ -25,6 +25,7 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose("Getting roles...");
var json = client.GetAsync("access/roles").GetAwaiter().GetResult();
var root = JObject.Parse(json);
var data = root["data"] as JArray ?? new JArray();
diff --git a/src/PSProxmoxVE/Cmdlets/Users/GetPveUserCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/GetPveUserCmdlet.cs
index c04efd1..eb69aab 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/GetPveUserCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/GetPveUserCmdlet.cs
@@ -20,11 +20,11 @@ namespace PSProxmoxVE.Cmdlets.Users
/// Filter results to a specific user ID or pattern (e.g., "admin@pam", "*@pve").
/// Supports wildcard (*) matching.
///
- [Parameter(Mandatory = false, Position = 0)]
+ [Parameter(Mandatory = false, Position = 0, HelpMessage = "The user ID in user@realm format.")]
public string? UserId { get; set; }
/// When specified, returns only enabled users.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Return only enabled users.")]
[Alias("EnabledOnly")]
public SwitchParameter Enabled { get; set; }
@@ -33,6 +33,7 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose("Getting users...");
var json = client.GetAsync("access/users").GetAwaiter().GetResult();
var root = JObject.Parse(json);
var data = root["data"] as JArray ?? new JArray();
diff --git a/src/PSProxmoxVE/Cmdlets/Users/NewPveApiTokenCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/NewPveApiTokenCmdlet.cs
index ce4bb01..50d8eb3 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/NewPveApiTokenCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/NewPveApiTokenCmdlet.cs
@@ -21,21 +21,21 @@ namespace PSProxmoxVE.Cmdlets.Users
/// The user ID to create the token for, in "username@realm" format (e.g., "admin@pam").
/// Accepts pipeline input from Get-PveUser (PveUser.UserId).
///
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
/// The token identifier (alphanumeric, hyphens allowed; e.g., "automation").
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The API token identifier.")]
public string TokenId { get; set; } = string.Empty;
/// Optional description for this token.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Description for this token.")]
public string? Comment { get; set; }
///
/// Token expiry as a Unix timestamp. Use 0 or omit for no expiry.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Token expiry as a Unix timestamp.")]
public long? Expire { get; set; }
///
@@ -43,7 +43,7 @@ namespace PSProxmoxVE.Cmdlets.Users
/// are the intersection of the user's ACLs and any explicit ACLs granted to the token.
/// When omitted, the token inherits the full permissions of its user.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Enable token privilege separation.")]
public SwitchParameter PrivilegeSeparation { get; set; }
protected override void ProcessRecord()
@@ -54,6 +54,8 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
var service = new UserService();
+
+ WriteVerbose($"Creating API token '{TokenId}' for user '{UserId}'...");
var token = service.CreateApiToken(
session,
UserId,
diff --git a/src/PSProxmoxVE/Cmdlets/Users/NewPveRoleCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/NewPveRoleCmdlet.cs
index 05938ab..01560b0 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/NewPveRoleCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/NewPveRoleCmdlet.cs
@@ -16,14 +16,14 @@ namespace PSProxmoxVE.Cmdlets.Users
public class NewPveRoleCmdlet : PveCmdletBase
{
/// The role identifier/name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The role identifier.")]
public string RoleId { get; set; } = string.Empty;
///
/// Comma-separated list of privileges to grant this role
/// (e.g., "VM.Allocate,VM.Config.CPU,VM.Config.Memory").
///
- [Parameter(Mandatory = false, Position = 1)]
+ [Parameter(Mandatory = false, Position = 1, HelpMessage = "Comma-separated list of privileges.")]
public string? Privileges { get; set; }
protected override void ProcessRecord()
@@ -34,6 +34,7 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Creating role '{RoleId}'...");
var data = new Dictionary
{
["roleid"] = RoleId
diff --git a/src/PSProxmoxVE/Cmdlets/Users/NewPveUserCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/NewPveUserCmdlet.cs
index 34a0e39..a9a404d 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/NewPveUserCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/NewPveUserCmdlet.cs
@@ -18,35 +18,35 @@ namespace PSProxmoxVE.Cmdlets.Users
public class NewPveUserCmdlet : PveCmdletBase
{
/// The user identifier in "user@realm" format (e.g., "jdoe@pve").
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
/// The user's password (for pve/pam realms). Accepts a SecureString.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Password for the user.")]
public System.Security.SecureString? Password { get; set; }
/// The user's first name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The user's first name.")]
public string? FirstName { get; set; }
/// The user's last name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The user's last name.")]
public string? LastName { get; set; }
/// The user's email address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The user's email address.")]
public string? Email { get; set; }
/// Comma-separated list of groups to add this user to.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comma-separated list of groups.")]
public string? Groups { get; set; }
/// Optional comment/notes for this user.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comment or notes for this user.")]
public string? Comment { get; set; }
/// Account expiry as a Unix timestamp. Use 0 for no expiry.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Account expiry as a Unix timestamp.")]
public long? Expire { get; set; }
protected override void ProcessRecord()
@@ -72,6 +72,8 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
var service = new UserService();
+
+ WriteVerbose($"Creating user '{UserId}'...");
service.CreateUser(session, UserId, config);
WriteObject(new PveUser
diff --git a/src/PSProxmoxVE/Cmdlets/Users/RemovePveApiTokenCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/RemovePveApiTokenCmdlet.cs
index d065f76..b17ca2d 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/RemovePveApiTokenCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/RemovePveApiTokenCmdlet.cs
@@ -18,14 +18,14 @@ namespace PSProxmoxVE.Cmdlets.Users
/// The user ID that owns the token, in "username@realm" format (e.g., "admin@pam").
/// Accepts pipeline input from Get-PveApiToken (PveApiToken.UserId).
///
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
///
/// The token identifier to remove (e.g., "automation").
/// Accepts pipeline input from Get-PveApiToken (PveApiToken.TokenId).
///
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The API token identifier.")]
public string TokenId { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -35,6 +35,7 @@ namespace PSProxmoxVE.Cmdlets.Users
if (!ShouldProcess($"{UserId}!{TokenId}", "Remove PVE API Token"))
return;
+ WriteVerbose($"Removing API token '{TokenId}' from user '{UserId}'...");
var service = new UserService();
service.RemoveApiToken(session, UserId, TokenId);
}
diff --git a/src/PSProxmoxVE/Cmdlets/Users/RemovePveRoleCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/RemovePveRoleCmdlet.cs
index 98aaa0d..c627068 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/RemovePveRoleCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/RemovePveRoleCmdlet.cs
@@ -14,7 +14,7 @@ namespace PSProxmoxVE.Cmdlets.Users
public class RemovePveRoleCmdlet : PveCmdletBase
{
/// The role identifier to remove.
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The role identifier.")]
public string RoleId { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -24,6 +24,8 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
var service = new UserService();
+
+ WriteVerbose($"Removing role '{RoleId}'...");
service.RemoveRole(session, RoleId);
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Users/RemovePveUserCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/RemovePveUserCmdlet.cs
index 34506e9..1961968 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/RemovePveUserCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/RemovePveUserCmdlet.cs
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Users
public class RemovePveUserCmdlet : PveCmdletBase
{
/// The user identifier to remove (e.g., "jdoe@pve").
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
protected override void ProcessRecord()
@@ -23,6 +23,8 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
var service = new UserService();
+
+ WriteVerbose($"Removing user '{UserId}'...");
service.RemoveUser(session, UserId);
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Users/SetPvePermissionCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/SetPvePermissionCmdlet.cs
index e3b79af..f0c4795 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/SetPvePermissionCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/SetPvePermissionCmdlet.cs
@@ -15,28 +15,28 @@ namespace PSProxmoxVE.Cmdlets.Users
public class SetPvePermissionCmdlet : PveCmdletBase
{
/// The resource path this ACL applies to (e.g., "/", "/vms/100").
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The resource path (e.g. /, /vms/100).")]
public string Path { get; set; } = string.Empty;
/// The user or group identifier (e.g., "jdoe@pve" or "admins").
- [Parameter(Mandatory = true, Position = 1)]
+ [Parameter(Mandatory = true, Position = 1, HelpMessage = "The user or group identifier.")]
public string UgId { get; set; } = string.Empty;
/// The role to assign (e.g., "Administrator", "PVEVMUser").
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The role to assign (e.g. Administrator).")]
public string Role { get; set; } = string.Empty;
/// The ACL entry type: "user" or "group".
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "ACL entry type: user or group.")]
[ValidateSet("user", "group", IgnoreCase = true)]
public string Type { get; set; } = "user";
/// Whether to propagate this ACL to child paths.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Propagate this ACL to child paths.")]
public SwitchParameter Propagate { get; set; }
/// When specified, removes the ACL entry instead of adding it.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Remove the ACL entry instead of adding it.")]
public SwitchParameter Delete { get; set; }
protected override void ProcessRecord()
@@ -48,6 +48,7 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
using var client = new PveHttpClient(session);
+ WriteVerbose($"Setting permission for '{UgId}' at '{Path}'...");
var data = new Dictionary
{
["path"] = Path,
diff --git a/src/PSProxmoxVE/Cmdlets/Users/SetPveUserCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/SetPveUserCmdlet.cs
index b3f0277..bab31c7 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/SetPveUserCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/SetPveUserCmdlet.cs
@@ -16,39 +16,39 @@ namespace PSProxmoxVE.Cmdlets.Users
public class SetPveUserCmdlet : PveCmdletBase
{
/// The user identifier to update (e.g., "jdoe@pve").
- [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, HelpMessage = "The user ID in user@realm format.")]
public string UserId { get; set; } = string.Empty;
/// New password for the user. Accepts a SecureString.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "New password for the user.")]
public System.Security.SecureString? Password { get; set; }
/// Updated first name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Updated first name.")]
public string? FirstName { get; set; }
/// Updated last name.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Updated last name.")]
public string? LastName { get; set; }
/// Updated email address.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Updated email address.")]
public string? Email { get; set; }
/// Updated group membership (comma-separated group names).
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Updated group membership (comma-separated).")]
public string? Groups { get; set; }
/// Updated comment/notes.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Updated comment or notes.")]
public string? Comment { get; set; }
/// Account expiry as a Unix timestamp. Use 0 to remove expiry.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Account expiry as a Unix timestamp.")]
public long? Expire { get; set; }
/// Enable or disable the user account.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Enable or disable the user account.")]
public bool? Enable { get; set; }
protected override void ProcessRecord()
@@ -75,6 +75,8 @@ namespace PSProxmoxVE.Cmdlets.Users
var session = GetSession();
var service = new UserService();
+
+ WriteVerbose($"Updating user '{UserId}'...");
service.SetUser(session, UserId, config);
}
}
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/CopyPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/CopyPveVmCmdlet.cs
index bd7ed15..6b6237b 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/CopyPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/CopyPveVmCmdlet.cs
@@ -20,31 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Vms
///
/// The node on which the source VM resides.
///
- [Parameter(Mandatory = true)]
+ [Parameter(Mandatory = true, HelpMessage = "The node where the source VM resides.")]
public string SourceNode { get; set; } = string.Empty;
///
/// The ID of the source VM to clone. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The VM ID to assign to the new clone. When omitted, the next available ID is used.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "VM ID for the new clone.")]
+ [ValidateRange(100, 999999999)]
public int? NewVmId { get; set; }
///
/// The display name for the new clone.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Display name for the new clone.")]
public string? NewName { get; set; }
///
/// The target node for the clone. Defaults to the source node.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Target node for the clone.")]
public string? TargetNode { get; set; }
///
@@ -53,19 +55,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// A full clone is required when the source VM is not a template.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
public SwitchParameter Full { get; set; }
///
/// Target storage pool for the full clone disks.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
public string? Storage { get; set; }
///
/// When specified, waits for the clone task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -77,6 +79,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Cloning VM {VmId}...");
var newid = NewVmId ?? 0;
var task = vmService.CloneVm(session, SourceNode, VmId, newid, NewName, TargetNode, Full.IsPresent);
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmCmdlet.cs
index a3532c0..ca8de89 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmCmdlet.cs
@@ -23,42 +23,45 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// When omitted, VMs from all nodes are returned.
///
///
- [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string? Node { get; set; }
///
/// Filter results to the VM with this ID.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int? VmId { get; set; }
///
/// Filter results to VMs whose name matches this value (case-insensitive, contains match).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by name.")]
public string? Name { get; set; }
///
/// Filter results to VMs in the specified status (e.g., "running", "stopped").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by status (e.g. running, stopped).")]
public string? Status { get; set; }
///
/// Filter results to VMs that have the specified tag (substring match against the semicolon-separated tags field).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Filter by tag.")]
public string? Tag { get; set; }
///
/// When specified, returns only VMs that are marked as templates.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Return only VMs marked as templates.")]
public SwitchParameter TemplatesOnly { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose("Getting VMs...");
var service = new VmService();
IEnumerable vms = service.GetVms(session, Node);
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmConfigCmdlet.cs
index f4b8696..3adfe85 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmConfigCmdlet.cs
@@ -20,13 +20,14 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM whose configuration to retrieve. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
protected override void ProcessRecord()
@@ -34,6 +35,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Getting config for VM {VmId} on node '{Node}'...");
var config = vmService.GetVmConfig(session, Node, VmId);
WriteObject(config);
}
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmGuestNetworkCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmGuestNetworkCmdlet.cs
index c39fb4e..229b1fd 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmGuestNetworkCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/GetPveVmGuestNetworkCmdlet.cs
@@ -17,16 +17,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
public sealed class GetPveVmGuestNetworkCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier.
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Getting guest network interfaces for VM {VmId}...");
var service = new VmService();
var interfaces = service.GetGuestNetworkInterfaces(session, Node, VmId);
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/InvokePveVmGuestExecCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/InvokePveVmGuestExecCmdlet.cs
index 057ee93..96e80b0 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/InvokePveVmGuestExecCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/InvokePveVmGuestExecCmdlet.cs
@@ -11,31 +11,36 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// installed and running inside the VM.
///
///
- [Cmdlet(VerbsLifecycle.Invoke, "PveVmGuestExec")]
+ [Cmdlet(VerbsLifecycle.Invoke, "PveVmGuestExec", SupportsShouldProcess = true)]
[OutputType(typeof(PSObject))]
public sealed class InvokePveVmGuestExecCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier.
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
/// The command to execute inside the guest.
- [Parameter(Mandatory = true, Position = 2)]
+ [Parameter(Mandatory = true, Position = 2, HelpMessage = "The command to execute inside the guest.")]
public string Command { get; set; } = string.Empty;
/// Optional arguments to pass to the command.
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Arguments to pass to the command.")]
public string[]? Args { get; set; }
protected override void ProcessRecord()
{
+ if (!ShouldProcess($"VM {VmId} on node '{Node}'", $"Execute guest command: {Command}"))
+ return;
+
var session = GetSession();
var service = new VmService();
+ WriteVerbose($"Executing command on VM {VmId} via guest agent...");
var pid = service.ExecuteGuestCommand(session, Node, VmId, Command, Args);
// Poll for completion
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/MovePveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/MovePveVmCmdlet.cs
index a6e8732..b8e023d 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/MovePveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/MovePveVmCmdlet.cs
@@ -21,19 +21,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM currently resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to migrate. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// The destination node to migrate the VM to.
///
- [Parameter(Mandatory = true)]
+ [Parameter(Mandatory = true, HelpMessage = "The destination node for migration.")]
public string TargetNode { get; set; } = string.Empty;
///
@@ -42,13 +43,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Requires shared storage between the source and target nodes.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Perform live migration (VM stays running).")]
public SwitchParameter Online { get; set; }
///
/// When specified, waits for the migration task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -59,6 +60,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Migrating VM {VmId} from '{Node}' to '{TargetNode}'...");
var task = vmService.MigrateVm(session, Node, VmId, TargetNode, Online.IsPresent);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/NewPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/NewPveVmCmdlet.cs
index 77a14d5..fb363f2 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/NewPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/NewPveVmCmdlet.cs
@@ -21,103 +21,104 @@ namespace PSProxmoxVE.Cmdlets.Vms
///
/// The node on which to create the VM.
///
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The VM ID to assign. When omitted, the next available ID is used.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int? VmId { get; set; }
///
/// The display name of the VM.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "The display name of the VM.")]
public string? Name { get; set; }
///
/// Memory size in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Memory size in MiB.")]
public int? Memory { get; set; }
///
/// Number of CPU cores per socket.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU cores per socket.")]
public int? Cores { get; set; }
///
/// Number of CPU sockets.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU sockets.")]
public int? Sockets { get; set; }
///
/// Emulated CPU type (e.g., "host", "x86-64-v2-AES").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Emulated CPU type (e.g. host, x86-64-v2-AES).")]
public string? CpuType { get; set; }
///
/// BIOS type: "seabios" (default) or "ovmf" (UEFI).
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "BIOS type: seabios (default) or ovmf (UEFI).")]
public string? Bios { get; set; }
///
/// Emulated machine type (e.g., "q35", "i440fx").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Emulated machine type (e.g. q35, i440fx).")]
public string? Machine { get; set; }
///
/// Size of the primary disk (e.g., "32G").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Size of the primary disk (e.g. 32G).")]
public string? DiskSize { get; set; }
///
/// Storage pool for the primary disk (e.g., "local-lvm").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Storage pool for the primary disk.")]
public string? DiskStorage { get; set; }
///
/// Disk format (e.g., "raw", "qcow2").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Disk format (e.g. raw, qcow2).")]
public string? DiskFormat { get; set; }
///
/// Network interface model (e.g., "virtio", "e1000").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Network interface model (e.g. virtio, e1000).")]
public string? Network { get; set; }
///
/// Network bridge to attach to (e.g., "vmbr0").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Network bridge to attach to (e.g. vmbr0).")]
public string? Bridge { get; set; }
///
/// Guest OS type hint (e.g., "l26" for Linux 2.6+, "win10").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Guest OS type hint (e.g. l26, win10).")]
public string? OsType { get; set; }
///
/// When specified, starts the VM after creation.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Start the VM after creation.")]
public SwitchParameter Start { get; set; }
///
/// When specified, waits for the creation task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -128,6 +129,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Creating VM on node '{Node}'...");
var config = new Dictionary();
if (VmId.HasValue)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/RemovePveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/RemovePveVmCmdlet.cs
index 1abe7dc..785433b 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/RemovePveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/RemovePveVmCmdlet.cs
@@ -22,13 +22,14 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to remove. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
@@ -36,7 +37,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// When specified, also removes the VM from HA resource configuration and replication jobs.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
public SwitchParameter Purge { get; set; }
///
@@ -44,13 +45,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// When specified, bypasses locks and forces removal even if a lock is set on the VM.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Force the operation without additional checks.")]
public SwitchParameter Force { get; set; }
///
/// When specified, waits for the removal task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -61,6 +62,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Removing VM {VmId} from node '{Node}'...");
var task = vmService.RemoveVm(session, Node, VmId, Purge.IsPresent);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/ResetPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/ResetPveVmCmdlet.cs
index 1f564bd..d98a4f2 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/ResetPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/ResetPveVmCmdlet.cs
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Use -Wait to block until the reset task completes.
///
///
- [Cmdlet("Reset", "PveVm", SupportsShouldProcess = true)]
+ [Cmdlet(VerbsCommon.Reset, "PveVm", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
[OutputType(typeof(PveTask))]
public sealed class ResetPveVmCmdlet : PveCmdletBase
{
@@ -22,19 +22,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to reset. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the reset task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -45,6 +46,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Resetting VM {VmId} on node '{Node}'...");
var task = vmService.ResetVm(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/ResizePveVmDiskCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/ResizePveVmDiskCmdlet.cs
index 78c334a..29dbf45 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/ResizePveVmDiskCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/ResizePveVmDiskCmdlet.cs
@@ -23,13 +23,14 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM whose disk should be resized. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
@@ -37,7 +38,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The disk slot to resize (e.g., "virtio0", "scsi0", "ide0", "sata0").
///
///
- [Parameter(Mandatory = true)]
+ [Parameter(Mandatory = true, HelpMessage = "The disk slot to resize (e.g. virtio0, scsi0).")]
public string Disk { get; set; } = string.Empty;
///
@@ -46,13 +47,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// or a "+" prefix (e.g., "+10G") to grow the disk by the specified amount.
///
///
- [Parameter(Mandatory = true)]
+ [Parameter(Mandatory = true, HelpMessage = "New disk size (e.g. 50G or +10G to grow).")]
public string Size { get; set; } = string.Empty;
///
/// When specified, waits for the resize task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -63,6 +64,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Resizing disk '{Disk}' on VM {VmId}...");
var task = vmService.ResizeDisk(session, Node, VmId, Disk, Size);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/RestartPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/RestartPveVmCmdlet.cs
index b495054..03b6089 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/RestartPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/RestartPveVmCmdlet.cs
@@ -21,13 +21,14 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to restart. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
@@ -35,13 +36,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Timeout in seconds for the graceful shutdown phase. Defaults to 60 seconds.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
public int Timeout { get; set; } = 60;
///
/// When specified, waits for both shutdown and start tasks to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -53,6 +54,8 @@ namespace PSProxmoxVE.Cmdlets.Vms
var vmService = new VmService();
var taskService = new TaskService();
+ WriteVerbose($"Restarting VM {VmId} on node '{Node}'...");
+
// Graceful shutdown
var shutdownTask = vmService.ShutdownVm(session, Node, VmId, Timeout);
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/ResumePveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/ResumePveVmCmdlet.cs
index 1fd98aa..c17f56c 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/ResumePveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/ResumePveVmCmdlet.cs
@@ -20,19 +20,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to resume. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the resume task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -43,6 +44,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Resuming VM {VmId} on node '{Node}'...");
var task = vmService.ResumeVm(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/SetPveVmConfigCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/SetPveVmConfigCmdlet.cs
index 5f09d48..f213cb0 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/SetPveVmConfigCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/SetPveVmConfigCmdlet.cs
@@ -21,67 +21,68 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to configure. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// Number of CPU cores per socket.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU cores per socket.")]
public int? Cores { get; set; }
///
/// Number of CPU sockets.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Number of CPU sockets.")]
public int? Sockets { get; set; }
///
/// Memory size in MiB.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Memory size in MiB.")]
public int? Memory { get; set; }
///
/// Emulated CPU type (e.g., "host", "x86-64-v2-AES").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Emulated CPU type (e.g. host, x86-64-v2-AES).")]
public string? CpuType { get; set; }
///
/// Human-readable description / notes for the VM.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Description or notes for the VM.")]
public string? Description { get; set; }
///
/// Semicolon-separated list of tags to assign to the VM.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Semicolon-separated list of tags.")]
public string? Tags { get; set; }
///
/// BIOS type: "seabios" or "ovmf".
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "BIOS type: seabios or ovmf.")]
public string? Bios { get; set; }
///
/// Emulated machine type (e.g., "q35", "i440fx").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Emulated machine type (e.g. q35, i440fx).")]
public string? Machine { get; set; }
///
/// Guest OS type hint (e.g., "l26", "win10").
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Guest OS type hint (e.g. l26, win10).")]
public string? OsType { get; set; }
///
@@ -91,7 +92,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Values are merged after named parameters and can override them.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Extra config keys as a hashtable.")]
public Hashtable? AdditionalConfig { get; set; }
///
@@ -100,7 +101,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Maps to the PVE API "delete" parameter.
///
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Comma-separated config keys to delete.")]
public string? Delete { get; set; }
protected override void ProcessRecord()
@@ -111,6 +112,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Updating config for VM {VmId} on node '{Node}'...");
var config = new Dictionary();
if (Cores.HasValue)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/StartPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/StartPveVmCmdlet.cs
index d21a446..42da0ac 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/StartPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/StartPveVmCmdlet.cs
@@ -20,19 +20,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to start. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the start task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -43,6 +44,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Starting VM {VmId} on node '{Node}'...");
var task = vmService.StartVm(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/StopPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/StopPveVmCmdlet.cs
index 4d46bb2..ba7248c 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/StopPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/StopPveVmCmdlet.cs
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// Use -Wait to block until the stop task completes.
///
///
- [Cmdlet(VerbsLifecycle.Stop, "PveVm", SupportsShouldProcess = true)]
+ [Cmdlet(VerbsLifecycle.Stop, "PveVm", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
[OutputType(typeof(PveTask))]
public sealed class StopPveVmCmdlet : PveCmdletBase
{
@@ -22,19 +22,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to stop. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the stop task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -45,6 +46,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Stopping VM {VmId} on node '{Node}'...");
var task = vmService.StopVm(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/SuspendPveVmCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/SuspendPveVmCmdlet.cs
index 898b6a0..5c6878a 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/SuspendPveVmCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/SuspendPveVmCmdlet.cs
@@ -21,19 +21,20 @@ namespace PSProxmoxVE.Cmdlets.Vms
/// The node on which the VM resides. Accepts pipeline input from a PveNode object's Name property.
///
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
///
/// The ID of the VM to suspend. Accepts pipeline input.
///
- [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
///
/// When specified, waits for the suspend task to complete before returning.
///
- [Parameter(Mandatory = false)]
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
public SwitchParameter Wait { get; set; }
protected override void ProcessRecord()
@@ -44,6 +45,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
var session = GetSession();
var vmService = new VmService();
+ WriteVerbose($"Suspending VM {VmId} on node '{Node}'...");
var task = vmService.SuspendVm(session, Node, VmId);
if (Wait.IsPresent)
diff --git a/src/PSProxmoxVE/Cmdlets/Vms/TestPveVmGuestAgentCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Vms/TestPveVmGuestAgentCmdlet.cs
index 07aa4de..2cd69b9 100644
--- a/src/PSProxmoxVE/Cmdlets/Vms/TestPveVmGuestAgentCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Vms/TestPveVmGuestAgentCmdlet.cs
@@ -15,16 +15,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
public sealed class TestPveVmGuestAgentCmdlet : PveCmdletBase
{
/// The Proxmox VE node name.
- [Parameter(Mandatory = true, Position = 0)]
+ [Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
public string Node { get; set; } = string.Empty;
/// The VM identifier.
- [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true)]
+ [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
+ [ValidateRange(100, 999999999)]
public int VmId { get; set; }
protected override void ProcessRecord()
{
var session = GetSession();
+
+ WriteVerbose($"Pinging guest agent on VM {VmId}...");
var service = new VmService();
WriteObject(service.PingGuestAgent(session, Node, VmId));
}