Menu
vChamp
  • About
  • Community
  • VCF Suite
    • VCF Automation
    • VCF Operations
    • VCF Operations – Log Management
    • VCF Automation Orchestrator
  • Scripts
  • Tags
  • vSphere
vChamp

PowerCLI: Storage vMotion VMs from File

Posted on September 14, 2023April 21, 2025 by Don Horrox

Estimated reading time: 8 minutes

I recall several occasions which called for the migration of a substantial count of virtual machines across datastores. Such scenarios typically arise during intrusive maintenance or lifecycle upgrades of storage arrays. Often times, this migration task can implicate migration of hundreds or even more virtual machines, creating an overwhelming sense of repetitive and labor-intensive work. Fortunately, this is precisely where PowerCLI comes to the rescue.

Our PowerCLI script empowers us to streamline this process by defining a targeted list of virtual machines along with their respective destination datastores, all through a user-friendly CSV file. Once this CSV file is populated with the necessary details and saved, executing the PowerCLI script initiates the migration process. The script systematically iterates through each specified VM until it successfully completes the migration for the entire list.

Before you begin

This article assumes you already have PowerCLI installed and the user credentials you intend to supply have adequate permissions to the target vCenter server.

Prepare the Environment

  1. Download the PUT_VM_vMotion_Storage_from_File.ps1 script and the sample vm_vmotion_storage_list.csv CSV file from my GitHub repository and save to a local directory of your choice.
  2. Launch a PowerShell session. Depending on user permissions, you may need to launch PowerShell with elevation (as Administrator).
  3. Open the sample CSV file provided and populate a list of your own virtual machines in Column A and their destination datastores in Column B. Once complete, save and exit the CSV file.

Execute Script

  1. Change working directories to the directory containing the script (i.e., C:\Scripts)
    cd C:\Scripts
  2. Execute the script by typing or pasting the below line within the PowerShell window.
    .\PUT_VM_vMotion_Storage_from_File.ps1

    Note: You can use autocomplete to populate the name of the file if you type the first few letters. Try typing “.\PUT” without quotes and press the Tab key to give it a try!
  3. The “Main Menu” is presented, which prompts the user to specify the Fully Qualified Domain Name (FQDN) of the vCenter server. Type the vCenter FQDN, then press the Enter key.
  4. The next prompt asks for the user’s credentials for authentication to the vCenter server. Type your credentials, then press the Enter key.


    Note: User accounts which are child objects of the same SSO Domain as the vCenter server are not required to specify a prefix or suffix to the User ID. However, accounts which are child objects of other SSO domains will be required to specify one or the other, depending on the LDAP configuration. For example, let us assume that the vCenter server’s default SSO Domain is vcenter.local. If the user account is a child object of the vcenter.local SSO Domain, then you would simply enter the user ID (“jdoe” for example) rather than the user ID and suffix (“[email protected]” for example). In similar fashion, if the vCenter server’s default SSO domain is vcenter.local but also has LDAP configured for XYZ Corp’s SSO Domain (i.e., “xyzcorp.com”), a user account which is a child object of the XYZ Corp domain would either specify a NETBIOS domain prefix (i.e., “xyz”) before the user ID, or the domain suffix (i.e., “@xyzcorp.com”) after the user ID. The prefix/suffix may vary based on the LDAP and NETBIOS configuration in your environment. The point being, you would only specify the SSO Domain prefix or suffix if the user account belongs to a SSO Domain other than what is selected as the default for the vCenter server.
  5. The vMotion commands will now execute, which can take a while depending on several factors such as resource availability on the vCenter server and storage array(s), number of virtual machines, etc.

  6. Upon completion, the user session between PowerShell/PowerCLI and the target vCenter server will be automatically disconnected at the end of the script.

Behind the Scenes

How did the script obtain this information and format accordingly? We will investigate a bit more closely below:

Lines 1-18
This is your average introductory comment block. Although useful when referencing the code directly, there is no functional value to this block.

 <#
.SYNOPSIS
VMware VM Storage vMotion from File
Script is used to migrate a scoped list of virtual machines to a destination datastore according to a user-provided CSV file.

Author: Don Horrox (vChamp - https://www.vchamp.net)
Version: 1.0

.DESCRIPTION
 This script must be run on a system with either the VMware PowerCli snap-in or module and an
 account that has appropriate rights to connect to vCenter using PowerCLI.
 To install the PowerCLI module run
 Install-Module -Name VMware.PowerCLI
 Install-Module -Name VMware.PowerCLI –Scope CurrentUser

.NOTES
N/A
#>
PowerShell

Lines 20-24
We begin by configuring a PowerShell function for timekeeping. This will help record the date and time for each line of our log file. We then set the location where the log should be saved, which is the same directory as the script in this case.

## Prepare Logging
function Get-TimeStamp {
    return "[{0:MM/dd/yy}  {0:HH:mm:ss}]" -f (Get-Date)
}
$outputLog = ".\put_vm_vmotion_storage_from_file.log"
PowerShell

Lines 26-51
The first line is written to our log file to indicate that a new session has started. We then configure the appearance and corresponding values for the “Main Menu” which is presented to the user.

## Initialize Script
Write-Output "$(Get-Timestamp) WARN: +++++++++++++++ Starting new session +++++++++++++++" | Out-File $outputLog -Append
Write-Output "$(Get-Timestamp) Initializing script." | Out-File $outputLog -Append

## Set Target(s)
Write-Output "$(Get-Timestamp) Importing CSV." | Out-File $outputLog -Append
$ImportFile = ".\vm_vmotion_storage_list.csv"
$VMList = Import-Csv $ImportFile
Write-Output "$(Get-Timestamp) Source CSV is $ImportFile." | Out-File $outputLog -Append

## Welcome message
Write-Host "############################################################################" -ForegroundColor Cyan
Write-Host "                  VMware VM Storage vMotion from File" -ForegroundColor Cyan
Write-Host "############################################################################" -ForegroundColor Cyan
Write-Host "`n"
Write-Host "Version: 1.0"
Write-Host "`n"
Write-Host "Objective:" -ForegroundColor Yellow
Write-Host "Initiate a storage vMotion of scoped VMs provided by a CSV file."
Write-Host "`n"
Write-Host "Requirements:" -ForegroundColor Yellow
Write-Host "  * CSV file named 'vm_vmotion_storage_list.csv' located in the working directory."
Write-Host "  * Cell A1 value should equal 'VMName' with VM Names on separate cells below."
Write-Host "  * Cell B1 value should equal 'Datastore' with the name of each respective datastore on separate cells below."
Write-Host "`n"
Write-Host "`n"
PowerShell

Lines 53-69
Fields are provided for the user to specify the vCenter server FQDN, User ID, and Password. Once provided, the script will attempt to authenticate with the vCenter server.

## Connect to the vCenter
Write-Host "######################################" -ForegroundColor Yellow
Write-Host "        vCenter Authentication" -ForegroundColor Yellow
Write-Host "######################################" -ForegroundColor Yellow
Write-Host "`n"
Write-Host "Specify the FQDN of your vCenter Server below:" -ForegroundColor Yellow
Write-Output "$(Get-Timestamp) Waiting for user input - VCSA." | Out-File $outputLog -Append
$VCServer = Read-Host "Enter your vCenter FQDN"
Write-Output "$(Get-Timestamp) Waiting for user credentials." | Out-File $outputLog -Append
Write-Host "`n"
Write-Host "Please enter your credentials below:" -ForegroundColor Yellow
$Username = Read-Host "Enter your username"
$Password = Read-Host "Enter password" -AsSecureString
Write-Host "`n"
Write-Host "Authentication in-progress. Please wait." -ForegroundColor Cyan
Write-Output "$(Get-Timestamp) Connecting to $VCServer as user $Username..." | Out-File $outputLog -Append
$null = Connect-VIServer $VCServer <#-AllLinked#> -User $username -Password ([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)))
PowerShell

Lines 71-99
The vMotion command is executed on the vCenter server for each VM on specified in the CSV file.

## Migrate VMs
Clear-Host
Write-Output "$(Get-Timestamp) Beginning storage vMotion loop." | Out-File $outputLog -Append
foreach ($item in $vmlist){
    $server = $item.vmname
    $destdatastore = $item.datastore
    # Check Current Datastore
    Write-Output "$(Get-Timestamp) Checking current storage location for $server." | Out-File $outputLog -Append
    $sourcedatastore = (Get-Datastore -RelatedObject $server).Name
    Write-Output "$(Get-Timestamp) Current datastore is $sourcedatastore." | Out-File $outputLog -Append
    # Logic to handle outcome of datastore query
    If($destdatastore -eq $sourcedatastore)
    # If VM is already located on destination datastore, do nothing
    {Write-Output "$(Get-Timestamp) VM $server is already located on datastore $sourcedatastore and user requested $destinationdatastore. Skipping." | Out-File $outputLog -Append
    Write-Host "$server is already located on datastore $sourcedatastore. Skipping." -ForegroundColor DarkGreen}
    # If VM is not located on destination datastore, perform storage vMotion
    else{
        Write-Output "$(Get-Timestamp) Sending storage vMotion command for VM $server." | Out-File $outputLog -Append
        Write-Host "Sending storage vMotion command for VM $server. Destination datastore is $destinationdatastore."
        try {
            Move-VM -VM $server -Datastore $destdatastore -VMotionPriority High -ErrorAction Stop | Out-Null
        }
        catch {
            Write-Output "$(Get-Timestamp) ERROR: Failed to send migration command to $server. Check vCenter logs for details." | Out-File $outputLog -Append
            Write-Host "Failed to send migration command to $server. Check vCenter logs for details." -ForegroundColor DarkRed
        }
        
    }
}
PowerShell

Lines 101-106
Upon completion, the script will disconnect the user session with the vCenter server.

## Disconnect from vCenter
Write-Host "`n"
Write-Output "$(Get-Timestamp) Disconnecting vCenter session." | Out-File $outputLog -Append
Write-Host "Disconnecting vCenter session." -ForegroundColor DarkGreen
Disconnect-VIServer -Server * -Force -Confirm:$false
Write-Host "All actions complete. Please close terminal window." -ForegroundColor White -BackgroundColor DarkGreen
PowerShell

Leave a Reply Cancel reply

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

Don Horrox

Virtualization professional and enthusiast.


VCP VCF 9 Architect Badge VCP VCF 2024 Badge VCP CMA 2024 Badge
vExpert Badge
vExpert VCF Subprogram Badge

Connect

  • GitHub
  • RSS Feed
  • LinkedIn
  • X

Recent Posts

  • VMware Explore 2025 – That’s a Wrap!September 8, 2025
  • VMware Explore 2025 – Presenting!July 26, 2025
  • Know before you go: Explore 2025 in Las VegasJuly 2, 2025
© 2023 - 2025 Don Horrox | All Rights Reserved