Как стать автором
Обновить

Скрипт для подсчета места, занимаемого виртуальными машинами Hyper-V

Время на прочтение3 мин
Количество просмотров9.3K
Недавно я обнаружил расхождение данных о занимаемом виртуальными машинами дисковом пространстве, отображаемых в консоли System Center Virtual Machine Manager с данными, полученными при помощи Get-SCVirtualMachine и решил выяснить, в чем дело. Данные о занимаемом дисковом пространстве я получал при помощи распространенного командлета Get-SCVirtualMachine. Для этого я использовал цикл, в котором перебирал все виртуальные машины и накапливал размер их дисков в переменной:

$totalhdd = 0
$vms =  Get-SCVirtualMachine  #| where {$_.Name -eq "VM Name"} # Для отладки 
foreach ($vm in $vms) {          
    $totalhdd += ($vm.VirtualHardDisks.Size -as [double]) / 1TB}  
}

Похожие конструкции многократно тиражируются на форумах technet и во всяких блогах, поэтому сомнений в их корректности у меня не возникало. После обнаружения расхождений я добавил в цикл вывод отладочной информации: $vm.VirtualHardDisks.Size для каждой ВМ и её имя. Вывод измененного скрипта показал, что у некоторых ВМ объём был равен 0. Я был уверен, что $vm.VirtualHardDisks.Size показывает сумму, но это оказалось не так — команда возвращала два числа (для двух vhd). Очевидно, powershell не смог поделить массив на 1TB, поэтому и отдавал 0:

PS D:\Scripts\IT_git> $vm.VirtualHardDisks.Size
3547332608
4194304

PS D:\Scripts\IT_git> ($vm.VirtualHardDisks.Size -as [double]) / 1TB
0

Даже не знаю в этом случае, сказать спасибо гибкости повершелла за то, что не ERROR, или сказать ему антиспасибо за подобную медвежью услугу. Очень много ошибок прощает.

Тогда я решил перебирать все диски циклом и изменил первоначальную конструкцию на чуть более сложную, но при этом и более корректную:

foreach ($vm in $vms) {   
    $vhds = $vm.VirtualHardDisks    
    foreach ($vhd in $vhds) { $totalhdd += ($vhd.Size -as [double]) / 1TB}  
}

Отлично! Теперь ВМ с двумя или более виртуальными дисками считались корректно, НО! Сумма по всем виртуалкам всё равно не совпадала, хоть и приблизилась к показаниям консоли.
Погонял свой скрипт и так, и эдак. Посмотрел, посравнивал и увидел, что по некоторым ВМ сумма совпадает до копейки, а по некоторым наблюдается значительное расхождение. Полез в свойства, а там… снапшоты! Их-то мы и не посчитали.
Далее опять гугл, опять сомнительные скрипты вплоть до очень экзотических методов с поиском файлов по маске.
Скрытый текст
Метод с поиском *avhdx, при этом, в корне неверный, так как в avhd пишутся текущие данные, а снапшот лежит себе в vhdx. Однако, его я встречал и у других авторов

Пришлось писать самому. Сначала я пробовал выбирать все диски при помощи Get-SCVirtualHardDisk не прибегая к перебору виртуальных машин, однако мне удалось перечислять лишь те диски, которые я получал при помощи $vm.VirtualHardDisks. Поэтому пришлось копнуть чуть глубже. У виртуальной машины есть свойство VMCheckpoints, в котором перечислены все контрольные точки. Из этого свойства можно получить, собственно, объект VMSnapshot (я так и не понял чем Snapshot отличается от Checkpoint в терминах SCVMM). У этого объекта также есть свойство VirtualDiskDrives, но у него почему-то нет свойства Size, поэтому пришлось вставить костыль: из VirtualDiskDrives мы берём свойство VirtualHardDiskID и с помощью этого ID делаем Get-SCVirtualHardDisk:

...
# Snapshots search
    foreach ($vmc in $vm.VMCheckpoints) {
        foreach ($vdd in $vmc.VirtualDiskDrives) {
            $vhd = Get-SCVirtualHardDisk -ID $vdd.VirtualHardDiskID
            $snapshotshdd += ($vhd.Size -as [double]) / 1TB 
            
        }
    }
...

После этого небольшое расхождение всё-таки осталось, и коллега подсказал мне посчитать также служебные файлы .bin и .vsv, в которых хранится служебная информация навроде дампа оперативной памяти. В очередной раз просматривая список доступных параметров виртуальной машины я наткнулся на… $vm.TotalSize. Кто бы мог подумать, что всю работу за меня уже сделали и нужно всего лишь просуммировать этот параметр для всех виртуальных машин!
Вот так через тернии, костыли и грабли я нашёл действительно красивое решение:

$totalsize = 0
$vms =  Get-SCVirtualMachine  #| where {$_.Name -eq "VM Name"} # Для отладки 
foreach ($vm in $vms) {          
    $totalsize += ($vm.TotalSize  -as [double]) / 1TB  
}

Было так смешно, что решил не удалять из скрипта данные о снапшотах, полученные таким трудом.
Залил вот сюда gallery.technet.microsoft.com/scriptcenter/Script-to-calculate-the-36a9314f
Математики шутят

Теги:
Хабы:
Всего голосов 14: ↑11 и ↓3+8
Комментарии3

Публикации

Истории

Работа

DevOps инженер
38 вакансий

Ближайшие события

22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань