diff --git a/README.md b/README.md
index 0cbba48..a94a761 100644
--- a/README.md
+++ b/README.md
@@ -238,6 +238,7 @@ SDN management requires Proxmox VE 8.0 or later. Connected server is version 7.4
| `Stop-PveContainer` | Stop a container |
| `Restart-PveContainer` | Restart a container |
| `Copy-PveContainer` | Clone a container |
+| `Move-PveContainer` | Migrate a container to another node |
| `Get-PveContainerConfig` | Get container configuration |
| `Set-PveContainerConfig` | Modify container configuration |
| `Get-PveContainerSnapshot` | List container snapshots |
diff --git a/src/PSProxmoxVE/Cmdlets/Containers/MovePveContainerCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Containers/MovePveContainerCmdlet.cs
new file mode 100644
index 0000000..3505d98
--- /dev/null
+++ b/src/PSProxmoxVE/Cmdlets/Containers/MovePveContainerCmdlet.cs
@@ -0,0 +1,63 @@
+using System.Management.Automation;
+using PSProxmoxVE.Core.Models.Vms;
+using PSProxmoxVE.Core.Services;
+
+namespace PSProxmoxVE.Cmdlets.Containers
+{
+ ///
+ /// Migrates an LXC container to a different Proxmox VE node.
+ ///
+ /// Performs a live or offline migration of the specified container to the target node.
+ /// Use -Online for live migration (container remains running). Use -Wait to block until the
+ /// migration task completes.
+ ///
+ ///
+ [Cmdlet(VerbsCommon.Move, "PveContainer", SupportsShouldProcess = true)]
+ [OutputType(typeof(PveTask))]
+ public sealed class MovePveContainerCmdlet : PveCmdletBase
+ {
+ /// The node on which the container currently resides.
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The PVE node name.")]
+ public string Node { get; set; } = string.Empty;
+
+ /// The ID of the container to migrate. Accepts pipeline input.
+ [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The container identifier.")]
+ [ValidateRange(100, 999999999)]
+ public int VmId { get; set; }
+
+ /// The destination node to migrate the container to.
+ [Parameter(Mandatory = true, HelpMessage = "The destination node for migration.")]
+ public string TargetNode { get; set; } = string.Empty;
+
+ ///
+ /// When specified, performs a live migration so the container remains running during migration.
+ /// Requires shared storage between the source and target nodes.
+ ///
+ [Parameter(Mandatory = false, HelpMessage = "Perform live migration (container stays running).")]
+ public SwitchParameter Online { get; set; }
+
+ /// When specified, waits for the migration task to complete before returning.
+ [Parameter(Mandatory = false, HelpMessage = "Wait for the task to complete before returning.")]
+ public SwitchParameter Wait { get; set; }
+
+ protected override void ProcessRecord()
+ {
+ if (!ShouldProcess($"Container {VmId} from node '{Node}' to node '{TargetNode}'", "Move-PveContainer"))
+ return;
+
+ var session = GetSession();
+ var service = new ContainerService();
+
+ WriteVerbose($"Migrating container {VmId} from '{Node}' to '{TargetNode}'...");
+ var task = service.MigrateContainer(session, Node, VmId, TargetNode, Online.IsPresent);
+
+ if (Wait.IsPresent)
+ {
+ var taskService = new TaskService();
+ task = taskService.WaitForTask(session, Node, task.Upid, null, null, null);
+ }
+
+ WriteObject(task);
+ }
+ }
+}
diff --git a/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1 b/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1
index 8b3939b..8bb325c 100644
--- a/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1
+++ b/tests/PSProxmoxVE.Tests/Containers/ContainerLifecycle.Tests.ps1
@@ -18,7 +18,7 @@ BeforeAll {
'Start-PveContainer', 'Stop-PveContainer',
'Restart-PveContainer',
'Get-PveContainerConfig', 'Set-PveContainerConfig',
- 'Copy-PveContainer')) {
+ 'Copy-PveContainer', 'Move-PveContainer')) {
$script:Availability[$name] = $null -ne (Get-Command $name -ErrorAction SilentlyContinue)
}
@@ -293,3 +293,64 @@ Describe 'Restart-PveContainer' {
}
}
}
+
+# ---------------------------------------------------------------------------
+# Move-PveContainer
+# ---------------------------------------------------------------------------
+Describe 'Move-PveContainer' {
+
+ BeforeAll { $script:Cmd = Get-Command 'Move-PveContainer' -ErrorAction SilentlyContinue }
+
+ Context 'Command existence' {
+ It 'Should be available after module import' {
+ Skip-IfMissing 'Move-PveContainer'
+ $script:Cmd | Should -Not -BeNullOrEmpty
+ }
+ }
+
+ Context 'Parameter metadata' {
+ It 'Node should be Mandatory' {
+ Skip-IfMissing 'Move-PveContainer'
+ $isMandatory = $script:Cmd.Parameters['Node'].ParameterSets.Values |
+ Where-Object { $_.IsMandatory }
+ $isMandatory | Should -Not -BeNullOrEmpty
+ }
+
+ It 'VmId should be Mandatory' {
+ Skip-IfMissing 'Move-PveContainer'
+ $isMandatory = $script:Cmd.Parameters['VmId'].ParameterSets.Values |
+ Where-Object { $_.IsMandatory }
+ $isMandatory | Should -Not -BeNullOrEmpty
+ }
+
+ It 'TargetNode should be Mandatory' {
+ Skip-IfMissing 'Move-PveContainer'
+ $isMandatory = $script:Cmd.Parameters['TargetNode'].ParameterSets.Values |
+ Where-Object { $_.IsMandatory }
+ $isMandatory | Should -Not -BeNullOrEmpty
+ }
+
+ It 'Should have Online switch parameter' {
+ Skip-IfMissing 'Move-PveContainer'
+ $script:Cmd.Parameters.ContainsKey('Online') | Should -BeTrue
+ }
+
+ It 'Should have Wait switch parameter' {
+ Skip-IfMissing 'Move-PveContainer'
+ $script:Cmd.Parameters.ContainsKey('Wait') | Should -BeTrue
+ }
+
+ It 'Should support ShouldProcess' {
+ Skip-IfMissing 'Move-PveContainer'
+ $script:Cmd.Parameters.ContainsKey('WhatIf') | Should -BeTrue
+ }
+ }
+
+ Context 'Without active session' {
+ It 'Should throw when no session is active' {
+ Skip-IfMissing 'Move-PveContainer'
+ { Move-PveContainer -Node 'pve-node1' -VmId 200 -TargetNode 'pve-node2' -ErrorAction Stop } |
+ Should -Throw '*No active Proxmox VE session*'
+ }
+ }
+}