mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-07-26 07:58:14 +00:00
refactor: improve cmdlet quality across all 66 cmdlets
- Add HelpMessage to every [Parameter] attribute - Add [ValidateRange(100, 999999999)] to all VmId parameters - Add ConfirmImpact.High to Stop-PveVm and Reset-PveVm - Add ShouldProcess to Invoke-PveVmGuestExec - Add WriteVerbose before every API call - Add WriteWarning on -SkipCertificateCheck usage in Connect-PveServer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,11 +18,12 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
|
||||
public class GetPveCloudInitConfigCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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"];
|
||||
|
||||
@@ -18,15 +18,16 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
|
||||
public class InvokePveCloudInitRegenerateCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>When specified, waits for the regeneration task to complete before returning.</summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -21,47 +21,48 @@ namespace PSProxmoxVE.Cmdlets.CloudInit
|
||||
public class SetPveCloudInitConfigCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>Cloud-init hostname override.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Cloud-init hostname override.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>Cloud-init default username. Alias: User.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Cloud-init default username.")]
|
||||
[Alias("User")]
|
||||
public string? CiUser { get; set; }
|
||||
|
||||
/// <summary>Cloud-init default user password. Accepts a SecureString.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Cloud-init default user password.")]
|
||||
public System.Security.SecureString? Password { get; set; }
|
||||
|
||||
/// <summary>SSH public keys to inject (one key per element).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "SSH public keys to inject.")]
|
||||
public string[]? SshKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IP configuration string (e.g., "ip=192.168.1.50/24,gw=192.168.1.1").
|
||||
/// Maps to ipconfig0 on the VM.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IP config string (e.g. ip=192.168.1.50/24,gw=...).")]
|
||||
public string? IpConfig0 { get; set; }
|
||||
|
||||
/// <summary>DNS nameserver(s) to inject (space or comma separated).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS nameserver(s) to inject.")]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>DNS search domain to inject.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS search domain to inject.")]
|
||||
public string? Searchdomain { get; set; }
|
||||
|
||||
/// <summary>When specified, waits for the config update task to complete before returning.</summary>
|
||||
[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<string, object>();
|
||||
|
||||
if (!string.IsNullOrEmpty(CiUser)) config["ciuser"] = CiUser!;
|
||||
|
||||
@@ -21,17 +21,17 @@ namespace PSProxmoxVE.Cmdlets.Connection
|
||||
private const string ParameterSetApiToken = "ApiToken";
|
||||
|
||||
/// <summary>Hostname or IP address of the Proxmox VE server.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>API port. Defaults to 8006.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "API port. Defaults to 8006.")]
|
||||
[ValidateRange(1, 65535)]
|
||||
public int Port { get; set; } = 8006;
|
||||
|
||||
/// <summary>Username and password credential. Username must include a realm, e.g. root@pam.</summary>
|
||||
[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.
|
||||
/// </summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>When specified, skips TLS certificate validation for the server.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Skip TLS certificate validation.")]
|
||||
public SwitchParameter SkipCertificateCheck { get; set; }
|
||||
|
||||
/// <summary>When specified, writes the resulting PveSession object to the pipeline.</summary>
|
||||
[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)
|
||||
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
[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()
|
||||
|
||||
@@ -20,31 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which the source container resides.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
[Parameter(Mandatory = true, HelpMessage = "The node where the source container resides.")]
|
||||
public string SourceNode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the source container to clone. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The container ID to assign to the new clone. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Container ID for the new clone.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? NewVmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname for the new clone.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Hostname for the new clone.")]
|
||||
public string? NewName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The target node for the clone. Defaults to the source node.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Target node for the clone.")]
|
||||
public string? TargetNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -53,19 +55,19 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// A full clone is required when the source container is not a template.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
|
||||
public SwitchParameter Full { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Target storage pool for the full clone root filesystem.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
|
||||
public string? Storage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the clone task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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,
|
||||
|
||||
@@ -23,36 +23,39 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// When omitted, containers from all nodes are returned.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to the container with this ID.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers whose name matches this value (case-insensitive, contains match).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by name.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers in the specified status (e.g., "running", "stopped").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by status (e.g. running, stopped).")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to containers that have the specified tag (substring match against the semicolon-separated tags field).</para>
|
||||
/// </summary>
|
||||
[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<PveContainer> containers = service.GetContainers(session, Node);
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container whose configuration to retrieve. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using PSProxmoxVE.Core.Models.Vms;
|
||||
using PSProxmoxVE.Core.Services;
|
||||
|
||||
namespace PSProxmoxVE.Cmdlets.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Lists snapshots for a Proxmox VE container.</para>
|
||||
/// <para type="description">
|
||||
/// Returns all snapshots for the specified LXC container on the given node.
|
||||
/// VmId can be piped from Get-PveContainer.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "PveContainerSnapshot")]
|
||||
[OutputType(typeof(PveSnapshot))]
|
||||
public class GetPveContainerSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The container identifier. Accepts pipeline input from Get-PveContainer (PveContainer.VmId).
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>Optional filter: return only the snapshot with this name.</summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,49 +22,50 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which to create the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The container ID to assign. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The hostname for the container.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory limit in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Memory limit in MiB.")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Swap size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Swap size in MiB.")]
|
||||
public int? Swap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores to allocate to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU cores to allocate.")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Size of the root filesystem (e.g., "8G").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Size of the root filesystem (e.g. 8G).")]
|
||||
public string? RootFsSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Storage pool for the root filesystem (e.g., "local-lvm").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Storage pool for the root filesystem.")]
|
||||
public string? RootFsStorage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -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").
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "OS template to use for the container.")]
|
||||
public string? OsTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Root password for the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Root password for the container.")]
|
||||
public System.Security.SecureString? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">SSH public keys to inject for the root user (newline-separated).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "SSH public keys for the root user.")]
|
||||
public string? SshPublicKeys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -93,31 +94,31 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// To create a privileged container, explicitly set this to $false.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Run in unprivileged mode (default true).")]
|
||||
public SwitchParameter Unprivileged { get; set; } = new SwitchParameter(true);
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network interface model (e.g., "eth0").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Network interface name (e.g. eth0).")]
|
||||
public string? Network { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network bridge to attach to (e.g., "vmbr0").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Network bridge to attach to (e.g. vmbr0).")]
|
||||
public string? Bridge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, starts the container after creation.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Start the container after creation.")]
|
||||
public SwitchParameter Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the creation task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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<string, object>();
|
||||
|
||||
if (VmId.HasValue)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Creates a snapshot of a Proxmox VE container.</para>
|
||||
/// <para type="description">
|
||||
/// Takes a snapshot of the specified LXC container.
|
||||
/// Returns a PveTask. Use -Wait to block until the snapshot completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "PveContainerSnapshot", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public class NewPveContainerSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The container identifier. Accepts pipeline input from Get-PveContainer (PveContainer.VmId).</summary>
|
||||
[Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>The snapshot name (alphanumeric, hyphens and underscores).</summary>
|
||||
[Parameter(Mandatory = true, Position = 2, HelpMessage = "The snapshot name.")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional human-readable description for the snapshot.</summary>
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description for the snapshot.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>When specified, waits for the snapshot task to complete before returning.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["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() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to remove. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -36,7 +37,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// When specified, also removes the container from HA resource configuration and replication jobs.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
|
||||
public SwitchParameter Purge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -44,13 +45,13 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// When specified, bypasses locks and forces removal even if a lock is set on the container.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Force the operation without additional checks.")]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the removal task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Removes a snapshot from a Proxmox VE container.</para>
|
||||
/// <para type="description">
|
||||
/// Deletes the specified snapshot from the LXC container.
|
||||
/// Returns a PveTask. Use -Wait to block until removal completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Remove, "PveContainerSnapshot", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public class RemovePveContainerSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The container identifier.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The snapshot name to remove. Accepts pipeline input from Get-PveContainerSnapshot (PveSnapshot.Name).
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to remove.")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>When specified, waits for the removal task to complete before returning.</summary>
|
||||
[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() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to restart. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -35,13 +36,13 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Timeout in seconds for the graceful shutdown phase. Defaults to 60 seconds.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
|
||||
public int Timeout { get; set; } = 60;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for both shutdown and start tasks to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// <para type="synopsis">Rolls back a Proxmox VE container to a snapshot.</para>
|
||||
/// <para type="description">
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsData.Restore, "PveContainerSnapshot",
|
||||
SupportsShouldProcess = true,
|
||||
ConfirmImpact = ConfirmImpact.High)]
|
||||
[OutputType(typeof(PveTask))]
|
||||
public class RestorePveContainerSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The container identifier.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The snapshot name to roll back to. Accepts pipeline input from Get-PveContainerSnapshot (PveSnapshot.Name).
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true, HelpMessage = "The snapshot name to roll back to.")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>When specified, waits for the rollback task to complete before returning.</summary>
|
||||
[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() };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to configure. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The hostname to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The hostname for the container.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores to allocate to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU cores to allocate.")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory limit in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Memory limit in MiB.")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Swap size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Swap size in MiB.")]
|
||||
public int? Swap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Human-readable description / notes for the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description or notes for the container.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Semicolon-separated list of tags to assign to the container.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Semicolon-separated list of tags.")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">DNS nameservers (space-separated).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS nameservers (space-separated).")]
|
||||
public string? Nameserver { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">DNS search domain.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS search domain.")]
|
||||
public string? SearchDomain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -85,7 +86,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Values are merged after named parameters and can override them.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Extra config keys as a hashtable.")]
|
||||
public Hashtable? AdditionalConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +95,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Maps to the PVE API "delete" parameter.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[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<string, object>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Hostname))
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to start. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the start task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Containers
|
||||
/// Use -Wait to block until the stop task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the container to stop. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the stop task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -20,16 +20,16 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
/// <summary>
|
||||
/// The Proxmox VE node name. Accepts pipeline input from Get-PveNode (PveNode.Name).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Filter results to this specific interface name (e.g., "vmbr0").</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The network interface name.")]
|
||||
public string? Iface { get; set; }
|
||||
|
||||
/// <summary>Filter by interface type (e.g., "bridge", "bond", "eth", "vlan").</summary>
|
||||
[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)}";
|
||||
|
||||
@@ -17,11 +17,11 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class GetPveSdnVnetCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>Filter VNets to a specific zone.</summary>
|
||||
[Parameter(Mandatory = false, Position = 0)]
|
||||
[Parameter(Mandatory = false, Position = 0, HelpMessage = "The SDN zone name.")]
|
||||
public string? Zone { get; set; }
|
||||
|
||||
/// <summary>Optional VNet identifier to retrieve a specific VNet.</summary>
|
||||
[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();
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class GetPveSdnZoneCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>Optional zone identifier to retrieve a specific zone.</summary>
|
||||
[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);
|
||||
|
||||
@@ -19,11 +19,11 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class InvokePveNetworkApplyCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node on which to apply network changes.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>When specified, waits for the apply task to complete before returning.</summary>
|
||||
[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;
|
||||
|
||||
@@ -15,53 +15,53 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class NewPveNetworkCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The interface name (e.g., "vmbr1", "bond0").</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The network interface name.")]
|
||||
public string Iface { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The interface type.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>IPv4 address for the interface.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 address for the interface.")]
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>IPv4 subnet mask.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 subnet mask.")]
|
||||
public string? Netmask { get; set; }
|
||||
|
||||
/// <summary>IPv4 gateway address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 gateway address.")]
|
||||
public string? Gateway { get; set; }
|
||||
|
||||
/// <summary>Bridge ports (space-separated interface names, for bridge type).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Bridge ports (space-separated interface names).")]
|
||||
public string? BridgePorts { get; set; }
|
||||
|
||||
/// <summary>Bond slave interfaces (space-separated names, for bond type).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Bond slave interfaces (space-separated names).")]
|
||||
public string? BondSlaves { get; set; }
|
||||
|
||||
/// <summary>VLAN tag ID (for vlan type).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "VLAN tag ID.")]
|
||||
public int? VlanId { get; set; }
|
||||
|
||||
/// <summary>MTU override.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "MTU override.")]
|
||||
public int? Mtu { get; set; }
|
||||
|
||||
/// <summary>Configure this interface to start automatically at boot.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Start interface automatically at boot.")]
|
||||
public SwitchParameter Autostart { get; set; }
|
||||
|
||||
/// <summary>Optional comments/notes for this interface.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["iface"] = Iface,
|
||||
|
||||
@@ -14,23 +14,23 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class NewPveSdnVnetCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The VNet identifier (alphanumeric, up to 8 characters).</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The SDN VNet name.")]
|
||||
public string Vnet { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The SDN zone this VNet belongs to.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The SDN zone name.")]
|
||||
public string Zone { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>VLAN tag for VLAN-type zones.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "VLAN tag for VLAN-type zones.")]
|
||||
public int? Tag { get; set; }
|
||||
|
||||
/// <summary>Optional alias/description for the VNet.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Alias or description for the VNet.")]
|
||||
public string? Alias { get; set; }
|
||||
|
||||
/// <summary>Enable VLAN awareness on this VNet.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["vnet"] = Vnet,
|
||||
|
||||
@@ -14,40 +14,40 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class NewPveSdnZoneCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The zone identifier (alphanumeric, hyphens allowed).</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The SDN zone name.")]
|
||||
public string Zone { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The zone type.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>VXLAN peer list or multicast address (for vxlan/evpn types).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "VXLAN peer list or multicast address.")]
|
||||
public string? Peers { get; set; }
|
||||
|
||||
/// <summary>Bridge interface this zone attaches to (for vlan/qinq types).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Bridge interface for this zone.")]
|
||||
public string? Bridge { get; set; }
|
||||
|
||||
/// <summary>MTU override for this zone.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "MTU override for this zone.")]
|
||||
public int? Mtu { get; set; }
|
||||
|
||||
/// <summary>DNS server for automatic DNS registration.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS server for automatic registration.")]
|
||||
public string? Dns { get; set; }
|
||||
|
||||
/// <summary>Reverse DNS server.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Reverse DNS server.")]
|
||||
public string? ReverseDns { get; set; }
|
||||
|
||||
/// <summary>DNS zone name for registration.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "DNS zone name for registration.")]
|
||||
public string? DnsZone { get; set; }
|
||||
|
||||
/// <summary>IPAM plugin to use for this zone.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["zone"] = Zone,
|
||||
|
||||
@@ -14,11 +14,11 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class RemovePveNetworkCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The interface name to remove.</summary>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class RemovePveSdnVnetCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The VNet identifier to remove.</summary>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class RemovePveSdnZoneCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The zone identifier to remove.</summary>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,55 +15,55 @@ namespace PSProxmoxVE.Cmdlets.Network
|
||||
public class SetPveNetworkCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The interface name to modify.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The network interface name.")]
|
||||
public string Iface { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>IPv4 address for the interface.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 address for the interface.")]
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>IPv4 subnet mask.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 subnet mask.")]
|
||||
public string? Netmask { get; set; }
|
||||
|
||||
/// <summary>IPv4 gateway address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv4 gateway address.")]
|
||||
public string? Gateway { get; set; }
|
||||
|
||||
/// <summary>IPv6 address for the interface.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv6 address for the interface.")]
|
||||
public string? Address6 { get; set; }
|
||||
|
||||
/// <summary>IPv6 prefix length.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv6 prefix length.")]
|
||||
public int? Netmask6 { get; set; }
|
||||
|
||||
/// <summary>IPv6 gateway address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "IPv6 gateway address.")]
|
||||
public string? Gateway6 { get; set; }
|
||||
|
||||
/// <summary>Bridge ports (space-separated interface names).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Bridge ports (space-separated interface names).")]
|
||||
public string? BridgePorts { get; set; }
|
||||
|
||||
/// <summary>Bond slave interfaces (space-separated names).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Bond slave interfaces (space-separated names).")]
|
||||
public string? BondSlaves { get; set; }
|
||||
|
||||
/// <summary>MTU override.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "MTU override.")]
|
||||
public int? Mtu { get; set; }
|
||||
|
||||
/// <summary>Configure this interface to start automatically at boot.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Start interface automatically at boot.")]
|
||||
public SwitchParameter Autostart { get; set; }
|
||||
|
||||
/// <summary>Optional comments/notes for this interface.</summary>
|
||||
[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<string, string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Address)) data["address"] = Address!;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
|
||||
public sealed class GetPveNodeCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>Optional node name filter. When specified, only the matching node is returned.</summary>
|
||||
[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
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace PSProxmoxVE.Cmdlets.Nodes
|
||||
/// <summary>
|
||||
/// Name of the node to query. Accepts pipeline input via the PveNode.Name property.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
@@ -17,22 +17,25 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
public class GetPveSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).
|
||||
/// </summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>Optional filter: return only the snapshot with this name.</summary>
|
||||
[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);
|
||||
|
||||
@@ -19,27 +19,28 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
public class NewPveSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>The snapshot name (alphanumeric, hyphens and underscores).</summary>
|
||||
[Parameter(Mandatory = true, Position = 2)]
|
||||
[Parameter(Mandatory = true, Position = 2, HelpMessage = "The snapshot name.")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional human-readable description for the snapshot.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description for the snapshot.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>When specified, includes the VM memory state in the snapshot.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Include VM memory state in the snapshot.")]
|
||||
public SwitchParameter IncludeVmState { get; set; }
|
||||
|
||||
/// <summary>When specified, waits for the snapshot task to complete before returning.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["snapname"] = Name
|
||||
|
||||
@@ -18,21 +18,22 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
public class RemovePveSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The snapshot name to remove. Accepts pipeline input from Get-PveSnapshot (PveSnapshot.Name).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>When specified, waits for the removal task to complete before returning.</summary>
|
||||
[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();
|
||||
|
||||
@@ -21,21 +21,22 @@ namespace PSProxmoxVE.Cmdlets.Snapshots
|
||||
public class RestorePveSnapshotCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The snapshot name to roll back to. Accepts pipeline input from Get-PveSnapshot (PveSnapshot.Name).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>When specified, waits for the rollback task to complete before returning.</summary>
|
||||
[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();
|
||||
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
[Alias("NodeName")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>Filter results to a specific storage name (e.g., "local", "local-lvm").</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
|
||||
public string? Storage { get; set; }
|
||||
|
||||
/// <summary>Filter results to a specific storage type (e.g., "dir", "nfs", "zfspool").</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by storage type (e.g. dir, nfs, zfspool).")]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>Filter results to storages that support the given content type (e.g., "iso", "backup").</summary>
|
||||
[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);
|
||||
|
||||
@@ -16,22 +16,24 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
public class GetPveStorageContentCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name that hosts the storage.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The storage identifier. Accepts pipeline input from Get-PveStorage (PveStorage.Storage).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Filter results to a specific content type (e.g., "iso", "vztmpl", "backup", "images").</summary>
|
||||
[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);
|
||||
|
||||
@@ -19,28 +19,28 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
public class InvokePveStorageDownloadCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node that will perform the download.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The target storage identifier.</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The storage pool name.")]
|
||||
public string Storage { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The URL to download the file from.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The filename to save the downloaded file as on the storage.</summary>
|
||||
[Parameter(Mandatory = true, Position = 3)]
|
||||
[Parameter(Mandatory = true, Position = 3, HelpMessage = "Filename to save the download as.")]
|
||||
public string Filename { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The content type category for the downloaded file. Defaults to "iso".</summary>
|
||||
[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";
|
||||
|
||||
/// <summary>When specified, waits for the download task to complete before returning.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
|
||||
@@ -18,61 +18,61 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
public class NewPveStorageCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The unique storage identifier/name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The storage pool name.")]
|
||||
public string Storage { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The storage type (e.g., "dir", "nfs", "lvm", "zfspool", "cephfs", "rbd").</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Comma-separated list of content types to support (e.g., "iso,vztmpl,backup").</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Comma-separated content types to support.")]
|
||||
public string? Content { get; set; }
|
||||
|
||||
/// <summary>Base directory path (for "dir" type storages).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Base directory path (for dir type).")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
/// <summary>NFS/CIFS server hostname or IP address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "NFS/CIFS server hostname or IP.")]
|
||||
public string? Server { get; set; }
|
||||
|
||||
/// <summary>NFS export path or CIFS share name.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "NFS export path or CIFS share name.")]
|
||||
public string? Export { get; set; }
|
||||
|
||||
/// <summary>LVM volume group name (for "lvm"/"lvmthin" types).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "LVM volume group name.")]
|
||||
public string? VgName { get; set; }
|
||||
|
||||
/// <summary>LVM thin pool name (for "lvmthin" type).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "LVM thin pool name.")]
|
||||
public string? ThinPool { get; set; }
|
||||
|
||||
/// <summary>ZFS pool name (for "zfspool" type).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "ZFS pool name.")]
|
||||
public string? Pool { get; set; }
|
||||
|
||||
/// <summary>Ceph pool name (for "rbd"/"cephfs" types).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Ceph pool name.")]
|
||||
public string? CephPool { get; set; }
|
||||
|
||||
/// <summary>Monitor list for Ceph storages (comma-separated host:port pairs).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Ceph monitor host list.")]
|
||||
public string? MonHost { get; set; }
|
||||
|
||||
/// <summary>Whether this storage is shared across cluster nodes.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Storage is shared across cluster nodes.")]
|
||||
public SwitchParameter Shared { get; set; }
|
||||
|
||||
/// <summary>Whether this storage is enabled. Defaults to enabled.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Create the storage in disabled state.")]
|
||||
public SwitchParameter Disable { get; set; }
|
||||
|
||||
/// <summary>Limit nodes that can access this storage (comma-separated node names).</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["storage"] = Storage,
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
public class RemovePveStorageCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The storage identifier to remove.</summary>
|
||||
[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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,33 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Storage
|
||||
public class SendPveIsoCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node to upload to.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The target storage identifier (must support "iso" content).</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The storage pool name.")]
|
||||
public string Storage { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The full local path to the ISO file to upload. The file must exist.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Optional checksum value to verify the uploaded file.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Checksum value to verify the upload.")]
|
||||
public string? Checksum { get; set; }
|
||||
|
||||
/// <summary>Checksum algorithm used for verification.</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>
|
||||
/// When specified, waits for the upload task to complete before returning.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
|
||||
@@ -17,16 +17,18 @@ namespace PSProxmoxVE.Cmdlets.Tasks
|
||||
public class GetPveTaskCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The node on which the task ran.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The UPID of the task to query.</summary>
|
||||
[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);
|
||||
|
||||
@@ -21,27 +21,27 @@ namespace PSProxmoxVE.Cmdlets.Tasks
|
||||
public class WaitPveTaskCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The node on which the task is running.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The UPID of the task to wait for. Accepts pipeline input from PveTask (PveTask.Upid).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time to wait for the task. Defaults to no timeout.
|
||||
/// Example: -Timeout (New-TimeSpan -Minutes 10)
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
|
||||
public TimeSpan? Timeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How frequently to poll the task status. Defaults to 2 seconds.
|
||||
/// Example: -PollInterval (New-TimeSpan -Seconds 5)
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "How often to poll task status.")]
|
||||
public TimeSpan? PollInterval { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
|
||||
@@ -17,11 +17,11 @@ namespace PSProxmoxVE.Cmdlets.Templates
|
||||
public class GetPveTemplateCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name. When omitted, queries all nodes in the cluster.</summary>
|
||||
[Parameter(Mandatory = false, Position = 0)]
|
||||
[Parameter(Mandatory = false, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>Filter results by template name. Supports wildcard (*) matching.</summary>
|
||||
[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<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Node))
|
||||
|
||||
@@ -17,15 +17,16 @@ namespace PSProxmoxVE.Cmdlets.Templates
|
||||
public class NewPveTemplateCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier to convert. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>When specified, waits for the conversion task to complete before returning.</summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -18,27 +18,29 @@ namespace PSProxmoxVE.Cmdlets.Templates
|
||||
public class NewPveVmFromTemplateCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The node where the source template resides. Alias: Node.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The source template VM ID. Accepts pipeline input from Get-PveTemplate (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>The VM ID for the new cloned VM.</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>Optional name for the new VM.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Name for the new VM.")]
|
||||
public string? NewName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target node for the new VM. When omitted, the new VM is created on the same node
|
||||
/// as the template.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Target node for the new VM.")]
|
||||
public string? TargetNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
|
||||
public SwitchParameter Full { get; set; }
|
||||
|
||||
/// <summary>When specified, waits for the clone task to complete before returning.</summary>
|
||||
[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,
|
||||
|
||||
@@ -18,19 +18,20 @@ namespace PSProxmoxVE.Cmdlets.Templates
|
||||
public class RemovePveTemplateCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM/template identifier to remove. Accepts pipeline input from Get-PveVm (PveVm.VmId).</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>When specified, also removes all associated backup files and jobs.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
|
||||
public SwitchParameter Purge { get; set; }
|
||||
|
||||
/// <summary>When specified, waits for the deletion task to complete before returning.</summary>
|
||||
[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))
|
||||
|
||||
@@ -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).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Filter to a specific token identifier (e.g., "automation").</summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -17,16 +17,18 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class GetPvePermissionCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>Filter results to a specific resource path (e.g., "/", "/vms/100").</summary>
|
||||
[Parameter(Mandatory = false, Position = 0)]
|
||||
[Parameter(Mandatory = false, Position = 0, HelpMessage = "Filter by resource path (e.g. /, /vms/100).")]
|
||||
public string? Path { get; set; }
|
||||
|
||||
/// <summary>Filter results to a specific user or group ID.</summary>
|
||||
[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);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class GetPveRoleCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>Optional role identifier to retrieve a specific role.</summary>
|
||||
[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();
|
||||
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, Position = 0)]
|
||||
[Parameter(Mandatory = false, Position = 0, HelpMessage = "The user ID in user@realm format.")]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
/// <summary>When specified, returns only enabled users.</summary>
|
||||
[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();
|
||||
|
||||
@@ -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).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The token identifier (alphanumeric, hyphens allowed; e.g., "automation").</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The API token identifier.")]
|
||||
public string TokenId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Optional description for this token.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description for this token.")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token expiry as a Unix timestamp. Use 0 or omit for no expiry.
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Token expiry as a Unix timestamp.")]
|
||||
public long? Expire { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
[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,
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class NewPveRoleCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The role identifier/name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The role identifier.")]
|
||||
public string RoleId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Comma-separated list of privileges to grant this role
|
||||
/// (e.g., "VM.Allocate,VM.Config.CPU,VM.Config.Memory").
|
||||
/// </summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["roleid"] = RoleId
|
||||
|
||||
@@ -18,35 +18,35 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class NewPveUserCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The user identifier in "user@realm" format (e.g., "jdoe@pve").</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The user's password (for pve/pam realms). Accepts a SecureString.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Password for the user.")]
|
||||
public System.Security.SecureString? Password { get; set; }
|
||||
|
||||
/// <summary>The user's first name.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The user's first name.")]
|
||||
public string? FirstName { get; set; }
|
||||
|
||||
/// <summary>The user's last name.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The user's last name.")]
|
||||
public string? LastName { get; set; }
|
||||
|
||||
/// <summary>The user's email address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The user's email address.")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>Comma-separated list of groups to add this user to.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Comma-separated list of groups.")]
|
||||
public string? Groups { get; set; }
|
||||
|
||||
/// <summary>Optional comment/notes for this user.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Comment or notes for this user.")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>Account expiry as a Unix timestamp. Use 0 for no expiry.</summary>
|
||||
[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
|
||||
|
||||
@@ -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).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// The token identifier to remove (e.g., "automation").
|
||||
/// Accepts pipeline input from Get-PveApiToken (PveApiToken.TokenId).
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class RemovePveRoleCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The role identifier to remove.</summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class RemovePveUserCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The user identifier to remove (e.g., "jdoe@pve").</summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,28 +15,28 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class SetPvePermissionCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The resource path this ACL applies to (e.g., "/", "/vms/100").</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The user or group identifier (e.g., "jdoe@pve" or "admins").</summary>
|
||||
[Parameter(Mandatory = true, Position = 1)]
|
||||
[Parameter(Mandatory = true, Position = 1, HelpMessage = "The user or group identifier.")]
|
||||
public string UgId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The role to assign (e.g., "Administrator", "PVEVMUser").</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>The ACL entry type: "user" or "group".</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "ACL entry type: user or group.")]
|
||||
[ValidateSet("user", "group", IgnoreCase = true)]
|
||||
public string Type { get; set; } = "user";
|
||||
|
||||
/// <summary>Whether to propagate this ACL to child paths.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Propagate this ACL to child paths.")]
|
||||
public SwitchParameter Propagate { get; set; }
|
||||
|
||||
/// <summary>When specified, removes the ACL entry instead of adding it.</summary>
|
||||
[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<string, string>
|
||||
{
|
||||
["path"] = Path,
|
||||
|
||||
@@ -16,39 +16,39 @@ namespace PSProxmoxVE.Cmdlets.Users
|
||||
public class SetPveUserCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The user identifier to update (e.g., "jdoe@pve").</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>New password for the user. Accepts a SecureString.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "New password for the user.")]
|
||||
public System.Security.SecureString? Password { get; set; }
|
||||
|
||||
/// <summary>Updated first name.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Updated first name.")]
|
||||
public string? FirstName { get; set; }
|
||||
|
||||
/// <summary>Updated last name.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Updated last name.")]
|
||||
public string? LastName { get; set; }
|
||||
|
||||
/// <summary>Updated email address.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Updated email address.")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>Updated group membership (comma-separated group names).</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Updated group membership (comma-separated).")]
|
||||
public string? Groups { get; set; }
|
||||
|
||||
/// <summary>Updated comment/notes.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Updated comment or notes.")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>Account expiry as a Unix timestamp. Use 0 to remove expiry.</summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Account expiry as a Unix timestamp.")]
|
||||
public long? Expire { get; set; }
|
||||
|
||||
/// <summary>Enable or disable the user account.</summary>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,31 +20,33 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which the source VM resides.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
[Parameter(Mandatory = true, HelpMessage = "The node where the source VM resides.")]
|
||||
public string SourceNode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the source VM to clone. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The VM ID to assign to the new clone. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "VM ID for the new clone.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? NewVmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The display name for the new clone.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Display name for the new clone.")]
|
||||
public string? NewName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The target node for the clone. Defaults to the source node.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Target node for the clone.")]
|
||||
public string? TargetNode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -53,19 +55,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// A full clone is required when the source VM is not a template.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Perform a full (non-linked) clone.")]
|
||||
public SwitchParameter Full { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Target storage pool for the full clone disks.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The storage pool name.")]
|
||||
public string? Storage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the clone task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -23,42 +23,45 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// When omitted, VMs from all nodes are returned.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string? Node { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to the VM with this ID.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to VMs whose name matches this value (case-insensitive, contains match).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by name.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to VMs in the specified status (e.g., "running", "stopped").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by status (e.g. running, stopped).")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Filter results to VMs that have the specified tag (substring match against the semicolon-separated tags field).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Filter by tag.")]
|
||||
public string? Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, returns only VMs that are marked as templates.</para>
|
||||
/// </summary>
|
||||
[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<PveVm> vms = service.GetVms(session, Node);
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM whose configuration to retrieve. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[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);
|
||||
}
|
||||
|
||||
@@ -17,16 +17,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
public sealed class GetPveVmGuestNetworkCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier.</summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -11,31 +11,36 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// installed and running inside the VM.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PveVmGuestExec")]
|
||||
[Cmdlet(VerbsLifecycle.Invoke, "PveVmGuestExec", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PSObject))]
|
||||
public sealed class InvokePveVmGuestExecCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier.</summary>
|
||||
[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; }
|
||||
|
||||
/// <summary>The command to execute inside the guest.</summary>
|
||||
[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;
|
||||
|
||||
/// <summary>Optional arguments to pass to the command.</summary>
|
||||
[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
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to migrate. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The destination node to migrate the VM to.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
[Parameter(Mandatory = true, HelpMessage = "The destination node for migration.")]
|
||||
public string TargetNode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
@@ -42,13 +43,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Requires shared storage between the source and target nodes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Perform live migration (VM stays running).")]
|
||||
public SwitchParameter Online { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the migration task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -21,103 +21,104 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// <summary>
|
||||
/// <para type="description">The node on which to create the VM.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The VM ID to assign. When omitted, the next available ID is used.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int? VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The display name of the VM.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "The display name of the VM.")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Memory size in MiB.")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores per socket.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU cores per socket.")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU sockets.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU sockets.")]
|
||||
public int? Sockets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Emulated CPU type (e.g., "host", "x86-64-v2-AES").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Emulated CPU type (e.g. host, x86-64-v2-AES).")]
|
||||
public string? CpuType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">BIOS type: "seabios" (default) or "ovmf" (UEFI).</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "BIOS type: seabios (default) or ovmf (UEFI).")]
|
||||
public string? Bios { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Emulated machine type (e.g., "q35", "i440fx").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Emulated machine type (e.g. q35, i440fx).")]
|
||||
public string? Machine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Size of the primary disk (e.g., "32G").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Size of the primary disk (e.g. 32G).")]
|
||||
public string? DiskSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Storage pool for the primary disk (e.g., "local-lvm").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Storage pool for the primary disk.")]
|
||||
public string? DiskStorage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Disk format (e.g., "raw", "qcow2").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Disk format (e.g. raw, qcow2).")]
|
||||
public string? DiskFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network interface model (e.g., "virtio", "e1000").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Network interface model (e.g. virtio, e1000).")]
|
||||
public string? Network { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Network bridge to attach to (e.g., "vmbr0").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Network bridge to attach to (e.g. vmbr0).")]
|
||||
public string? Bridge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Guest OS type hint (e.g., "l26" for Linux 2.6+, "win10").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Guest OS type hint (e.g. l26, win10).")]
|
||||
public string? OsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, starts the VM after creation.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Start the VM after creation.")]
|
||||
public SwitchParameter Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the creation task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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<string, object>();
|
||||
|
||||
if (VmId.HasValue)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to remove. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -36,7 +37,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// When specified, also removes the VM from HA resource configuration and replication jobs.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Remove all associated resources.")]
|
||||
public SwitchParameter Purge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -44,13 +45,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// When specified, bypasses locks and forces removal even if a lock is set on the VM.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Force the operation without additional checks.")]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the removal task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Use -Wait to block until the reset task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to reset. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the reset task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM whose disk should be resized. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -37,7 +38,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// The disk slot to resize (e.g., "virtio0", "scsi0", "ide0", "sata0").
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
[Parameter(Mandatory = true, HelpMessage = "The disk slot to resize (e.g. virtio0, scsi0).")]
|
||||
public string Disk { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
@@ -46,13 +47,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// or a "+" prefix (e.g., "+10G") to grow the disk by the specified amount.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true)]
|
||||
[Parameter(Mandatory = true, HelpMessage = "New disk size (e.g. 50G or +10G to grow).")]
|
||||
public string Size { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the resize task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to restart. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -35,13 +36,13 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Timeout in seconds for the graceful shutdown phase. Defaults to 60 seconds.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Maximum time to wait for the task.")]
|
||||
public int Timeout { get; set; } = 60;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for both shutdown and start tasks to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to resume. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the resume task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to configure. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU cores per socket.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU cores per socket.")]
|
||||
public int? Cores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Number of CPU sockets.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Number of CPU sockets.")]
|
||||
public int? Sockets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Memory size in MiB.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Memory size in MiB.")]
|
||||
public int? Memory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Emulated CPU type (e.g., "host", "x86-64-v2-AES").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Emulated CPU type (e.g. host, x86-64-v2-AES).")]
|
||||
public string? CpuType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Human-readable description / notes for the VM.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description or notes for the VM.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Semicolon-separated list of tags to assign to the VM.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Semicolon-separated list of tags.")]
|
||||
public string? Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">BIOS type: "seabios" or "ovmf".</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "BIOS type: seabios or ovmf.")]
|
||||
public string? Bios { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Emulated machine type (e.g., "q35", "i440fx").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Emulated machine type (e.g. q35, i440fx).")]
|
||||
public string? Machine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">Guest OS type hint (e.g., "l26", "win10").</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Guest OS type hint (e.g. l26, win10).")]
|
||||
public string? OsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +92,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Values are merged after named parameters and can override them.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = false)]
|
||||
[Parameter(Mandatory = false, HelpMessage = "Extra config keys as a hashtable.")]
|
||||
public Hashtable? AdditionalConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -100,7 +101,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Maps to the PVE API "delete" parameter.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[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<string, object>();
|
||||
|
||||
if (Cores.HasValue)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to start. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the start task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
/// Use -Wait to block until the stop task completes.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to stop. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the stop task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">The ID of the VM to suspend. Accepts pipeline input.</para>
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The VM identifier.")]
|
||||
[ValidateRange(100, 999999999)]
|
||||
public int VmId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para type="description">When specified, waits for the suspend task to complete before returning.</para>
|
||||
/// </summary>
|
||||
[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)
|
||||
|
||||
@@ -15,16 +15,19 @@ namespace PSProxmoxVE.Cmdlets.Vms
|
||||
public sealed class TestPveVmGuestAgentCmdlet : PveCmdletBase
|
||||
{
|
||||
/// <summary>The Proxmox VE node name.</summary>
|
||||
[Parameter(Mandatory = true, Position = 0)]
|
||||
[Parameter(Mandatory = true, Position = 0, HelpMessage = "The PVE node name.")]
|
||||
public string Node { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>The VM identifier.</summary>
|
||||
[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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user