Yesterday I showed you how to perform an advanced storage migration with Windows “8” using the graphical user interface.  Today I want to show you how to do the same thing in PowerShell.

Just like when we did a simple storage migration in PowerShell – you use the Move-VMStorage command.  But instead of providing a single location (via the DestinationStoragePath parameter) you will need to provide the new location for each part of the virtual machine that you want to move.  You can use the VirtualMachinePath, SnapshotFilePath and SmartPagingFilePath parameters to specify the new location for the virtual machine configuration file, snapshot configuration files and the smart paging file respectively.

However, where things get tricky is when you want to specify new locations for the virtual hard disks.  The problem is that a virtual machine may have 1 virtual hard disk, or dozens of virtual hard disks, and PowerShell does not provide a simple way to handle an arbitrarily changing set of parameters.  We spent a lot of time trying to figure out how to handle this – and ended up with a solution where we use an array of hash tables to specify the new location for the virtual hard disks.

Let me explain in detail:

Imagine that you had a virtual machine with three virtual hard disks that you wanted to move to different locations.  The virtual hard disk names, locations and new locations were as follows:


VHDX name Current location New Location
Boot.vhdx C:\TheWrongPlace D:\VHDs
Data1.vhdx C:\TheWrongPlace E:\VHDs
Data2.vhdx C:\TheWrongPlace F:\VHDs

To move these files you would need to construct a hash table for each one.  Like this:

@{“SourceFilePath” = “C:\TheWrongPlace\Boot.vhdx”; “DestinationFilePath” = “D:\VHDs\Boot.vhdx”}
@{“SourceFilePath” = “C:\TheWrongPlace\Data1.vhdx”; “DestinationFilePath” = “E:\VHDs\Data1.vhdx”}
@{“SourceFilePath” = “C:\TheWrongPlace\Data2.vhdx”; “DestinationFilePath” = “F:\VHDs\Data2.vhdx”}

You would then need to put all of these hash tables into an array and pass them to Move-VMStorage on the VHDs parameter.  Which would look like this:

Move-VMStorage –VMName “Test” –VHDs @(@{“SourceFilePath” = “C:\TheWrongPlace\Boot.vhdx”; “DestinationFilePath” = ���D:\VHDs\Boot.vhdx”}, @{“SourceFilePath” = “C:\TheWrongPlace\Data1.vhdx”; “DestinationFilePath” = “E:\VHDs\Data1.vhdx”}, @{“SourceFilePath” = “C:\TheWrongPlace\Data2.vhdx”; “DestinationFilePath” = “F:\VHDs\Data2.vhdx”})

Pay special attention to the following details:

  • The array uses round brackets “()” while the hash table uses curly brackets “{}”
  • The array is comma separated, while the hash table is semicolon delineated

With all of that in mind – here is the PowerShell command to perform the same operation that I showed you yesterday in the graphical user interface:

Move-VMStorage "Windows Server 8 - Spaces test 1" -SnapshotFilePath "C:\Foo" -VHDs @(@{"SourceFilePath" = "D:\Hyper-V\Virtual Hard Disks\3tb - 1.vhdx"; "DestinationFilePath" = C:\Foo\3tb - 1.vhdx"}, @{"SourceFilePath" = "D:\Hyper-V\Virtual Hard Disks\3tb - 2.vhdx"; "DestinationFilePath" = C:\Foo\3tb - 2.vhdx"}) 

Specifically – it moves the snapshot location and two of the virtual hard disks for the virtual machine “Windows Server 8 – Spaces test 1”.