Storage vMotions based on CSV file
This script reads a CSV file and executes storage vmotions based on the input. The number of storage vmotions can be throttled and is by default set to maximum 6 concurrent vMotions. If the VM is already on the correct location it will not execute a storage vmotion for that vm.
This is still work in progress. The parameters to accept a different CSV file, log file location and number of storage vmotions other than the default have not been added yet.
This script has been built and tested on a VMware vSphere 5.5 environment.
I updated the script to accept all parameters as shown in the description and I also added a Dry Run parameter. The Dry Run parameter will do a dry run escaping the vMotion sequence, so all actions will be logged. Combining the Debug and DryRun parameter will show everything on the console without executing.
The default location for the CSV file is C:\Scripts\Storage vMotion\Sources. The script will log to the C:\Scripts\Storage vMotion\Logs location. If the directory doesn't exist, it will be created.
1<#
2 .Synopsis
3 Moves VMs to the correct datastore based on a csv file.
4
5 .Description
6 Moves VMs to the correct datastore based on a csv file.
7
8 .Author
9 Harold Preyers
10
11 .Parameter DryRun
12 The DryRun parameter will create the log file without vMotion-ing the virtual machines to the correct datastore.
13
14 .Parameter Debug
15 The Debug parameter shows output to the screen. This will not prevent to start the vMotions.
16
17 .Parameter CSV_Dir
18 Supply your own CSV file location.
19
20 .Parameter CSV_FileName
21 Supply your own CSV file location.
22
23 .Parameter Log_Dir
24 Supply your own LogFile location.
25
26 .Parameter Log_FileName
27 Supply your own LogFile location. Don't add a file extension, the script will construct a filename based on the time of launch and add a .log extension
28
29 .Example
30 # Start storage vmotions without debug output based on the default CSV (C:\Scripts\Storage vMotion\Sources) and log file (C:\Scripts\Storage vMotion\Logs) location
31 # Name,Datastore
32 # VM1,DS1
33 # VM2,DS2
34 ./svMotion_CSV.ps1
35
36 .Example
37 # Start storage vmotions with debug output based on the default CSV (C:\Scripts\Storage vMotion\Sources) and log file (C:\Scripts\Storage vMotion\Logs) location
38 # Name,Datastore
39 # VM1,DS1
40 # VM2,DS2
41 ./svMotion_CSV.ps1 -Debug $true
42
43 .Example
44 # Start storage vmotions with debug output based on custom CSV and log file location
45 # The CSV file should have the following lay-out
46 # Name,Datastore
47 # VM1,DS1
48 # VM2,DS2
49 ./svMotion_CSV -Debug $true -Log_Dir "C:\Scripts\Storage vMotion\Logs" -Log_FileName svMotion_log -CSV_Dir "C:\Scripts\Storage vMotion\Sources" -CSV_File svMotion.csv
50#>
51
52# Accept parameters
53[cmdletBinding()]
54 Param (
55 [Bool]$Debug = $false # Write output to console
56 [Bool]$DryRun = $false # Write logfile without vMotion
57 [string]$CSV_Dir, # CSV Directory location
58 [string]$CSV_FileName, # CSV Filename
59 [string]$Log_Dir, # Log Directory location
60 [string]$Log_FileName, # Log Filename
61 )
62
63# Variables
64$Num_vMotions = 6
65$CSV_Dir = "C:\Scripts\Storage vMotion\Sources"
66$CSV_FileName = "vmdatastore.csv"
67$CSV_File = "$CSV_Dir\$CSV_FileName"
68
69# Logging
70$Log_Dir="C:\Scripts\Storage vMotion\Logs"
71$Log_FileName="svMotion_log"
72$Log_Breaker="##########################"
73$global:File=""
74
75# Create the necessary directories if necessary
76If(!(Test-Path -Path $Log_Dir )){
77 New-Item -ItemType directory -Path $Log_Dir
78}
79
80Function Initialize {
81 # Logging parameters
82 $Date = (get-date).tostring("yyyyMMdd_HHmmss")
83 $global:File = $LogDir + "\" + $Log_FileName + "_" + $Date + ".log"
84 If ($Debug) {Write-Host "The filename is: $global:File"}
85
86 # Initialize log
87 $Log_Breaker | Out-File "$global:File" -Append
88 " LogFile: $global:File" | Out-File "$global:File" -Append
89 " LogDate: $Date" | Out-File "$global:File" -Append
90 " CSV File: $CSV_File" | Out-File "$global:File" -Append
91 $Log_Breaker | Out-File "$global:File" -Append
92 Add-Content -Path $global:File -Value "`n"
93}
94
95# Import CSV
96$CSV = Import-csv "$CSV_File"
97
98Initialize
99
100$Date = (get-date).ToString("yyyy-MM-dd HH:mm:ss.fff")
101
102# Do for each entry in CSV file
103Foreach ($VM in $CSV) {
104 Try {
105 # Does the virtual machine exist
106 Get-VM $VM.Name -ErrorAction Stop | Out-Null
107
108 # What is the current Datastore of the virtual machine
109 $CurrentDS=(get-vm $VM.Name | Get-Datastore).Name
110 If ($CurrentDS -ne $VM.Datastore) {
111 # Log & Debug
112 $Message = "Starting for VM " + $VM.Name + " to datastore " + $VM.Datastore
113 If ($Debug) {Write-Host "$Message" -Foregroundcolor darkyellow}
114 $Message | Out-File "$global:File" -Append
115
116 If ($DryRun -eq $false) {
117 # Determing amount of vMotions currently executing
118 $num_tasks = (get-task |where {$_.name -eq "RelocateVM_task"} | where {$_.state -eq "running"})
119 Do {
120 $num_tasks = (get-task |where {$_.name -eq "RelocateVM_task"} | where {$_.state -eq "running"})
121 } While ($num_tasks.Count -eq $Num_vMotions)
122 Get-VM $VM.Name | Move-VM -Datastore $VM.DS -RunAsync
123 }
124 }
125 # virtual machine was found on the correct datastore
126 $Message = $VM.Name + " is already on datastore " + $VM.Datastore
127 If ($Debug) {Write-Host "$Message" -Foregroundcolor darkgreen}
128 $Message | Out-File "$global:File" -Append
129 }
130 Catch {
131 $Message = $VM.Name + " was not found."
132 If ($Debug) {Write-Host "$Message" -Foregroundcolor red}
133 $Message | Out-File "$global:File" -Append
134 }
135}