diff --git a/src/PSProxmoxVE.Core/Models/Cluster/PveClusterNode.cs b/src/PSProxmoxVE.Core/Models/Cluster/PveClusterNode.cs
new file mode 100644
index 0000000..ea551d8
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Cluster/PveClusterNode.cs
@@ -0,0 +1,69 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Cluster;
+
+///
+/// Represents a node entry within the cluster status response,
+/// as returned by the /cluster/status endpoint when the item type is "node".
+///
+public class PveClusterNode
+{
+ ///
+ /// The node name (e.g., "pve", "pve2").
+ ///
+ [JsonPropertyName("name")]
+ [JsonProperty("name")]
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Indicates whether this node is currently online (1) or offline (0).
+ ///
+ [JsonPropertyName("online")]
+ [JsonProperty("online")]
+ public int? Online { get; set; }
+
+ ///
+ /// Indicates whether this is the local node making the request (1) or a remote node (0).
+ ///
+ [JsonPropertyName("local")]
+ [JsonProperty("local")]
+ public int? Local { get; set; }
+
+ ///
+ /// The numeric node ID within the cluster Corosync configuration.
+ ///
+ [JsonPropertyName("nodeid")]
+ [JsonProperty("nodeid")]
+ public int? NodeId { get; set; }
+
+ ///
+ /// The IP address used for cluster communication on this node.
+ ///
+ [JsonPropertyName("ip")]
+ [JsonProperty("ip")]
+ public string? Ip { get; set; }
+
+ ///
+ /// The cluster membership level of this node (e.g., "c" for configured member).
+ ///
+ [JsonPropertyName("level")]
+ [JsonProperty("level")]
+ public string? Level { get; set; }
+
+ ///
+ /// The item type as returned by the cluster status endpoint (always "node" for this model).
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var onlineStr = Online is 1 ? "online" : "offline";
+ var localStr = Local is 1 ? " [local]" : string.Empty;
+ return $"Node: {Name}{localStr} | ID: {NodeId?.ToString() ?? "N/A"} | "
+ + $"IP: {Ip ?? "N/A"} | {onlineStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Cluster/PveClusterStatus.cs b/src/PSProxmoxVE.Core/Models/Cluster/PveClusterStatus.cs
new file mode 100644
index 0000000..1c8bc35
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Cluster/PveClusterStatus.cs
@@ -0,0 +1,95 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Cluster;
+
+///
+/// Represents an entry in the mixed array returned by the /cluster/status endpoint.
+/// Each entry has a Type of either "cluster" (cluster-wide info) or "node" (per-node info).
+/// Filter by to distinguish cluster vs. node entries.
+///
+public class PveClusterStatus
+{
+ ///
+ /// The entry type: "cluster" for the cluster-wide record, or "node" for a node record.
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ /// The name of the cluster (present when Type == "cluster") or the node name (when Type == "node").
+ ///
+ [JsonPropertyName("name")]
+ [JsonProperty("name")]
+ public string? Name { get; set; }
+
+ ///
+ /// The total number of nodes in the cluster. Only present when Type == "cluster".
+ ///
+ [JsonPropertyName("nodes")]
+ [JsonProperty("nodes")]
+ public int? Nodes { get; set; }
+
+ ///
+ /// Indicates whether the cluster currently has quorum (1) or not (0).
+ /// Without quorum, most write operations are blocked to maintain data consistency.
+ /// Only present when Type == "cluster".
+ ///
+ [JsonPropertyName("quorate")]
+ [JsonProperty("quorate")]
+ public int? Quorate { get; set; }
+
+ ///
+ /// The cluster configuration version number. Only present when Type == "cluster".
+ ///
+ [JsonPropertyName("version")]
+ [JsonProperty("version")]
+ public int? Version { get; set; }
+
+ ///
+ /// The IP address used for cluster communication on this node.
+ /// Only present when Type == "node".
+ ///
+ [JsonPropertyName("ip")]
+ [JsonProperty("ip")]
+ public string? Ip { get; set; }
+
+ ///
+ /// Indicates whether this node is currently online (1) or offline (0).
+ /// Only present when Type == "node".
+ ///
+ [JsonPropertyName("online")]
+ [JsonProperty("online")]
+ public int? Online { get; set; }
+
+ ///
+ /// Indicates whether this is the local node making the request (1) or a remote node (0).
+ /// Only present when Type == "node".
+ ///
+ [JsonPropertyName("local")]
+ [JsonProperty("local")]
+ public int? Local { get; set; }
+
+ ///
+ /// The numeric node ID within the cluster Corosync configuration.
+ /// Only present when Type == "node".
+ ///
+ [JsonPropertyName("nodeid")]
+ [JsonProperty("nodeid")]
+ public int? NodeId { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ if (Type == "node")
+ {
+ var onlineStr = Online is 1 ? "online" : "offline";
+ var localStr = Local is 1 ? " [local]" : string.Empty;
+ return $"Node: {Name ?? "N/A"}{localStr} | IP: {Ip ?? "N/A"} | {onlineStr}";
+ }
+ var quorateStr = Quorate is 1 ? "quorate" : "NO QUORUM";
+ return $"Cluster: {Name ?? "N/A"} | Nodes: {Nodes?.ToString() ?? "N/A"} | "
+ + $"{quorateStr} | Config Version: {Version?.ToString() ?? "N/A"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Containers/PveContainer.cs b/src/PSProxmoxVE.Core/Models/Containers/PveContainer.cs
new file mode 100644
index 0000000..ab84e37
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Containers/PveContainer.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Containers;
+
+///
+/// Represents a Linux Container (LXC) as returned by the cluster or node container list endpoints.
+///
+public class PveContainer
+{
+ ///
+ /// The unique container identifier.
+ ///
+ [JsonPropertyName("vmid")]
+ [JsonProperty("vmid")]
+ public int VmId { get; set; }
+
+ ///
+ /// The hostname / display name of the container.
+ ///
+ [JsonPropertyName("name")]
+ [JsonProperty("name")]
+ public string? Name { get; set; }
+
+ ///
+ /// The current runtime status of the container (e.g., "running", "stopped").
+ ///
+ [JsonPropertyName("status")]
+ [JsonProperty("status")]
+ public string? Status { get; set; }
+
+ ///
+ /// The node on which the container resides.
+ ///
+ [JsonPropertyName("node")]
+ [JsonProperty("node")]
+ public string? Node { get; set; }
+
+ ///
+ /// The number of CPU cores assigned to the container.
+ ///
+ [JsonPropertyName("cpus")]
+ [JsonProperty("cpus")]
+ public int? CpuCount { get; set; }
+
+ ///
+ /// Maximum memory allocated to the container, in bytes.
+ ///
+ [JsonPropertyName("maxmem")]
+ [JsonProperty("maxmem")]
+ public long? MaxMem { get; set; }
+
+ ///
+ /// Maximum swap space allocated to the container, in bytes.
+ ///
+ [JsonPropertyName("maxswap")]
+ [JsonProperty("maxswap")]
+ public long? MaxSwap { get; set; }
+
+ ///
+ /// Root filesystem disk size allocated to the container, in bytes.
+ ///
+ [JsonPropertyName("maxdisk")]
+ [JsonProperty("maxdisk")]
+ public long? RootFsSize { get; set; }
+
+ ///
+ /// The OS template type used for this container (e.g., "debian", "ubuntu").
+ ///
+ [JsonPropertyName("ostype")]
+ [JsonProperty("ostype")]
+ public string? OsType { get; set; }
+
+ ///
+ /// Indicates whether the container runs in unprivileged mode (1) or privileged mode (0).
+ ///
+ [JsonPropertyName("unprivileged")]
+ [JsonProperty("unprivileged")]
+ public int? Unprivileged { get; set; }
+
+ ///
+ /// The current lock type applied to the container, if any (e.g., "migrate", "backup").
+ ///
+ [JsonPropertyName("lock")]
+ [JsonProperty("lock")]
+ public string? Lock { get; set; }
+
+ ///
+ /// Container uptime in seconds.
+ ///
+ [JsonPropertyName("uptime")]
+ [JsonProperty("uptime")]
+ public long? Uptime { get; set; }
+
+ ///
+ /// Semicolon-separated list of tags assigned to the container.
+ ///
+ [JsonPropertyName("tags")]
+ [JsonProperty("tags")]
+ public string? Tags { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var maxMemMb = MaxMem.HasValue ? $"{MaxMem.Value / 1024 / 1024} MB" : "N/A";
+ var rootFsGb = RootFsSize.HasValue ? $"{RootFsSize.Value / 1024 / 1024 / 1024} GB" : "N/A";
+ var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
+ var privStr = Unprivileged is 1 ? "unprivileged" : "privileged";
+ return $"CT {VmId}: {Name ?? "(unnamed)"} | Node: {Node ?? "N/A"} | "
+ + $"Status: {Status ?? "N/A"} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
+ + $"Mem: {maxMemMb} | Disk: {rootFsGb} | {privStr} | Uptime: {uptimeStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Containers/PveContainerConfig.cs b/src/PSProxmoxVE.Core/Models/Containers/PveContainerConfig.cs
new file mode 100644
index 0000000..7461668
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Containers/PveContainerConfig.cs
@@ -0,0 +1,236 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Containers;
+
+///
+/// Represents the configuration of a Linux Container (LXC),
+/// as returned by the /nodes/{node}/lxc/{vmid}/config endpoint.
+///
+public class PveContainerConfig
+{
+ // -------------------------------------------------------------------------
+ // Identity / OS
+ // -------------------------------------------------------------------------
+
+ ///
+ /// The container hostname.
+ ///
+ [JsonPropertyName("hostname")]
+ [JsonProperty("hostname")]
+ public string? Hostname { get; set; }
+
+ ///
+ /// The OS type used for the container (e.g., "debian", "ubuntu", "alpine").
+ ///
+ [JsonPropertyName("ostype")]
+ [JsonProperty("ostype")]
+ public string? OsType { get; set; }
+
+ ///
+ /// Container architecture (e.g., "amd64", "arm64").
+ ///
+ [JsonPropertyName("arch")]
+ [JsonProperty("arch")]
+ public string? Arch { get; set; }
+
+ ///
+ /// Indicates whether the container runs unprivileged (1) or privileged (0).
+ ///
+ [JsonPropertyName("unprivileged")]
+ [JsonProperty("unprivileged")]
+ public int? Unprivileged { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Resources
+ // -------------------------------------------------------------------------
+
+ ///
+ /// Memory limit in megabytes.
+ ///
+ [JsonPropertyName("memory")]
+ [JsonProperty("memory")]
+ public int? Memory { get; set; }
+
+ ///
+ /// Swap space limit in megabytes. 0 disables swap.
+ ///
+ [JsonPropertyName("swap")]
+ [JsonProperty("swap")]
+ public int? Swap { get; set; }
+
+ ///
+ /// Number of CPU cores allocated to the container.
+ ///
+ [JsonPropertyName("cores")]
+ [JsonProperty("cores")]
+ public int? Cores { get; set; }
+
+ ///
+ /// Root filesystem configuration string (e.g., "local-lvm:8").
+ ///
+ [JsonPropertyName("rootfs")]
+ [JsonProperty("rootfs")]
+ public string? RootFs { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Metadata
+ // -------------------------------------------------------------------------
+
+ ///
+ /// Human-readable description or notes for the container.
+ ///
+ [JsonPropertyName("description")]
+ [JsonProperty("description")]
+ public string? Description { get; set; }
+
+ ///
+ /// Semicolon-separated list of tags assigned to the container.
+ ///
+ [JsonPropertyName("tags")]
+ [JsonProperty("tags")]
+ public string? Tags { get; set; }
+
+ ///
+ /// When set to 1, prevents the container from being deleted or modified accidentally.
+ ///
+ [JsonPropertyName("protection")]
+ [JsonProperty("protection")]
+ public int? Protection { get; set; }
+
+ ///
+ /// Startup / shutdown order and delay configuration string.
+ ///
+ [JsonPropertyName("startup")]
+ [JsonProperty("startup")]
+ public string? Startup { get; set; }
+
+ ///
+ /// Feature flags for the container (e.g., "nesting=1,keyctl=1").
+ ///
+ [JsonPropertyName("features")]
+ [JsonProperty("features")]
+ public string? Features { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Network interfaces (0-7)
+ // -------------------------------------------------------------------------
+
+ /// Network interface 0 configuration string.
+ [JsonPropertyName("net0")]
+ [JsonProperty("net0")]
+ public string? Net0 { get; set; }
+
+ /// Network interface 1 configuration string.
+ [JsonPropertyName("net1")]
+ [JsonProperty("net1")]
+ public string? Net1 { get; set; }
+
+ /// Network interface 2 configuration string.
+ [JsonPropertyName("net2")]
+ [JsonProperty("net2")]
+ public string? Net2 { get; set; }
+
+ /// Network interface 3 configuration string.
+ [JsonPropertyName("net3")]
+ [JsonProperty("net3")]
+ public string? Net3 { get; set; }
+
+ /// Network interface 4 configuration string.
+ [JsonPropertyName("net4")]
+ [JsonProperty("net4")]
+ public string? Net4 { get; set; }
+
+ /// Network interface 5 configuration string.
+ [JsonPropertyName("net5")]
+ [JsonProperty("net5")]
+ public string? Net5 { get; set; }
+
+ /// Network interface 6 configuration string.
+ [JsonPropertyName("net6")]
+ [JsonProperty("net6")]
+ public string? Net6 { get; set; }
+
+ /// Network interface 7 configuration string.
+ [JsonPropertyName("net7")]
+ [JsonProperty("net7")]
+ public string? Net7 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Mount points (0-7)
+ // -------------------------------------------------------------------------
+
+ /// Mount point 0 configuration string (e.g., "local-lvm:10,mp=/data").
+ [JsonPropertyName("mp0")]
+ [JsonProperty("mp0")]
+ public string? Mp0 { get; set; }
+
+ /// Mount point 1 configuration string.
+ [JsonPropertyName("mp1")]
+ [JsonProperty("mp1")]
+ public string? Mp1 { get; set; }
+
+ /// Mount point 2 configuration string.
+ [JsonPropertyName("mp2")]
+ [JsonProperty("mp2")]
+ public string? Mp2 { get; set; }
+
+ /// Mount point 3 configuration string.
+ [JsonPropertyName("mp3")]
+ [JsonProperty("mp3")]
+ public string? Mp3 { get; set; }
+
+ /// Mount point 4 configuration string.
+ [JsonPropertyName("mp4")]
+ [JsonProperty("mp4")]
+ public string? Mp4 { get; set; }
+
+ /// Mount point 5 configuration string.
+ [JsonPropertyName("mp5")]
+ [JsonProperty("mp5")]
+ public string? Mp5 { get; set; }
+
+ /// Mount point 6 configuration string.
+ [JsonPropertyName("mp6")]
+ [JsonProperty("mp6")]
+ public string? Mp6 { get; set; }
+
+ /// Mount point 7 configuration string.
+ [JsonPropertyName("mp7")]
+ [JsonProperty("mp7")]
+ public string? Mp7 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // DNS / SSH
+ // -------------------------------------------------------------------------
+
+ ///
+ /// DNS nameserver(s) for the container.
+ ///
+ [JsonPropertyName("nameserver")]
+ [JsonProperty("nameserver")]
+ public string? Nameserver { get; set; }
+
+ ///
+ /// DNS search domain for the container.
+ ///
+ [JsonPropertyName("searchdomain")]
+ [JsonProperty("searchdomain")]
+ public string? Searchdomain { get; set; }
+
+ ///
+ /// SSH public keys injected into the container's root account.
+ ///
+ [JsonPropertyName("ssh-public-keys")]
+ [JsonProperty("ssh-public-keys")]
+ public string? SshPublicKeys { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ return $"Config | Hostname: {Hostname ?? "N/A"} | OS: {OsType ?? "N/A"} | "
+ + $"Cores: {Cores?.ToString() ?? "N/A"} | Memory: {Memory?.ToString() ?? "N/A"} MB | "
+ + $"Swap: {Swap?.ToString() ?? "N/A"} MB | Arch: {Arch ?? "N/A"} | "
+ + $"Unprivileged: {(Unprivileged is 1 ? "yes" : "no")}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Network/PveNetwork.cs b/src/PSProxmoxVE.Core/Models/Network/PveNetwork.cs
new file mode 100644
index 0000000..397d41a
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Network/PveNetwork.cs
@@ -0,0 +1,130 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Network;
+
+///
+/// Represents a network interface configuration on a Proxmox VE node,
+/// as returned by the /nodes/{node}/network endpoint.
+///
+public class PveNetwork
+{
+ ///
+ /// The interface name (e.g., "vmbr0", "eth0", "bond0").
+ ///
+ [JsonPropertyName("iface")]
+ [JsonProperty("iface")]
+ public string Iface { get; set; } = string.Empty;
+
+ ///
+ /// The interface type (e.g., "bridge", "bond", "eth", "vlan", "OVSBridge").
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ /// The IPv4 address assigned to this interface.
+ ///
+ [JsonPropertyName("address")]
+ [JsonProperty("address")]
+ public string? Address { get; set; }
+
+ ///
+ /// The IPv4 netmask for this interface.
+ ///
+ [JsonPropertyName("netmask")]
+ [JsonProperty("netmask")]
+ public string? Netmask { get; set; }
+
+ ///
+ /// The IPv4 default gateway associated with this interface.
+ ///
+ [JsonPropertyName("gateway")]
+ [JsonProperty("gateway")]
+ public string? Gateway { get; set; }
+
+ ///
+ /// Space-separated list of physical ports attached to this bridge.
+ ///
+ [JsonPropertyName("bridge_ports")]
+ [JsonProperty("bridge_ports")]
+ public string? BridgePorts { get; set; }
+
+ ///
+ /// Space-separated list of slave interfaces for bond/team interfaces.
+ ///
+ [JsonPropertyName("slaves")]
+ [JsonProperty("slaves")]
+ public string? BondSlaves { get; set; }
+
+ ///
+ /// VLAN ID for VLAN sub-interfaces.
+ ///
+ [JsonPropertyName("vlan-id")]
+ [JsonProperty("vlan-id")]
+ public int? VlanId { get; set; }
+
+ ///
+ /// The Maximum Transmission Unit in bytes.
+ ///
+ [JsonPropertyName("mtu")]
+ [JsonProperty("mtu")]
+ public int? Mtu { get; set; }
+
+ ///
+ /// Indicates whether the interface is brought up automatically at boot (1) or not (0).
+ ///
+ [JsonPropertyName("autostart")]
+ [JsonProperty("autostart")]
+ public int? Autostart { get; set; }
+
+ ///
+ /// Indicates whether the interface is currently active/up (1) or down (0).
+ ///
+ [JsonPropertyName("active")]
+ [JsonProperty("active")]
+ public int? Active { get; set; }
+
+ ///
+ /// Optional comment or description for this interface.
+ ///
+ [JsonPropertyName("comments")]
+ [JsonProperty("comments")]
+ public string? Comments { get; set; }
+
+ ///
+ /// IPv4 address in CIDR notation (e.g., "192.168.1.1/24").
+ ///
+ [JsonPropertyName("cidr")]
+ [JsonProperty("cidr")]
+ public string? Cidr { get; set; }
+
+ ///
+ /// Indicates whether VLAN-aware bridging is enabled on this bridge (1) or not (0).
+ ///
+ [JsonPropertyName("bridge_vlan_aware")]
+ [JsonProperty("bridge_vlan_aware")]
+ public int? BridgeVlanAware { get; set; }
+
+ ///
+ /// The bonding mode for bond interfaces (e.g., "active-backup", "802.3ad", "balance-rr").
+ ///
+ [JsonPropertyName("bond_mode")]
+ [JsonProperty("bond_mode")]
+ public string? BondMode { get; set; }
+
+ ///
+ /// The node this network interface belongs to. Populated by cmdlets after retrieval.
+ ///
+ public string? Node { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var addr = Cidr ?? Address ?? "N/A";
+ var activeStr = Active is 1 ? "up" : "down";
+ return $"Network: {Iface} | Type: {Type ?? "N/A"} | Address: {addr} | "
+ + $"GW: {Gateway ?? "N/A"} | MTU: {Mtu?.ToString() ?? "N/A"} | {activeStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Network/PveSdnVnet.cs b/src/PSProxmoxVE.Core/Models/Network/PveSdnVnet.cs
new file mode 100644
index 0000000..f8612e6
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Network/PveSdnVnet.cs
@@ -0,0 +1,62 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Network;
+
+///
+/// Represents a Software-Defined Networking (SDN) virtual network (VNet) as returned by
+/// the /cluster/sdn/vnets endpoint.
+/// Available in Proxmox VE 8.0+.
+///
+public class PveSdnVnet
+{
+ ///
+ /// The unique VNet identifier.
+ ///
+ [JsonPropertyName("vnet")]
+ [JsonProperty("vnet")]
+ public string Vnet { get; set; } = string.Empty;
+
+ ///
+ /// The SDN zone this VNet belongs to.
+ ///
+ [JsonPropertyName("zone")]
+ [JsonProperty("zone")]
+ public string? Zone { get; set; }
+
+ ///
+ /// The VLAN or VXLAN tag associated with this VNet.
+ ///
+ [JsonPropertyName("tag")]
+ [JsonProperty("tag")]
+ public int? Tag { get; set; }
+
+ ///
+ /// An optional human-readable alias for this VNet.
+ ///
+ [JsonPropertyName("alias")]
+ [JsonProperty("alias")]
+ public string? Alias { get; set; }
+
+ ///
+ /// Indicates whether VLAN-aware mode is enabled on this VNet (1) or not (0).
+ ///
+ [JsonPropertyName("vlanaware")]
+ [JsonProperty("vlanaware")]
+ public int? VlanAware { get; set; }
+
+ ///
+ /// Optional comment or description for this SDN VNet.
+ ///
+ [JsonPropertyName("comments")]
+ [JsonProperty("comments")]
+ public string? Comments { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var vlanAwareStr = VlanAware is 1 ? " [vlan-aware]" : string.Empty;
+ return $"SDN VNet: {Vnet}{vlanAwareStr} | Zone: {Zone ?? "N/A"} | "
+ + $"Tag: {Tag?.ToString() ?? "N/A"} | Alias: {Alias ?? "N/A"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Network/PveSdnZone.cs b/src/PSProxmoxVE.Core/Models/Network/PveSdnZone.cs
new file mode 100644
index 0000000..39813fd
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Network/PveSdnZone.cs
@@ -0,0 +1,90 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Network;
+
+///
+/// Represents a Software-Defined Networking (SDN) zone as returned by
+/// the /cluster/sdn/zones endpoint.
+/// Available in Proxmox VE 8.0+.
+///
+public class PveSdnZone
+{
+ ///
+ /// The unique zone identifier.
+ ///
+ [JsonPropertyName("zone")]
+ [JsonProperty("zone")]
+ public string Zone { get; set; } = string.Empty;
+
+ ///
+ /// The zone type (e.g., "simple", "vlan", "qinq", "vxlan", "evpn").
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ /// The DNS server address associated with this zone.
+ ///
+ [JsonPropertyName("dns")]
+ [JsonProperty("dns")]
+ public string? Dns { get; set; }
+
+ ///
+ /// The reverse DNS zone name for this SDN zone.
+ ///
+ [JsonPropertyName("reversedns")]
+ [JsonProperty("reversedns")]
+ public string? Reversedns { get; set; }
+
+ ///
+ /// The DNS zone name used for forward lookups.
+ ///
+ [JsonPropertyName("dnszone")]
+ [JsonProperty("dnszone")]
+ public string? DnsZone { get; set; }
+
+ ///
+ /// The IPAM plugin to use for IP address management in this zone.
+ ///
+ [JsonPropertyName("ipam")]
+ [JsonProperty("ipam")]
+ public string? Ipam { get; set; }
+
+ ///
+ /// The Maximum Transmission Unit in bytes for this zone.
+ ///
+ [JsonPropertyName("mtu")]
+ [JsonProperty("mtu")]
+ public int? Mtu { get; set; }
+
+ ///
+ /// Comma-separated list of nodes that participate in this SDN zone.
+ ///
+ [JsonPropertyName("nodes")]
+ [JsonProperty("nodes")]
+ public string? Nodes { get; set; }
+
+ ///
+ /// Indicates whether the zone has pending (unapplied) configuration changes (1) or not (0).
+ ///
+ [JsonPropertyName("pending")]
+ [JsonProperty("pending")]
+ public int? Pending { get; set; }
+
+ ///
+ /// Optional comment or description for this SDN zone.
+ ///
+ [JsonPropertyName("comments")]
+ [JsonProperty("comments")]
+ public string? Comments { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var pendingStr = Pending is 1 ? " [pending]" : string.Empty;
+ return $"SDN Zone: {Zone}{pendingStr} | Type: {Type ?? "N/A"} | DNS: {Dns ?? "N/A"} | "
+ + $"IPAM: {Ipam ?? "N/A"} | Nodes: {Nodes ?? "all"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Nodes/PveNode.cs b/src/PSProxmoxVE.Core/Models/Nodes/PveNode.cs
new file mode 100644
index 0000000..d0e67b7
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Nodes/PveNode.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Nodes;
+
+///
+/// Represents a Proxmox VE cluster node as returned by the /nodes endpoint.
+///
+public class PveNode
+{
+ ///
+ /// The name of the node.
+ ///
+ [JsonPropertyName("node")]
+ [JsonProperty("node")]
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// The current status of the node (e.g., "online" or "offline").
+ ///
+ [JsonPropertyName("status")]
+ [JsonProperty("status")]
+ public string Status { get; set; } = string.Empty;
+
+ ///
+ /// The total number of CPU cores available on the node.
+ ///
+ [JsonPropertyName("maxcpu")]
+ [JsonProperty("maxcpu")]
+ public int? CpuCount { get; set; }
+
+ ///
+ /// Total memory in bytes available on the node.
+ ///
+ [JsonPropertyName("maxmem")]
+ [JsonProperty("maxmem")]
+ public long? MemoryTotal { get; set; }
+
+ ///
+ /// Memory currently in use on the node, in bytes.
+ ///
+ [JsonPropertyName("mem")]
+ [JsonProperty("mem")]
+ public long? MemoryUsed { get; set; }
+
+ ///
+ /// Node uptime in seconds.
+ ///
+ [JsonPropertyName("uptime")]
+ [JsonProperty("uptime")]
+ public long? Uptime { get; set; }
+
+ ///
+ /// The version of Proxmox VE running on the node.
+ ///
+ [JsonPropertyName("pveversion")]
+ [JsonProperty("pveversion")]
+ public string? PveVersion { get; set; }
+
+ ///
+ /// The Linux kernel version running on the node.
+ ///
+ [JsonPropertyName("kversion")]
+ [JsonProperty("kversion")]
+ public string? KernelVersion { get; set; }
+
+ ///
+ /// The 1-minute, 5-minute, and 15-minute load averages for the node.
+ ///
+ [JsonPropertyName("loadavg")]
+ [JsonProperty("loadavg")]
+ public double[]? LoadAverage { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var memUsedMb = MemoryUsed.HasValue ? $"{MemoryUsed.Value / 1024 / 1024} MB" : "N/A";
+ var memTotalMb = MemoryTotal.HasValue ? $"{MemoryTotal.Value / 1024 / 1024} MB" : "N/A";
+ var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
+ return $"Node: {Name} | Status: {Status} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
+ + $"Mem: {memUsedMb}/{memTotalMb} | Uptime: {uptimeStr} | PVE: {PveVersion ?? "N/A"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Nodes/PveNodeStatus.cs b/src/PSProxmoxVE.Core/Models/Nodes/PveNodeStatus.cs
new file mode 100644
index 0000000..2d11423
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Nodes/PveNodeStatus.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Nodes;
+
+///
+/// Represents detailed status information for a single Proxmox VE node,
+/// as returned by the /nodes/{node}/status endpoint.
+///
+public class PveNodeStatus
+{
+ ///
+ /// The name of the node.
+ ///
+ [JsonPropertyName("node")]
+ [JsonProperty("node")]
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// The current status of the node (e.g., "online" or "offline").
+ ///
+ [JsonPropertyName("status")]
+ [JsonProperty("status")]
+ public string Status { get; set; } = string.Empty;
+
+ ///
+ /// The total number of CPU cores available on the node.
+ ///
+ [JsonPropertyName("maxcpu")]
+ [JsonProperty("maxcpu")]
+ public int? CpuCount { get; set; }
+
+ ///
+ /// Total memory in bytes available on the node.
+ ///
+ [JsonPropertyName("maxmem")]
+ [JsonProperty("maxmem")]
+ public long? MemoryTotal { get; set; }
+
+ ///
+ /// Memory currently in use on the node, in bytes.
+ ///
+ [JsonPropertyName("mem")]
+ [JsonProperty("mem")]
+ public long? MemoryUsed { get; set; }
+
+ ///
+ /// Node uptime in seconds.
+ ///
+ [JsonPropertyName("uptime")]
+ [JsonProperty("uptime")]
+ public long? Uptime { get; set; }
+
+ ///
+ /// The version of Proxmox VE running on the node.
+ ///
+ [JsonPropertyName("pveversion")]
+ [JsonProperty("pveversion")]
+ public string? PveVersion { get; set; }
+
+ ///
+ /// The Linux kernel version running on the node.
+ ///
+ [JsonPropertyName("kversion")]
+ [JsonProperty("kversion")]
+ public string? KernelVersion { get; set; }
+
+ ///
+ /// The 1-minute, 5-minute, and 15-minute load averages for the node.
+ ///
+ [JsonPropertyName("loadavg")]
+ [JsonProperty("loadavg")]
+ public double[]? LoadAverage { get; set; }
+
+ ///
+ /// Total root filesystem size in bytes.
+ ///
+ [JsonPropertyName("rootfs.total")]
+ [JsonProperty("rootfs.total")]
+ public long? DiskTotal { get; set; }
+
+ ///
+ /// Used root filesystem space in bytes.
+ ///
+ [JsonPropertyName("rootfs.used")]
+ [JsonProperty("rootfs.used")]
+ public long? DiskUsed { get; set; }
+
+ ///
+ /// Current CPU utilization as a fraction between 0.0 and 1.0.
+ ///
+ [JsonPropertyName("cpu")]
+ [JsonProperty("cpu")]
+ public double? CpuUsage { get; set; }
+
+ ///
+ /// Memory utilization as a percentage (0–100), computed from MemoryUsed / MemoryTotal.
+ ///
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Newtonsoft.Json.JsonIgnore]
+ public double? MemoryUsage =>
+ MemoryTotal.HasValue && MemoryTotal.Value > 0 && MemoryUsed.HasValue
+ ? (double)MemoryUsed.Value / MemoryTotal.Value * 100.0
+ : null;
+
+ ///
+ /// Total swap space in bytes.
+ ///
+ [JsonPropertyName("swap.total")]
+ [JsonProperty("swap.total")]
+ public long? SwapTotal { get; set; }
+
+ ///
+ /// Used swap space in bytes.
+ ///
+ [JsonPropertyName("swap.used")]
+ [JsonProperty("swap.used")]
+ public long? SwapUsed { get; set; }
+
+ ///
+ /// Total bytes received over the network since boot.
+ ///
+ [JsonPropertyName("netin")]
+ [JsonProperty("netin")]
+ public long? NetworkIn { get; set; }
+
+ ///
+ /// Total bytes transmitted over the network since boot.
+ ///
+ [JsonPropertyName("netout")]
+ [JsonProperty("netout")]
+ public long? NetworkOut { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var memUsedMb = MemoryUsed.HasValue ? $"{MemoryUsed.Value / 1024 / 1024} MB" : "N/A";
+ var memTotalMb = MemoryTotal.HasValue ? $"{MemoryTotal.Value / 1024 / 1024} MB" : "N/A";
+ var cpuPct = CpuUsage.HasValue ? $"{CpuUsage.Value * 100:F1}%" : "N/A";
+ var diskUsedGb = DiskUsed.HasValue ? $"{DiskUsed.Value / 1024 / 1024 / 1024} GB" : "N/A";
+ var diskTotalGb = DiskTotal.HasValue ? $"{DiskTotal.Value / 1024 / 1024 / 1024} GB" : "N/A";
+ var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
+ return $"Node: {Name} | Status: {Status} | CPU: {cpuPct} | "
+ + $"Mem: {memUsedMb}/{memTotalMb} ({MemoryUsage:F1}%) | "
+ + $"Disk: {diskUsedGb}/{diskTotalGb} | Uptime: {uptimeStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Storage/PveStorage.cs b/src/PSProxmoxVE.Core/Models/Storage/PveStorage.cs
new file mode 100644
index 0000000..32ae490
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Storage/PveStorage.cs
@@ -0,0 +1,89 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Storage;
+
+///
+/// Represents a Proxmox VE storage entry as returned by the /storage or /nodes/{node}/storage endpoints.
+///
+public class PveStorage
+{
+ ///
+ /// The unique identifier / name of the storage pool.
+ ///
+ [JsonPropertyName("storage")]
+ [JsonProperty("storage")]
+ public string Storage { get; set; } = string.Empty;
+
+ ///
+ /// The storage backend type (e.g., "dir", "lvm", "zfspool", "nfs", "cifs", "rbd").
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ /// Comma-separated list of content types this storage supports
+ /// (e.g., "images,rootdir,backup,snippets,iso,vztmpl").
+ ///
+ [JsonPropertyName("content")]
+ [JsonProperty("content")]
+ public string? Content { get; set; }
+
+ ///
+ /// Total capacity of the storage pool, in bytes.
+ ///
+ [JsonPropertyName("total")]
+ [JsonProperty("total")]
+ public long? Total { get; set; }
+
+ ///
+ /// Used capacity of the storage pool, in bytes.
+ ///
+ [JsonPropertyName("used")]
+ [JsonProperty("used")]
+ public long? Used { get; set; }
+
+ ///
+ /// Available (free) capacity of the storage pool, in bytes.
+ ///
+ [JsonPropertyName("avail")]
+ [JsonProperty("avail")]
+ public long? Available { get; set; }
+
+ ///
+ /// Indicates whether the storage is enabled (1) or disabled (0) in the configuration.
+ ///
+ [JsonPropertyName("enabled")]
+ [JsonProperty("enabled")]
+ public int? Enabled { get; set; }
+
+ ///
+ /// Indicates whether the storage is shared across all cluster nodes (1) or node-local (0).
+ ///
+ [JsonPropertyName("shared")]
+ [JsonProperty("shared")]
+ public int? Shared { get; set; }
+
+ ///
+ /// Indicates whether the storage is currently active and reachable (1) or not (0).
+ ///
+ [JsonPropertyName("active")]
+ [JsonProperty("active")]
+ public int? Active { get; set; }
+
+ /// The node this storage entry is associated with. Populated by cmdlets after retrieval.
+ public string? Node { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var usedGb = Used.HasValue ? $"{Used.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
+ var totalGb = Total.HasValue ? $"{Total.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
+ var availGb = Available.HasValue ? $"{Available.Value / 1024.0 / 1024 / 1024:F1} GB" : "N/A";
+ var activeStr = Active is 1 ? "active" : "inactive";
+ var sharedStr = Shared is 1 ? "shared" : "local";
+ return $"Storage: {Storage} | Type: {Type ?? "N/A"} | {activeStr} | {sharedStr} | "
+ + $"Used: {usedGb}/{totalGb} | Free: {availGb} | Content: {Content ?? "N/A"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Storage/PveStorageContent.cs b/src/PSProxmoxVE.Core/Models/Storage/PveStorageContent.cs
new file mode 100644
index 0000000..b56a982
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Storage/PveStorageContent.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Storage;
+
+///
+/// Represents a single content item (disk image, backup, ISO, template, etc.)
+/// stored within a Proxmox VE storage pool, as returned by
+/// the /nodes/{node}/storage/{storage}/content endpoint.
+///
+public class PveStorageContent
+{
+ ///
+ /// The full volume identifier in the form "storage:volumename"
+ /// (e.g., "local-lvm:vm-100-disk-0").
+ ///
+ [JsonPropertyName("volid")]
+ [JsonProperty("volid")]
+ public string VolId { get; set; } = string.Empty;
+
+ ///
+ /// The content type of this volume (e.g., "images", "backup", "iso", "vztmpl", "rootdir").
+ ///
+ [JsonPropertyName("content")]
+ [JsonProperty("content")]
+ public string? Content { get; set; }
+
+ ///
+ /// The disk image format (e.g., "raw", "qcow2", "vmdk", "subvol").
+ ///
+ [JsonPropertyName("format")]
+ [JsonProperty("format")]
+ public string? Format { get; set; }
+
+ ///
+ /// The size of the volume in bytes.
+ ///
+ [JsonPropertyName("size")]
+ [JsonProperty("size")]
+ public long? Size { get; set; }
+
+ ///
+ /// Unix timestamp of when the volume was created.
+ ///
+ [JsonPropertyName("ctime")]
+ [JsonProperty("ctime")]
+ public long? CreationTime { get; set; }
+
+ ///
+ /// The VM or container ID that owns this volume, if applicable (e.g., for disk images and backups).
+ ///
+ [JsonPropertyName("vmid")]
+ [JsonProperty("vmid")]
+ public int? VmId { get; set; }
+
+ ///
+ /// Optional notes or description attached to the volume (commonly used on backup files).
+ ///
+ [JsonPropertyName("notes")]
+ [JsonProperty("notes")]
+ public string? Notes { get; set; }
+
+ ///
+ /// Verification status of the volume, if applicable (e.g., for backups verified with vzdump).
+ ///
+ [JsonPropertyName("verification")]
+ [JsonProperty("verification")]
+ public string? Verification { get; set; }
+
+ /// The storage identifier this content resides on. Populated by cmdlets after retrieval.
+ public string? Storage { get; set; }
+
+ /// The node this content was retrieved from. Populated by cmdlets after retrieval.
+ public string? Node { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var sizeGb = Size.HasValue ? $"{Size.Value / 1024.0 / 1024 / 1024:F2} GB" : "N/A";
+ var created = CreationTime.HasValue
+ ? DateTimeOffset.FromUnixTimeSeconds(CreationTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
+ : "N/A";
+ return $"Volume: {VolId} | Content: {Content ?? "N/A"} | Format: {Format ?? "N/A"} | "
+ + $"Size: {sizeGb} | Created: {created}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs b/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs
new file mode 100644
index 0000000..b14b397
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs
@@ -0,0 +1,47 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Users;
+
+///
+/// Represents a single Access Control List (ACL) entry as returned by the /access/acl endpoint.
+/// An ACL entry grants a specific role to a user or group on a particular resource path.
+///
+public class PvePermission
+{
+ ///
+ /// The resource path this ACL entry applies to (e.g., "/", "/nodes/pve", "/vms/100").
+ ///
+ [JsonPropertyName("path")]
+ [JsonProperty("path")]
+ public string? Path { get; set; }
+
+ ///
+ /// The role ID granted by this ACL entry (e.g., "Administrator", "PVEVMAdmin").
+ ///
+ [JsonPropertyName("roleid")]
+ [JsonProperty("roleid")]
+ public string? RoleId { get; set; }
+
+ ///
+ /// Indicates whether the permission propagates to sub-paths (1) or is restricted to the exact path (0).
+ ///
+ [JsonPropertyName("propagate")]
+ [JsonProperty("propagate")]
+ public int? Propagate { get; set; }
+
+ ///
+ /// The user ID or group ID (with "@" prefix for groups) that this ACL entry applies to.
+ /// Maps to the "ugid" JSON field.
+ ///
+ [JsonPropertyName("ugid")]
+ [JsonProperty("ugid")]
+ public string? UserId { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var propagateStr = Propagate is 1 ? " [propagate]" : string.Empty;
+ return $"ACL: {UserId ?? "N/A"} | Path: {Path ?? "/"} | Role: {RoleId ?? "N/A"}{propagateStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Users/PveRole.cs b/src/PSProxmoxVE.Core/Models/Users/PveRole.cs
new file mode 100644
index 0000000..49a23b7
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Users/PveRole.cs
@@ -0,0 +1,41 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Users;
+
+///
+/// Represents a Proxmox VE role as returned by the /access/roles endpoint.
+/// Roles are named collections of privileges that can be assigned to users or groups via ACLs.
+///
+public class PveRole
+{
+ ///
+ /// The unique role identifier (e.g., "Administrator", "PVEVMAdmin", "PVEDatastoreUser").
+ ///
+ [JsonPropertyName("roleid")]
+ [JsonProperty("roleid")]
+ public string RoleId { get; set; } = string.Empty;
+
+ ///
+ /// Comma-separated list of privilege strings assigned to this role
+ /// (e.g., "VM.Allocate,VM.Config.Disk,Datastore.AllocateSpace").
+ ///
+ [JsonPropertyName("privs")]
+ [JsonProperty("privs")]
+ public string? Privileges { get; set; }
+
+ ///
+ /// Indicates whether this is a built-in / special role (1) that cannot be deleted,
+ /// or a custom role (0).
+ ///
+ [JsonPropertyName("special")]
+ [JsonProperty("special")]
+ public int? Special { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var specialStr = Special is 1 ? " [built-in]" : string.Empty;
+ return $"Role: {RoleId}{specialStr} | Privs: {Privileges ?? "none"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Users/PveUser.cs b/src/PSProxmoxVE.Core/Models/Users/PveUser.cs
new file mode 100644
index 0000000..f1ca079
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Users/PveUser.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Linq;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Users;
+
+///
+/// Represents a Proxmox VE user account as returned by the /access/users endpoint.
+///
+public class PveUser
+{
+ ///
+ /// The full user ID in the format "username@realm" (e.g., "admin@pam", "user@pve").
+ ///
+ [JsonPropertyName("userid")]
+ [JsonProperty("userid")]
+ public string UserId { get; set; } = string.Empty;
+
+ ///
+ /// The user's first name.
+ ///
+ [JsonPropertyName("firstname")]
+ [JsonProperty("firstname")]
+ public string? FirstName { get; set; }
+
+ ///
+ /// The user's last name.
+ ///
+ [JsonPropertyName("lastname")]
+ [JsonProperty("lastname")]
+ public string? LastName { get; set; }
+
+ ///
+ /// The user's email address.
+ ///
+ [JsonPropertyName("email")]
+ [JsonProperty("email")]
+ public string? Email { get; set; }
+
+ ///
+ /// Indicates whether the user account is enabled (1) or disabled (0).
+ ///
+ [JsonPropertyName("enable")]
+ [JsonProperty("enable")]
+ public int? Enabled { get; set; }
+
+ ///
+ /// The authentication realm for this user (e.g., "pam", "pve", "ldap").
+ ///
+ [JsonPropertyName("realm")]
+ [JsonProperty("realm")]
+ public string? Realm { get; set; }
+
+ ///
+ /// Comma-separated list of groups this user is a member of.
+ ///
+ [JsonPropertyName("groups")]
+ [JsonProperty("groups")]
+ public string? Groups { get; set; }
+
+ ///
+ /// Optional comment or description for this user account.
+ ///
+ [JsonPropertyName("comment")]
+ [JsonProperty("comment")]
+ public string? Comment { get; set; }
+
+ ///
+ /// Account expiry as a Unix timestamp. 0 or null means the account never expires.
+ ///
+ [JsonPropertyName("expire")]
+ [JsonProperty("expire")]
+ public long? Expire { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var fullName = string.Join(" ", new[] { FirstName, LastName }.Where(s => !string.IsNullOrWhiteSpace(s)));
+ var enabledStr = Enabled is 1 ? "enabled" : "disabled";
+ var expireStr = Expire is > 0 ? DateTimeOffset.FromUnixTimeSeconds(Expire.Value).ToString("yyyy-MM-dd") : "never";
+ return $"User: {UserId} | Name: {(string.IsNullOrEmpty(fullName) ? "N/A" : fullName)} | "
+ + $"{enabledStr} | Groups: {Groups ?? "none"} | Expires: {expireStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveCloudInitConfig.cs b/src/PSProxmoxVE.Core/Models/Vms/PveCloudInitConfig.cs
new file mode 100644
index 0000000..63aa9ab
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveCloudInitConfig.cs
@@ -0,0 +1,54 @@
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms
+{
+ ///
+ /// Represents the Cloud-Init specific configuration fields for a VM.
+ /// Fields are extracted from the full VM config.
+ ///
+ public class PveCloudInitConfig
+ {
+ /// Default user name injected by Cloud-Init.
+ [JsonProperty("ciuser")]
+ public string? CiUser { get; set; }
+
+ /// Default user password (may be hashed).
+ [JsonProperty("cipassword")]
+ public string? CiPassword { get; set; }
+
+ /// URL-encoded SSH public keys.
+ [JsonProperty("sshkeys")]
+ public string? SshKeys { get; set; }
+
+ /// IP configuration for interface 0 (e.g. "ip=dhcp" or "ip=192.168.1.10/24,gw=192.168.1.1").
+ [JsonProperty("ipconfig0")]
+ public string? IpConfig0 { get; set; }
+
+ /// IP configuration for interface 1.
+ [JsonProperty("ipconfig1")]
+ public string? IpConfig1 { get; set; }
+
+ /// IP configuration for interface 2.
+ [JsonProperty("ipconfig2")]
+ public string? IpConfig2 { get; set; }
+
+ /// IP configuration for interface 3.
+ [JsonProperty("ipconfig3")]
+ public string? IpConfig3 { get; set; }
+
+ /// DNS nameserver(s) space-separated.
+ [JsonProperty("nameserver")]
+ public string? Nameserver { get; set; }
+
+ /// DNS search domain.
+ [JsonProperty("searchdomain")]
+ public string? Searchdomain { get; set; }
+
+ /// Custom Cloud-Init config files (cicustom field).
+ [JsonProperty("cicustom")]
+ public string? CiCustom { get; set; }
+
+ public override string ToString() =>
+ $"CloudInit: User={CiUser ?? "N/A"} | IP0={IpConfig0 ?? "N/A"} | NS={Nameserver ?? "N/A"}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveSnapshot.cs b/src/PSProxmoxVE.Core/Models/Vms/PveSnapshot.cs
new file mode 100644
index 0000000..af17441
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveSnapshot.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms;
+
+///
+/// Represents a VM snapshot as returned by the /nodes/{node}/qemu/{vmid}/snapshot endpoint.
+///
+public class PveSnapshot
+{
+ ///
+ /// The snapshot name / identifier.
+ ///
+ [JsonPropertyName("name")]
+ [JsonProperty("name")]
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Optional human-readable description of what this snapshot captures.
+ ///
+ [JsonPropertyName("description")]
+ [JsonProperty("description")]
+ public string? Description { get; set; }
+
+ ///
+ /// Unix timestamp when the snapshot was created.
+ ///
+ [JsonPropertyName("snaptime")]
+ [JsonProperty("snaptime")]
+ public long? SnapTime { get; set; }
+
+ ///
+ /// Indicates whether the VM RAM state was saved with this snapshot (1) or not (0).
+ ///
+ [JsonPropertyName("vmstate")]
+ [JsonProperty("vmstate")]
+ public int? VmState { get; set; }
+
+ ///
+ /// The name of the parent snapshot, or null if this is the root snapshot.
+ ///
+ [JsonPropertyName("parent")]
+ [JsonProperty("parent")]
+ public string? Parent { get; set; }
+
+ /// The VM ID this snapshot belongs to. Populated by cmdlets after retrieval.
+ public int VmId { get; set; }
+
+ /// The node the VM resides on. Populated by cmdlets after retrieval.
+ public string? Node { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var timeStr = SnapTime.HasValue
+ ? DateTimeOffset.FromUnixTimeSeconds(SnapTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
+ : "N/A";
+ var stateStr = VmState is 1 ? " [+vmstate]" : string.Empty;
+ var parentStr = Parent is not null ? $" | Parent: {Parent}" : string.Empty;
+ return $"Snapshot: {Name}{stateStr} | Created: {timeStr} | "
+ + $"Description: {Description ?? "(none)"}{parentStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveTask.cs b/src/PSProxmoxVE.Core/Models/Vms/PveTask.cs
new file mode 100644
index 0000000..617c2cb
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveTask.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms;
+
+///
+/// Represents a Proxmox VE asynchronous task as returned by the task-related endpoints
+/// (e.g., /nodes/{node}/tasks, /nodes/{node}/tasks/{upid}/status).
+/// Most mutating API calls return a UPID string that identifies the created task.
+///
+public class PveTask
+{
+ ///
+ /// The Unique Process Identifier for this task
+ /// (e.g., "UPID:pve:000ABC:00000001:5F1234AB:qmstart:100:root@pam:").
+ ///
+ [JsonPropertyName("upid")]
+ [JsonProperty("upid")]
+ public string Upid { get; set; } = string.Empty;
+
+ ///
+ /// The task type string (e.g., "qmstart", "qmstop", "qmmigrate", "vzrestore").
+ ///
+ [JsonPropertyName("type")]
+ [JsonProperty("type")]
+ public string? Type { get; set; }
+
+ ///
+ /// The current task status: "running" while in progress, "stopped" when complete.
+ ///
+ [JsonPropertyName("status")]
+ [JsonProperty("status")]
+ public string? Status { get; set; }
+
+ ///
+ /// The exit status when the task has stopped (e.g., "OK" on success, or an error message).
+ ///
+ [JsonPropertyName("exitstatus")]
+ [JsonProperty("exitstatus")]
+ public string? ExitStatus { get; set; }
+
+ ///
+ /// The node on which this task is executing.
+ ///
+ [JsonPropertyName("node")]
+ [JsonProperty("node")]
+ public string? Node { get; set; }
+
+ ///
+ /// Unix timestamp of when the task started.
+ ///
+ [JsonPropertyName("starttime")]
+ [JsonProperty("starttime")]
+ public long? StartTime { get; set; }
+
+ ///
+ /// Unix timestamp of when the task ended. Null if still running.
+ ///
+ [JsonPropertyName("endtime")]
+ [JsonProperty("endtime")]
+ public long? EndTime { get; set; }
+
+ ///
+ /// The user that initiated the task (e.g., "root@pam").
+ ///
+ [JsonPropertyName("user")]
+ [JsonProperty("user")]
+ public string? User { get; set; }
+
+ ///
+ /// The object ID the task is operating on (e.g., a VM ID or storage name).
+ ///
+ [JsonPropertyName("id")]
+ [JsonProperty("id")]
+ public string? Id { get; set; }
+
+ ///
+ /// Returns true when the task completed successfully (stopped with exit status "OK").
+ ///
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Newtonsoft.Json.JsonIgnore]
+ public bool IsSuccessful => Status == "stopped" && ExitStatus == "OK";
+
+ ///
+ public override string ToString()
+ {
+ var startStr = StartTime.HasValue
+ ? DateTimeOffset.FromUnixTimeSeconds(StartTime.Value).ToString("yyyy-MM-dd HH:mm:ss")
+ : "N/A";
+ return $"Task [{Type ?? "unknown"}] UPID: {Upid} | Node: {Node ?? "N/A"} | "
+ + $"Status: {Status ?? "unknown"} | ExitStatus: {ExitStatus ?? "-"} | "
+ + $"User: {User ?? "N/A"} | Started: {startStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveTaskLog.cs b/src/PSProxmoxVE.Core/Models/Vms/PveTaskLog.cs
new file mode 100644
index 0000000..4158923
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveTaskLog.cs
@@ -0,0 +1,21 @@
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms
+{
+ ///
+ /// Represents a single log line from a Proxmox VE task log,
+ /// as returned by the /nodes/{node}/tasks/{upid}/log endpoint.
+ ///
+ public class PveTaskLog
+ {
+ /// Line number (1-based).
+ [JsonProperty("n")]
+ public int LineNumber { get; set; }
+
+ /// Log line text.
+ [JsonProperty("t")]
+ public string Text { get; set; } = string.Empty;
+
+ public override string ToString() => $"{LineNumber,4}: {Text}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveVm.cs b/src/PSProxmoxVE.Core/Models/Vms/PveVm.cs
new file mode 100644
index 0000000..88d1f32
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveVm.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms;
+
+///
+/// Represents a QEMU/KVM virtual machine as returned by the cluster or node VM list endpoints.
+///
+public class PveVm
+{
+ ///
+ /// The unique VM identifier.
+ ///
+ [JsonPropertyName("vmid")]
+ [JsonProperty("vmid")]
+ public int VmId { get; set; }
+
+ ///
+ /// The name of the virtual machine.
+ ///
+ [JsonPropertyName("name")]
+ [JsonProperty("name")]
+ public string? Name { get; set; }
+
+ ///
+ /// The current runtime status of the VM (e.g., "running", "stopped").
+ ///
+ [JsonPropertyName("status")]
+ [JsonProperty("status")]
+ public string? Status { get; set; }
+
+ ///
+ /// The node on which the VM resides.
+ ///
+ [JsonPropertyName("node")]
+ [JsonProperty("node")]
+ public string? Node { get; set; }
+
+ ///
+ /// The number of virtual CPU cores assigned to the VM.
+ ///
+ [JsonPropertyName("cpus")]
+ [JsonProperty("cpus")]
+ public int? CpuCount { get; set; }
+
+ ///
+ /// Maximum memory allocated to the VM, in bytes.
+ ///
+ [JsonPropertyName("maxmem")]
+ [JsonProperty("maxmem")]
+ public long? MaxMem { get; set; }
+
+ ///
+ /// Maximum disk size allocated to the VM, in bytes.
+ ///
+ [JsonPropertyName("maxdisk")]
+ [JsonProperty("maxdisk")]
+ public long? MaxDisk { get; set; }
+
+ ///
+ /// VM uptime in seconds.
+ ///
+ [JsonPropertyName("uptime")]
+ [JsonProperty("uptime")]
+ public long? Uptime { get; set; }
+
+ ///
+ /// Semicolon-separated list of tags assigned to the VM.
+ ///
+ [JsonPropertyName("tags")]
+ [JsonProperty("tags")]
+ public string? Tags { get; set; }
+
+ ///
+ /// Indicates whether the VM is a template (1) or a regular VM (0).
+ ///
+ [JsonPropertyName("template")]
+ [JsonProperty("template")]
+ public int? Template { get; set; }
+
+ ///
+ /// The current lock type applied to the VM, if any (e.g., "migrate", "backup").
+ ///
+ [JsonPropertyName("lock")]
+ [JsonProperty("lock")]
+ public string? Lock { get; set; }
+
+ ///
+ /// The process ID of the running QEMU process, if applicable.
+ ///
+ [JsonPropertyName("pid")]
+ [JsonProperty("pid")]
+ public int? Pid { get; set; }
+
+ ///
+ /// The QMP (QEMU Machine Protocol) status string.
+ ///
+ [JsonPropertyName("qmpstatus")]
+ [JsonProperty("qmpstatus")]
+ public string? QmpStatus { get; set; }
+
+ ///
+ /// Indicates whether the QEMU guest agent is running (non-zero) inside the VM.
+ ///
+ [JsonPropertyName("agent")]
+ [JsonProperty("agent")]
+ public int? AgentStatus { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var maxMemMb = MaxMem.HasValue ? $"{MaxMem.Value / 1024 / 1024} MB" : "N/A";
+ var maxDiskGb = MaxDisk.HasValue ? $"{MaxDisk.Value / 1024 / 1024 / 1024} GB" : "N/A";
+ var uptimeStr = Uptime.HasValue ? TimeSpan.FromSeconds(Uptime.Value).ToString(@"d\.hh\:mm\:ss") : "N/A";
+ var templateStr = Template is 1 ? " [template]" : string.Empty;
+ return $"VM {VmId}{templateStr}: {Name ?? "(unnamed)"} | Node: {Node ?? "N/A"} | "
+ + $"Status: {Status ?? "N/A"} | CPUs: {CpuCount?.ToString() ?? "N/A"} | "
+ + $"Mem: {maxMemMb} | Disk: {maxDiskGb} | Uptime: {uptimeStr}";
+ }
+}
diff --git a/src/PSProxmoxVE.Core/Models/Vms/PveVmConfig.cs b/src/PSProxmoxVE.Core/Models/Vms/PveVmConfig.cs
new file mode 100644
index 0000000..ebf90a5
--- /dev/null
+++ b/src/PSProxmoxVE.Core/Models/Vms/PveVmConfig.cs
@@ -0,0 +1,353 @@
+using System.Text.Json.Serialization;
+using Newtonsoft.Json;
+
+namespace PSProxmoxVE.Core.Models.Vms;
+
+///
+/// Represents the configuration of a QEMU/KVM virtual machine,
+/// as returned by the /nodes/{node}/qemu/{vmid}/config endpoint.
+///
+public class PveVmConfig
+{
+ // -------------------------------------------------------------------------
+ // CPU / Memory
+ // -------------------------------------------------------------------------
+
+ ///
+ /// Number of CPU cores per socket.
+ ///
+ [JsonPropertyName("cores")]
+ [JsonProperty("cores")]
+ public int? Cores { get; set; }
+
+ ///
+ /// Number of CPU sockets.
+ ///
+ [JsonPropertyName("sockets")]
+ [JsonProperty("sockets")]
+ public int? Sockets { get; set; }
+
+ ///
+ /// Memory size in megabytes.
+ ///
+ [JsonPropertyName("memory")]
+ [JsonProperty("memory")]
+ public int? Memory { get; set; }
+
+ ///
+ /// Emulated CPU type (e.g., "host", "x86-64-v2-AES").
+ ///
+ [JsonPropertyName("cpu")]
+ [JsonProperty("cpu")]
+ public string? CpuType { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Firmware / Machine
+ // -------------------------------------------------------------------------
+
+ ///
+ /// BIOS implementation to use: "seabios" (default) or "ovmf" (UEFI).
+ ///
+ [JsonPropertyName("bios")]
+ [JsonProperty("bios")]
+ public string? Bios { get; set; }
+
+ ///
+ /// Emulated machine type (e.g., "q35", "i440fx").
+ ///
+ [JsonPropertyName("machine")]
+ [JsonProperty("machine")]
+ public string? Machine { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Boot / Args
+ // -------------------------------------------------------------------------
+
+ ///
+ /// Boot order specification string.
+ ///
+ [JsonPropertyName("boot")]
+ [JsonProperty("boot")]
+ public string? Boot { get; set; }
+
+ ///
+ /// Arbitrary QEMU command-line arguments appended to the QEMU launch command.
+ ///
+ [JsonPropertyName("args")]
+ [JsonProperty("args")]
+ public string? Args { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Metadata
+ // -------------------------------------------------------------------------
+
+ ///
+ /// Human-readable description or notes for the VM.
+ ///
+ [JsonPropertyName("description")]
+ [JsonProperty("description")]
+ public string? Description { get; set; }
+
+ ///
+ /// Semicolon-separated list of tags assigned to the VM.
+ ///
+ [JsonPropertyName("tags")]
+ [JsonProperty("tags")]
+ public string? Tags { get; set; }
+
+ ///
+ /// When set to 1, prevents the VM from being deleted or modified accidentally.
+ ///
+ [JsonPropertyName("protection")]
+ [JsonProperty("protection")]
+ public int? Protection { get; set; }
+
+ ///
+ /// NUMA topology enabled (1) or disabled (0).
+ ///
+ [JsonPropertyName("numa")]
+ [JsonProperty("numa")]
+ public int? Numa { get; set; }
+
+ ///
+ /// VirtIO balloon device target memory in MB. 0 disables ballooning.
+ ///
+ [JsonPropertyName("balloon")]
+ [JsonProperty("balloon")]
+ public int? Balloon { get; set; }
+
+ ///
+ /// Guest OS type hint (e.g., "l26" for Linux 2.6+, "win10").
+ ///
+ [JsonPropertyName("ostype")]
+ [JsonProperty("ostype")]
+ public string? OsType { get; set; }
+
+ // -------------------------------------------------------------------------
+ // VirtIO disk slots (0–3, most commonly used)
+ // -------------------------------------------------------------------------
+
+ /// VirtIO disk slot 0 configuration string.
+ [JsonPropertyName("virtio0")]
+ [JsonProperty("virtio0")]
+ public string? Virtio0 { get; set; }
+
+ /// VirtIO disk slot 1 configuration string.
+ [JsonPropertyName("virtio1")]
+ [JsonProperty("virtio1")]
+ public string? Virtio1 { get; set; }
+
+ /// VirtIO disk slot 2 configuration string.
+ [JsonPropertyName("virtio2")]
+ [JsonProperty("virtio2")]
+ public string? Virtio2 { get; set; }
+
+ /// VirtIO disk slot 3 configuration string.
+ [JsonPropertyName("virtio3")]
+ [JsonProperty("virtio3")]
+ public string? Virtio3 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // SCSI disk slots (0–7)
+ // -------------------------------------------------------------------------
+
+ /// SCSI disk slot 0 configuration string.
+ [JsonPropertyName("scsi0")]
+ [JsonProperty("scsi0")]
+ public string? Scsi0 { get; set; }
+
+ /// SCSI disk slot 1 configuration string.
+ [JsonPropertyName("scsi1")]
+ [JsonProperty("scsi1")]
+ public string? Scsi1 { get; set; }
+
+ /// SCSI disk slot 2 configuration string.
+ [JsonPropertyName("scsi2")]
+ [JsonProperty("scsi2")]
+ public string? Scsi2 { get; set; }
+
+ /// SCSI disk slot 3 configuration string.
+ [JsonPropertyName("scsi3")]
+ [JsonProperty("scsi3")]
+ public string? Scsi3 { get; set; }
+
+ /// SCSI disk slot 4 configuration string.
+ [JsonPropertyName("scsi4")]
+ [JsonProperty("scsi4")]
+ public string? Scsi4 { get; set; }
+
+ /// SCSI disk slot 5 configuration string.
+ [JsonPropertyName("scsi5")]
+ [JsonProperty("scsi5")]
+ public string? Scsi5 { get; set; }
+
+ /// SCSI disk slot 6 configuration string.
+ [JsonPropertyName("scsi6")]
+ [JsonProperty("scsi6")]
+ public string? Scsi6 { get; set; }
+
+ /// SCSI disk slot 7 configuration string.
+ [JsonPropertyName("scsi7")]
+ [JsonProperty("scsi7")]
+ public string? Scsi7 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // IDE disk slots (0–3)
+ // -------------------------------------------------------------------------
+
+ /// IDE disk/CDROM slot 0 configuration string.
+ [JsonPropertyName("ide0")]
+ [JsonProperty("ide0")]
+ public string? Ide0 { get; set; }
+
+ /// IDE disk/CDROM slot 1 configuration string.
+ [JsonPropertyName("ide1")]
+ [JsonProperty("ide1")]
+ public string? Ide1 { get; set; }
+
+ /// IDE disk/CDROM slot 2 configuration string.
+ [JsonPropertyName("ide2")]
+ [JsonProperty("ide2")]
+ public string? Ide2 { get; set; }
+
+ /// IDE disk/CDROM slot 3 configuration string.
+ [JsonPropertyName("ide3")]
+ [JsonProperty("ide3")]
+ public string? Ide3 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // SATA disk slots (0–5)
+ // -------------------------------------------------------------------------
+
+ /// SATA disk slot 0 configuration string.
+ [JsonPropertyName("sata0")]
+ [JsonProperty("sata0")]
+ public string? Sata0 { get; set; }
+
+ /// SATA disk slot 1 configuration string.
+ [JsonPropertyName("sata1")]
+ [JsonProperty("sata1")]
+ public string? Sata1 { get; set; }
+
+ /// SATA disk slot 2 configuration string.
+ [JsonPropertyName("sata2")]
+ [JsonProperty("sata2")]
+ public string? Sata2 { get; set; }
+
+ /// SATA disk slot 3 configuration string.
+ [JsonPropertyName("sata3")]
+ [JsonProperty("sata3")]
+ public string? Sata3 { get; set; }
+
+ /// SATA disk slot 4 configuration string.
+ [JsonPropertyName("sata4")]
+ [JsonProperty("sata4")]
+ public string? Sata4 { get; set; }
+
+ /// SATA disk slot 5 configuration string.
+ [JsonPropertyName("sata5")]
+ [JsonProperty("sata5")]
+ public string? Sata5 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Network interface slots (0–7)
+ // -------------------------------------------------------------------------
+
+ /// Network interface 0 configuration string (e.g., "virtio=XX:XX:XX:XX:XX:XX,bridge=vmbr0").
+ [JsonPropertyName("net0")]
+ [JsonProperty("net0")]
+ public string? Net0 { get; set; }
+
+ /// Network interface 1 configuration string.
+ [JsonPropertyName("net1")]
+ [JsonProperty("net1")]
+ public string? Net1 { get; set; }
+
+ /// Network interface 2 configuration string.
+ [JsonPropertyName("net2")]
+ [JsonProperty("net2")]
+ public string? Net2 { get; set; }
+
+ /// Network interface 3 configuration string.
+ [JsonPropertyName("net3")]
+ [JsonProperty("net3")]
+ public string? Net3 { get; set; }
+
+ /// Network interface 4 configuration string.
+ [JsonPropertyName("net4")]
+ [JsonProperty("net4")]
+ public string? Net4 { get; set; }
+
+ /// Network interface 5 configuration string.
+ [JsonPropertyName("net5")]
+ [JsonProperty("net5")]
+ public string? Net5 { get; set; }
+
+ /// Network interface 6 configuration string.
+ [JsonPropertyName("net6")]
+ [JsonProperty("net6")]
+ public string? Net6 { get; set; }
+
+ /// Network interface 7 configuration string.
+ [JsonPropertyName("net7")]
+ [JsonProperty("net7")]
+ public string? Net7 { get; set; }
+
+ // -------------------------------------------------------------------------
+ // Cloud-Init
+ // -------------------------------------------------------------------------
+
+ /// Cloud-Init default user name.
+ [JsonPropertyName("ciuser")]
+ [JsonProperty("ciuser")]
+ public string? CiUser { get; set; }
+
+ /// Cloud-Init default user password (hashed or plaintext depending on PVE version).
+ [JsonPropertyName("cipassword")]
+ [JsonProperty("cipassword")]
+ public string? CiPassword { get; set; }
+
+ /// URL-encoded SSH public keys injected by Cloud-Init.
+ [JsonPropertyName("sshkeys")]
+ [JsonProperty("sshkeys")]
+ public string? SshKeys { get; set; }
+
+ /// Cloud-Init IP configuration for interface 0.
+ [JsonPropertyName("ipconfig0")]
+ [JsonProperty("ipconfig0")]
+ public string? IpConfig0 { get; set; }
+
+ /// Cloud-Init IP configuration for interface 1.
+ [JsonPropertyName("ipconfig1")]
+ [JsonProperty("ipconfig1")]
+ public string? IpConfig1 { get; set; }
+
+ /// Cloud-Init IP configuration for interface 2.
+ [JsonPropertyName("ipconfig2")]
+ [JsonProperty("ipconfig2")]
+ public string? IpConfig2 { get; set; }
+
+ /// Cloud-Init IP configuration for interface 3.
+ [JsonPropertyName("ipconfig3")]
+ [JsonProperty("ipconfig3")]
+ public string? IpConfig3 { get; set; }
+
+ /// DNS nameserver(s) injected via Cloud-Init.
+ [JsonPropertyName("nameserver")]
+ [JsonProperty("nameserver")]
+ public string? Nameserver { get; set; }
+
+ /// DNS search domain injected via Cloud-Init.
+ [JsonPropertyName("searchdomain")]
+ [JsonProperty("searchdomain")]
+ public string? Searchdomain { get; set; }
+
+ ///
+ public override string ToString()
+ {
+ var totalCores = (Cores ?? 1) * (Sockets ?? 1);
+ return $"Config | CPUs: {totalCores} ({Sockets ?? 1}S x {Cores ?? 1}C) | "
+ + $"Memory: {Memory?.ToString() ?? "N/A"} MB | BIOS: {Bios ?? "seabios"} | "
+ + $"Machine: {Machine ?? "default"} | OS: {OsType ?? "N/A"}";
+ }
+}