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 directory location.
19
20 .Parameter CSV_FileName
21 Supply your own CSV filename.
22
23 .Parameter Log_Dir
24 Supply your own LogFile directory location.
25
26 .Parameter Log_FileName
27 Supply your own LogFile filename. 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_FileName 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
66# Set defaults if not provided
67if (!$CSV_Dir) { $CSV_Dir = "C:\Scripts\Storage vMotion\Sources" }
68if (!$CSV_FileName) { $CSV_FileName = "vmdatastore.csv" }
69$CSV_File = "$CSV_Dir\$CSV_FileName"
70if (!$Log_Dir) { $Log_Dir = "C:\Scripts\Storage vMotion\Logs" }
71if (!$Log_FileName) { $Log_FileName = "svMotion_log" }
72
73$Log_Breaker = "##########################"
74$global:File = ""
75
76# Create the necessary directories if necessary
77If (!(Test-Path -Path $Log_Dir)) {
78 New-Item -ItemType directory -Path $Log_Dir
79}
80
81Function Initialize {
82 # Logging parameters
83 $Date = (get-date).tostring("yyyyMMdd_HHmmss")
84 $global:File = $Log_Dir + "\" + $Log_FileName + "_" + $Date + ".log"
85 If ($Debug) { Write-Host "The filename is: $global:File" }
86
87 # Initialize log
88 $Log_Breaker | Out-File "$global:File" -Append
89 " LogFile: $global:File" | Out-File "$global:File" -Append
90 " LogDate: $Date" | Out-File "$global:File" -Append
91 " CSV File: $CSV_File" | Out-File "$global:File" -Append
92 $Log_Breaker | Out-File "$global:File" -Append
93 Add-Content -Path $global:File -Value "`n"
94}
95
96# Import CSV
97$CSV = Import-csv "$CSV_File"
98
99Initialize
100
101$Date = (get-date).ToString("yyyy-MM-dd HH:mm:ss.fff")
102
103# Do for each entry in CSV file
104Foreach ($VM in $CSV) {
105 Try {
106 # Does the virtual machine exist
107 Get-VM $VM.Name -ErrorAction Stop | Out-Null
108
109 # What is the current Datastore of the virtual machine
110 $CurrentDS = (get-vm $VM.Name | Get-Datastore).Name
111 If ($CurrentDS -ne $VM.Datastore) {
112 # Log & Debug
113 $Message = "Starting for VM " + $VM.Name + " to datastore " + $VM.Datastore
114 If ($Debug) { Write-Host "$Message" -Foregroundcolor darkyellow }
115 $Message | Out-File "$global:File" -Append
116
117 If ($DryRun -eq $false) {
118 # Determining amount of vMotions currently executing
119 $num_tasks = (get-task | where {$_.name -eq "RelocateVM_task"} | where {$_.state -eq "running"})
120 While ($num_tasks.Count -ge $Num_vMotions) {
121 Start-Sleep -Seconds 5
122 $num_tasks = (get-task | where {$_.name -eq "RelocateVM_task"} | where {$_.state -eq "running"})
123 }
124 Get-VM $VM.Name | Move-VM -Datastore $VM.Datastore -RunAsync
125 }
126 }
127 # virtual machine was found on the correct datastore
128 $Message = $VM.Name + " is already on datastore " + $VM.Datastore
129 If ($Debug) { Write-Host "$Message" -Foregroundcolor darkgreen }
130 $Message | Out-File "$global:File" -Append
131 }
132 Catch {
133 $Message = $VM.Name + " was not found."
134 If ($Debug) { Write-Host "$Message" -Foregroundcolor red }
135 $Message | Out-File "$global:File" -Append
136 }
137}