4 Replies Latest reply on Aug 31, 2015 1:30 PM by Chrisxxxx

    Storage vMotion using PowerCLI

    piercj2 Enthusiast



      I need to Storage vMotion approx 300 VM's from an old SAN to a new SAN.

      The new SAN has 10 4TB LUNs provisioned, these are called New_SAN_1, New_SAN_2, etc...


      What I would like to do is the following

      1. provide a .txt tile with a list of VM's to be migrated
      2. for each VM in this list
        • Calculate the Used Space (GB)
        • Randomly, select one of the 10 new LUNs
        • Migrate the VM to the LUN only if free space equal to the amount of space used by the VM plus 25%
          E.G. if the VM is using 100GB, only svMotion it if the randomly selected LUN has 125GB free


      Here's what i've come up with


      $VMs = get-vm (get-content c:\temp\VmList.txt)

      foreach ($v in $VMs) {

      $VmUsedSpace = $_.UsedSpaceGB

          $random = Get-Random -InputObject 1,2,3,4,5,6,7,8,9,10

          $random_New_Datastore  = get-datastore | where-object {$_.name -match “New_SAN_$random”}

          if ($random_New_Datastore.FreeSpaceGB -gt ($VmUsedSpace * 1.25)) {

              Move-VM -VM $v -Datastore $random_New_Datastore -RunAsync -Confirm:$false




      If the randomly selected LUN, does not have enough free space,

      • how can I cleanly select a different LUN
      • verify that it has enough free space
      • svMotion the VM



        • 1. Re: Storage vMotion using PowerCLI
          chrislcrain Novice

          You can use Get-random against the entire get-datastore object in this case. Here I've filtered out datastores which do not meet your size requirement and piped them to get-random to randomly select one of them. I also changed your vm property to provisionedspacegb instead of usedspacegb and removed the -runasync parameter as the sizes of the datastores will be changing during this process. Feel free to add those back in. The way the script is here I think it'll throw an error if it can't find a datastore which meets your criteria.


          $VMs = get-vm (get-content c:\temp\VmList.txt)
          foreach ($v in $VMs) {
              $random_new_datastore = Get-Datastore | ? freespacegb -GE ($v.provisionedspaceGB*1.25) | Get-Random -Count 1
              Move-VM -VM $v -Datastore $random_New_Datastore -Confirm:$false}


          Let me know how this works out.

          • 2. Re: Storage vMotion using PowerCLI
            Craig Baltzer Expert

            Which edition of vSphere are you licensed for? If you're licensed for it you could put the new LUNs in a SDRS cluster, set your threshold limits on the datastore cluster (i.e. 75% occupancy) then just specify the name of the cluster in the Move-VM command (-Datastore takes either a datastore or a datastore cluster) and SDRS will look after putting things in the right places and rebalance as necessary. No need to fuss with finding datastores, managing space, etc. in the PowerCLI script...

            • 3. Re: Storage vMotion using PowerCLI
              piercej2 Novice

              Thanks chrislcrain,


              That worked perfectly.

              I needed to make a slight modification to your script as there are lots of Datastores/LUNs presented and I needed to specifically select from the LUNs presented on the new SAN.


              Below is the working script


              $VMs = get-vm (Get-Content $filelocation)

              $new_vnx = Get-Datastore | where {$_.name -match “new_san_vnx"}


              foreach ($v in $VMs) {

                  $random_new_san_lun = Get-Datastore -Name $new_vnx.name | where {$_.freespacegb -GE ($v.provisionedspaceGB*1.25)} | Get-Random -Count 1

                  Write-Host "Storage vMotion of $v to $random_new_san_lun is beginning"

                  Move-VM -VM $v -Datastore $random_new-san_lun -Confirm:$false


              • 4. Re: Storage vMotion using PowerCLI
                Chrisxxxx Novice

                  This is what I use.  We have a pretty large environment so sometimes we're deploying a new QA enviroment of 20 or 40 VMs, or we're migrating 138tb from one array to another.


                  I do call another function Get-mDataStoreList.ps1 to retrieve the list of eligible datastores.  It'll return datastores the hosts can see that aren't in maintenance mode, and minus some special purpose datastores that won't hold VMs, like an NFS share for templates.







                #Parameter- Name of the VMware cluster the VM will be assigned to

                function Get-DatastoreMostFree ($Cluster, [switch] $Second)




                Return the datastore in the cluster with the most unprovisioned disk space.  This takes thin provisioning into account.



                Queries all the datastores in the cluster and returns the datastore with the most free disk space.  Used in conjunction with a mass cloning of virtual machines script. (Clone_Template_fromCSV.ps1)



                1- You will need to modify the 2nd to last line's with criteria for your own environment.  I'm filtering out anything that's designed to hold guest VMs, like any datastores hosting ISO files and template VMs.

                2- Error and constraint checking need to be added.  If you try to put a VM a full LUN it will fail.





                Get-DatastoreMostFree.ps1 clustername



                # Prep

                Set-Variable -Name ScriptDir -Value "\\servername\folder" -Scope Local

                . $ScriptDir\Get-mDataStoreList.ps1


                # Amount of free space on a LUN for it to be an eligible target

                $LUNSizeFreeMB = 300*1024


                $DSTs = Get-mDataStoreList $Cluster


                if (!$Second) {

                  $DST =  $DSTs | Where-Object { $_.FreeSpaceMB -gt $LUNSizeFreeMB } | Select Name,@{n="Provisioned";e={($_.extensiondata.summary.capacity - $_.extensiondata.summary.freespace + $_.extensiondata.summary.Uncommitted)}} | Sort Provisioned -Descending | Select-Object -Last 1 -Property Name }

                else {

                  $DST =  $DSTs | Where-Object { $_.FreeSpaceMB -gt $LUNSizeFreeMB } | Select Name,@{n="Provisioned";e={($_.extensiondata.summary.capacity - $_.extensiondata.summary.freespace + $_.extensiondata.summary.Uncommitted)}} | Sort Provisioned -Descending | Select-Object -Last 2 | Select-Object -First 1 -Property Name }


                write-output $dst