Last active
June 18, 2019 08:59
-
-
Save basroovers/2c1cdf9298c2a26ad633e008d95abf46 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Start-VMStorageOptimization { | |
<# | |
.SYNOPSIS | |
Function to optimize storage usage on CSV volumes by using Hyper-V Live Storage Migration. | |
.DESCRIPTION | |
If you use dynamic virtual disks with VMs, you may need to monitor free space on your CSV volumes. | |
This script moves virtual machines into different CSV volumes by using Hyper-V Live Storage Migration. | |
Note: run this as Administrator | |
.PARAMETER WhatIf | |
Display what would happen if you would run the function with given parameters. | |
.PARAMETER Confirm | |
Prompts for confirmation for each operation. Allow user to specify Yes/No to all option to stop prompting. | |
.EXAMPLE | |
Start-VMStorageOptimization | |
.EXAMPLE | |
Start-VMStorageOptimization -AllowPT | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
.NOTES | |
Author: Yusuf Ozturk (Small updates by Bas Roovers) | |
Website: http://www.yusufozturk.info | |
Email: ysfozy@gmail.com | |
Date created: 08-June-2014 | |
Last modified: 06-June-2019 | |
Version: 1.5 | |
.LINK | |
http://www.yusufozturk.info | |
http://twitter.com/yusufozturk | |
#> | |
[CmdletBinding(SupportsShouldProcess = $true)] | |
param ( | |
# Allow Passthrough Disks | |
[Parameter( | |
Mandatory = $false, | |
HelpMessage = 'Allow Passthrough Disks')] | |
[switch]$AllowPT = $false, | |
# Debug Mode | |
[Parameter( | |
Mandatory = $false, | |
HelpMessage = 'Debug Mode')] | |
[switch]$DebugMode = $false | |
) | |
# Enable Debug Mode | |
if ($DebugMode) | |
{ | |
$DebugPreference = "Continue" | |
} | |
else | |
{ | |
$ErrorActionPreference = "silentlycontinue" | |
} | |
# Informational Output | |
Write-Host " " | |
Write-Host "------------------------------------------" -ForegroundColor Green | |
Write-Host " Hyper-V Storage Optimization Script v1.4 " -ForegroundColor Green | |
Write-Host "------------------------------------------" -ForegroundColor Green | |
Write-Host " " | |
# Set Storage Status | |
$StorageStatus = $True | |
while ($StorageStatus -eq $True) | |
{ | |
# Get Worst CSV Volume | |
$WorstVolume = ((Get-ClusterSharedVolume | Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[-1]) | |
# Worst CSV Volume Information | |
$WorstVolumeName = $WorstVolume.Name | |
$WorstVolumeFreeSpace = $WorstVolume.FreeSpace | |
# Get Best CSV Volume | |
$BestVolume = ((Get-ClusterSharedVolume | Select -ExpandProperty SharedVolumeInfo | Select @{label="Name";expression={(($_.FriendlyVolumeName).Split("\"))[-1]}},@{label="FreeSpace";expression={($_ | Select -Expand Partition).FreeSpace}} | Sort FreeSpace -Descending)[0]) | |
# Best CSV Volume Information | |
$BestVolumeName = $BestVolume.Name | |
$BestVolumeFreeSpace = $BestVolume.FreeSpace | |
# Calculate Space Gap | |
[int64]$SpaceGap = [math]::round((([int64]$BestVolumeFreeSpace - [int64]$WorstVolumeFreeSpace) / 1GB), 0) | |
if ($SpaceGap -lt "100") | |
{ | |
# Informational Output | |
Write-Host "Storage is already optimized." -ForegroundColor Green | |
Write-Host " " | |
# Set Storage Status | |
$StorageStatus = $False | |
} | |
else | |
{ | |
# VM Reports | |
$VMReports = $Null | |
# Get Cluster Nodes | |
$ClusterNodes = Get-Cluster | Get-ClusterNode | |
# Informational Output | |
Write-Host "Measuring VMs to find the most suitable virtual machine for the migration.. Please wait.." -ForegroundColor Cyan | |
Write-Host " " | |
if ($AllowPT) | |
{ | |
# Enable Resource Metering | |
$EnableMetering = Get-VM -ComputerName $ClusterNodes | Where ConfigurationLocation -like "C:\ClusterStorage\$WorstVolumeName\*" | Enable-VMResourceMetering | |
# Get Resource Usage | |
$VMReports = Get-VM -ComputerName $ClusterNodes | Where ConfigurationLocation -like "C:\ClusterStorage\$WorstVolumeName\*" | Measure-VM | |
} | |
else | |
{ | |
# Enable Resource Metering | |
$EnableMetering = Get-VM -ComputerName $ClusterNodes | Where ConfigurationLocation -like "C:\ClusterStorage\$WorstVolumeName\*" | Where {(($_ | Select -Expand HardDrives).Path -notlike "Disk*") -and (($_ | Select -expand FibreChannelHostBusAdapters) -eq $Null)} | Enable-VMResourceMetering | |
# Get Resource Usage | |
$VMReports = Get-VM -ComputerName $ClusterNodes | Where ConfigurationLocation -like "C:\ClusterStorage\$WorstVolumeName\*" | Where {(($_ | Select -Expand HardDrives).Path -notlike "Disk*") -and (($_ | Select -expand FibreChannelHostBusAdapters) -eq $Null)} | Measure-VM | |
} | |
# Calculate Space Gap Average | |
[int64]$SpaceGapAverage = [math]::round(([int64]$SpaceGap / 2), 0) | |
[int64]$SpaceGapAverageMb = [int64]$SpaceGapAverage * 1024 | |
# Find Most Suitable VM | |
$BestVM = ($VMReports | Where TotalDisk -lt $SpaceGapAverageMb | Sort TotalDisk -Descending)[0] | |
if ($BestVM) | |
{ | |
# Best VM Information | |
$BestVMName = $BestVM.VMName | |
$BestVMHost = $BestVM.ComputerName | |
# Informational Output | |
Write-Host "Moving $BestVMName from $WorstVolumeName to $BestVolumeName by using Hyper-V Storage Live Migration.." -ForegroundColor Yellow | |
# Move Virtual Machine | |
Move-VMStorage -ComputerName "$BestVMHost" -VMName "$BestVMName" -DestinationStoragePath "C:\ClusterStorage\$BestVolumeName\$BestVMName" | |
# Informational Output | |
Write-Host "Done." -ForegroundColor Green | |
Write-Host " " | |
} | |
else | |
{ | |
# Informational Output | |
Write-Host "No suitable VM is found.. $WorstVolumeName contains VMs with large spaces." -ForegroundColor Red | |
Write-Host " " | |
# Set Storage Status | |
$StorageStatus = $False | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the update @basroovers 👍 💯 🥇