Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
}
}
}
}
@yusufozturk

This comment has been minimized.

Copy link

commented Jun 18, 2019

Thanks for the update @basroovers 👍 💯 🥇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.