Moving VM Storage with PowerShell

Table of contents


We all like to think that when we built our Hyper-V server that we carefully mapped out storage requirements. But if you are an IT professional that has been around for any length of time you know that sometimes the best laid plans can quickly go out the window. In short, there may be any number of reasons why you might need to relocate storage associated with a Hyper-V virtual machine.

This might mean not only associated VHD or VHDX files but paging files and snapshots as well. If you only have a single virtual machine, I think it is just as easy to select the virtual machine in the Hyper-V manager and use the Move action which I’ve highlighted in Figure 1.

You can use the wizard to move files to new locations. But if you need to manage a migration for multiple machines, then PowerShell I think is the best choice. The latest version of Hyper-V includes a PowerShell cmdlet called Move-VMStorage. You can move VHD/VHDX files, snapshots and/or paging files. Here’s one of my virtual machines that has a single VHD file.

PS C:> get-vm "xp lab" | Select *path,@{N="HDD";E={$_.Harddrives.path}} | format-list

SmartPagingFilePath : C:ProgramDataMicrosoftWindowsHyper-V
Path : C:ProgramDataMicrosoftWindowsHyper-V
HDD : G:VHDsXPLab_75B1D704-F5B1-4AB7-B099-5EE7E41996FB.avhd

If I wanted to move all storage to a new folder, the necessary PowerShell command is pretty simple.

PS C:> Move-VMStorage -VMName "XP Lab" -DestinationStoragePath "E:VMStorage" -whatif

What if: Move-VMStorage will migrate the storage for virtual machine "XP Lab".

[optin-monster-shortcode id=”lwzgfpb294pntqna”]

As you can see it also support –Whatif. Depending on the size of the file or files this command might take some time to run so you have the option of running it as a PowerShell background job.

PS C:> Move-VMStorage -VMName "XP Lab" -DestinationStoragePath "E:VMStorage" -asjob

When finished there will be subfolders under E:VMStorage for the hard disk, snapshot and configuration files. It is also possible to move individual components.

PS C:> Move-VMStorage -VMName "JDHlab win7" -SnapshotFilePath E:VMStorageSnapshots

With this command I moved the snapshots from the virtual machine to a new location. I didn’t even have to create the Snapshots folder ahead of time. PowerShell did it for me. Think about this for a moment. If I can do this for a single virtual machine I can do it for 10 or 100. Let’s say I want to move snapshots for all of my Chicago virtual machines to this location. It is a one line command.

PS C:> get-vm chi* | Move-VMStorage -SnapshotFilePath E:VMStorageSnapshots -whatif

What if: Move-VMStorage will migrate the storage for virtual machine "CHI-Win8".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-FP02".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-FP01".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-DC04".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-DC02".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-DC01".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-Client02".
What if: Move-VMStorage will migrate the storage for virtual machine "CHI-APP01".

Once I’ve verified this is what I want I can run this as a PowerShell background job.

PS C:> get-vm chi* | Move-VMStorage -SnapshotFilePath E:VMStorageSnapshots –asjob

Each movement will be a separate job. There is one caveat, however. This command will be dependent on the server configuration for simultaneous storage migrations. When you run this command as a background job, each migration happens simultaneously which can lead to failures. You can either run the command without using –AsJob you’ll need to add some logic to your command or throttle your jobs accordingly. Or don’t use the –AsJob parameter at all!

Lastly, you can also elect to move virtual disk files, although this is a bit more cumbersome. The –VHDS path expects a specially constructed hash table using the format @{“SourceFilePath”=<source vhd file path>;”DestinationFilePath”=<destination vhd file path>}. The file path must include the file name and it must be the same in both the source and destination. Here’s an example that moves the VHD file from F:VHD to E:VMStorage.

PS C:> Move-VMStorage -VMName TechDays -Vhds @{"SourceFilePath"="F:VHDTechDays_C.vhdx";"DestinationFilePath"="E:VMStorageTechDays_C.vhdx"}

This presumes you know in advance the path and name of the VHD or VHDX file. It is possible with a little work to build this with some PowerShell code.

#requires -version 3.0

$destination = "E:VMStorage"

Get-VM "XP Lab" | select -expand HardDrives | foreach {
   #get file name
   $file = $_.Path | Split-Path -Leaf 
   #create the destination
   $destfile = Join-Path $destination $file

  #create the hash table putting the value in quotes

  $hash = @{
    "SourceFilePath" = "$($_.path)";
    "DestinationFilePath" = "$destfile"

  #pass the VM name to Move-VMStorage and move the VHD

  Write-Host "Moving $($hash.sourceFilePath) to $($hash.DestinationFilePath)" -foregroundcolor Cyan

  Move-VMStorage -VMName $_.VMName -vhds $hash


If the virtual machine had multiple hard drives they would all go to the same, new location in separate Move-VMStorage commands. It is possible to build an array of hash tables for all the drives and pass that as a value to –VHDS in a single Move-VMStorage command, but my approach works just fine since as far as I can tell only one file is copied at a time anyway.

Everything I’ve shown you can be mixed into the same expression. This means you could move snapshots to one location, hard drives to another and paging files to yet another. And to top it off, you can migrate while the virtual machine is running! Although, personally I would avoid migrations during periods of heavy use to avoid any unexpected problems.

Before you start migrating storage around you network, take some time to read the help and examples for Move-VMStorage and test your commands with non-production virtual machines. If you’d like to see more Hyper-V and PowerShell content, please let me know.


Altaro Hyper-V Backup
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

14 thoughts on "Moving VM Storage with PowerShell"

  • Saulo says:

    I like it very much, it could save a lot of time migrating all my VMStorages to my new NetApp Storage. But, I faced a problem that I just CAN’T find any answer an solution. I get this message when I try to migrate:
    Storage migration failed with erro ‘No such interface supported’ (0x80004002)

    I don’t know if you can help

    • The first question would be if you get the same error if you try to manually move storage for a single virtual machine using the GUI. Hard to tell if that error is on the Hyper-V side or NetApp. If that works, then we would need to know what PowerShell syntax you are using. Or you may be better off seeing if NetApp has a utility for migrating storage to its appliance.

      • Saulo says:

        I tried first using GUI, tried using Powershell because of this error.
        I already tried to migrate to another storage and get the same error. I really don’t know what to do now

        • At this point I think you need to research and troubleshoot this further. First do you get the error with any VM or just a few? If it works for some what are the differences between the VMs, especially when it comes to virtual disks. Second, is there any more information in the event log for this error?

          I would also be using a test virtual machine if you aren’t already.

          • I would also make sure the server is current on service packs, patches and updates.

            Finally for event logs make sure you drill down to the Applications and Services log. Under Microsoft you will see a number of Hyper-V logs. I would first check under Hyper-V-Worker/Admin and see if there is any more detail on the error.

            This could be a COM error or maybe even permissions.

  • Matt Browne says:

    Hi Jeffery,
    Great post, was very helpful as I needed to do this to move some VM files out of hours.
    Problem is using the commands in a scheduled task from another machine didn’t always work (using the -computername command)
    It said it completed but when you looked at the get-vm path command some files hadn’t moved or been updated.
    Did some playing and the only way I could get it to run from another 2012 R2 machine (our management box) was to use the invoke command.

    Have you come across that before?

  • John Tsang says:

    Hi there,

    This is a very helpful script, but when you migrate the VMs, is there a way for the script to create folders with the VM name on the destination host?


  • Tom Weustink says:

    On a Failover Cluster when I do this, the cmdlet will show all paths set to the new location, but the Failover Cluster manager will still show the Storage resource as the old one for de VM role.

    Only after I use the wizard to move everything to the same location (meaning the VHD’s will moved too) will it change the Storage resource location.

    Any idea why this is?

  • anas says:

    I want to know the state of Moving VM Storage with PowerShell ?
    because on the interface cluster i see just that the VM are locked when i move the storage.
    thank you.

Leave a comment or ask a question

Your email address will not be published. Required fields are marked *

Your email address will not be published.

Notify me of follow-up replies via email

Yes, I would like to receive new blog posts by email

What is the color of grass?

Please note: If you’re not already a member on the Dojo Forums you will create a new account and receive an activation email.