justinsmith
Enthusiast
Enthusiast

PowerCLI script to svMotion VM's based on a list of VM's

Jump to solution

Im looking to svMotion VM's based on a spreadsheet or txt file (either will work for me) from one datastore to another. I've found simple ones that do it, but nothing that will import a csv file or txt file and svmotion those VM's.

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership

Try changing line 37 (in the original function) into this

$NumvMotionTasks = (Get-Task | ? { ($_.PercentComplete -ne 100) -and ($_.Description -match 'Relocate')} | Measure-Object).Count


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
46 Replies
brentcochran1
Contributor
Contributor

Do you want to put your destination datastore in the CSV?  If so, you'd have something like this:

csv file format:

vmnamedestDS
myVM1datastore1
myVM2datastore2
myVM3datastore3

$filepath = "D:\PathtoCSV\filename.csv

$csvobj = import-csv $filepath

foreach ($row in $csvobj) {

     $vmobj = get-vm $row.vmname

     $ds = get-datastore $row.destds

     $vmobj | move-vm -datastore $ds -confirm:$false

     }

Not very eloquent, but should get the job done.  Let me know how it works out!

BC

justinsmith
Enthusiast
Enthusiast

Wouldnt be an issue.

So you're saying I would add the VM's I want to migrate to the "vmname" column, then the DS that I want it to go to in the "DESTDS"?

If I have 30-40 VMs in the csv file.....Is there a way to have say, 3 or 4 run at a time and queue up the ones behind it? Almost like a job.....

0 Kudos
Zsoldier
Expert
Expert

I might do it like this:

$VMsToMove = Get-Datastore "NameofDataStoreContainingTargetVMs" | Get-VM

$TargetDatastore = GetDatastore NameofTargetDatastore

Foreach ($VM in $VMsToMove)

{

Move-VM -VM $VM -Destination $TargetDatastore -Confirm:$False

}

Unless of course you have a particular need to make a CSV to import from.

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
0 Kudos
Zsoldier
Expert
Expert

Or, if it's an option, make a datastore cluster and place the datastore you want to move from into maintenance mode.

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
0 Kudos
justinsmith
Enthusiast
Enthusiast

Yeah, I want to queue up basically 30-40 VM's so having them in a list would work better, since I dont want to evacuate an entire DS.

0 Kudos
justinsmith
Enthusiast
Enthusiast

Not an option, we have some VM's that have RDM's attached and I want to svMotion those VM's separately.

0 Kudos
Zsoldier
Expert
Expert

So then you can use Brent's suggestion.  Just add the -runasync switch to make it run like a queued job.  Like so:

$filepath = "D:\PathtoCSV\filename.csv

$csvobj = import-csv $filepath

foreach ($row in $csvobj) {

     $vmobj = get-vm $row.vmname

     $ds = get-datastore $row.destds

     $vmobj | move-vm -datastore $ds -runasync -confirm:$false

     }

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
0 Kudos
justinsmith
Enthusiast
Enthusiast

Does that only do 1 at a time? is there a value I can set against the -runasync command to run say 3 or 4 at the same time and have it kick off the next in the list when one's done?

0 Kudos
Zsoldier
Expert
Expert

The -runasync switch should just send the command and not monitor it's progress allowing the foreach loop to keep going even if the initial storage vmotion didn't start.

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
0 Kudos
justinsmith
Enthusiast
Enthusiast

Ah

Is there a way to queue up 3 or 4 at a time based on a list of 30 or 40?

0 Kudos
Zsoldier
Expert
Expert

You could if you wanted to, but vCenter will normally throttle itself.  So you could have all 50 queued up and only a subset of those would actually be active jobs.

One method would be to introduce an arbitrary count and sleep method.  Or another more accurate, but would require a bit more coding would be to look @ the tasks and only start another job if the active task count is less than 4 or 5.

Here is the first method as an example:

$filepath = "D:\PathtoCSV\filename.csv

$csvobj = import-csv $filepath

$Count = 4

foreach ($row in $csvobj) {

     $Count --

     $vmobj = get-vm $row.vmname

     $ds = get-datastore $row.destds

     $vmobj | move-vm -datastore $ds -runasync -confirm:$false

     If ($Count -lt 0){Sleep 1500; $Count = 4}

     }

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
justinsmith
Enthusiast
Enthusiast

Id feel more comfortable with a script throttling it as apposed to what vCenter can handle. We have almost 4k VM's running and I wouldnt want it to try 30 because it thinks it can and then choke. Im ok with it doing 3-4 at a time though.

0 Kudos
Zsoldier
Expert
Expert

I have 3500 VM's in my environment.  they are just job queues.  I migrated 60 VM's from one datastore to another in the middle of the day using Storage DRS.  It did exactly that, moved I think 8 at a time, while the rest of the jobs were just queued.  The next one would continue when one finished.

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
0 Kudos
justinsmith
Enthusiast
Enthusiast

We're not running storage DRS, but Im familiar with both.

Like I said, I'd feel more comfortable scheduling or queuing up a set number before running it. Thanks for the helpful info though.

0 Kudos
LucD
Leadership
Leadership

Have a look at VMware sVmotion throttle


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

That might do it LucD, I just didnt want to throttle vCenter's resources with 40+ svMotions and not be able to do any other work until those are done. How would I integrate this code with the one below?

$filepath = "D:\PathtoCSV\filename.csv

$csvobj = import-csv $filepath

foreach ($row in $csvobj) {

     $vmobj = get-vm $row.vmname

     $ds = get-datastore $row.destds

     $vmobj | move-vm -datastore $ds -confirm:$false

     }

0 Kudos
Zsoldier
Expert
Expert

Like this:

<#

  .SYNOPSIS

  Will enter a wait/loop if there are running vMotion or svMotion tasks.

  .DESCRIPTION

  Checks the tasks and counts the number running vMotion or svMotion tasks.

  If the number of active tasks is greater than the specified limit

  then the function sleeps and checks again. The intended is as a throttle

  in large (s)vMotion loops to prevent overloading the environment.  Is

  especially useful in throttling a script while an unrelated event happens,

  such as putting a host or datastore into maintenance mode.

  .PARAMETER vMotionLimit

  The active tasks to test for.  If the number of active tasks is less than

  this the function will exit.  The default is 1, and must be an integer.

  .PARAMETER DelayMinutes

  How long to wait before checking the active tasks again.  The default

  is 1, and must be an integer.

  .EXAMPLE

  Wait-mTaskvMotions -Verbose

  .EXAMPLE

  Wait-mTaskvMotions -vMotionLimit 4

  .EXAMPLE

  Wait-mTaskvMotions -vMotionLimit 2 -DelayMinutes 3 -Verbose

  .NOTES

  Using -Verbose will output standard script started and finished messages,

  and how long the function will sleep before it checks the active tasks again.

  .LINK

  http://mongit201.be.monster.com/chrism/virtech/blob/master/Repo/Wait-mTaskvMotions.ps1

#>

function Wait-mTaskvMotions {

[CmdletBinding()]

Param(

  [int] $vMotionLimit=1,

  [int] $DelayMinutes=5

)

$NumvMotionTasks = (Get-Task | ? { ($_.PercentComplete -ne 100) -and ( ($_.Description -like '*DRS*') -or ($_.Description -like '*vMotion*') )} | Measure-Object).Count

While ( $NumvMotionTasks -ge $vMotionLimit ) {

  Write-Verbose "$(Get-Date)- Waiting $($DelayMinutes) minute(s) before checking again."

  Start-Sleep ($DelayMinutes * 60)

  $NumvMotionTasks = (Get-Task | ? { ($_.PercentComplete -ne 100) -and ( ($_.Description -like '*DRS*') -or ($_.Description -like '*vMotion*') )} | Measure-Object).Count

}

Write-Verbose "$(Get-Date)- Proceeding."

} # end function

$filepath = "D:\PathtoCSV\filename.csv

$csvobj = import-csv $filepath

foreach ($row in $csvobj) {

     $vmobj = get-vm $row.vmname

     $ds = get-datastore $row.destds

     $vmobj | move-vm -datastore $ds -confirm:$false -runasync

     Wait-mTaskvMotions -vMotionLimit 4 # This will keep going through the foreach loop until 4 tasks are registered (vMotion or Storage vMotion), waits 5 minutes between checks.  Will only continue to process loop when vMotion tasks are less than 4.

     }

Chris Nakagaki (中垣浩一)
Blog: https://tech.zsoldier.com
Twitter: @zsoldier
justinsmith
Enthusiast
Enthusiast

Not sure what Im missing, but when I run it, it just opens the .csv file.

0 Kudos
justinsmith
Enthusiast
Enthusiast

I actually added connect-viserver VSERVERNAME to the script and it worked instead of doing it from the powercli prompt first.

Only downside is, its migrating all the VM's and not queuing any up. I was hoping it would just grab the first 4 in the csv file, process them, and when one is done it moves on to the next one.

pastedImage_0.png

0 Kudos