かつて山市良と呼ばれたおじさんのブログ

セイテクエンジニアのブログ  かつて山市良と呼ばれたおじさんのブログ  vol.249 棚卸から資産管理へ ― VM一覧の作成(1)|Hyper-V 健康診断

 

 

vol.249 棚卸から資産管理へ ― VM一覧の作成(1)|Hyper-V 健康診断

2026年11月09日配信
執筆者:山内 和朗

 これまでは、棚卸スクリプト(get-hypervhostinventory.ps1)を使用して、Get-ComputerInfo、Get-VMHost、Get-VMなどで取得した情報を1つのCLIXMLファイル(.xml)に棚卸データとして保存し、新旧棚卸データの差分を比較することで、Hyper-V環境の構成変更を確認してきました。

 今回からは少し視点を変え、VMを資産として管理するための一覧を作成していきます。VMの名前や配置先、CPU、メモリなどの情報を整理し、保有しているVMとその構成を一覧で把握できるようにすることが目的です。この一覧は、作成する都度、Hyper-V環境から必要な情報を取得する方針とします。まずは、VMの基本情報の一覧から作成し、一覧に含める項目をどんどん増やしていきたいと思います。

 

最初のシンプルなVM一覧スクリプト

 

 以下のGet-VMコマンドレットの実行結果を見てください。Get-VMは、VM(Microsoft.HyperV.PowerShell.VirtualMachine)オブジェクトのコレクションを返します。VMオブジェクトには非常に多くのプロパティ(Windows Server 2025のHyper-V環境では80*1)がありますが、出力を制御しない限り、Name、Stateなど既定の表示項目のみを出力します(画面1)。

*1 Get-VM |S elect -First 1 | Get-Member | Where {$_.MemberType -Like "*Proper*"}).Count

 

画面1 Get-VMは既定で表示するプロパティセットを使用して画面出力するが、既定で表示されないものを含めると80のプロパティを持つ

画面1 Get-VMは既定で表示するプロパティセットを使用して画面出力するが、既定で表示されないものを含めると80のプロパティを持つ

 次のスクリプトは、Get-VMが返すオブジェクトから、コレクションではない単純値で、資産管理のために重要と思われる項目だけをピックアップし、カスタムオブジェクト(PSCustomObject《System.Management.Automation.PSCustomObject》)のコレクションとして返します。カスタムオブジェクトにしているのは、必要な情報を名前付きのプロパティにまとめて扱え、参照、絞り込み、並べ替え、CSV出力(後で説明します)が簡単になるからです。また、この後するようにプロパティをどんどん追加できるという利点もあります。なお、今回は出力結果を資産管理のためのVM一覧の作成を目的としているため、State、CPUUsage、MemoryAssigned、Uptime、Statusといった動的に変化する値や状態はあえて除外しています。

$report = Get-VM | ForEach-Object {
    $vm = $_
    [pscustomobject]@{
        VMName           = $vm.Name
        VMId             = $vm.VMId
        Generation       = $vm.Generation
        ConfigPath       = $vm.ConfigurationLocation
        ## Firmware
        ## Security
        ## Processor
        vCPUs            = $vm.ProcessorCount
        ## Memory
        # MemoryAssigned = $vm.MemoryAssigned
        DynamicMemory    = $vm.DynamicMemoryEnabled
        RAMStartupGB     = [math]::Round($vm.MemoryStartup / 1GB, 1)
        RAMMinimumGB     = [math]::Round($vm.MemoryMinimum / 1GB, 1)  
        RAMMaximumGB     = [math]::Round($vm.MemoryMaximum / 1GB, 1)
        ## HardDrives
        ## DVDDrives
        ## NetoworkAdapters
        Version          = $vm.Version
        CreationTime     = $vm.CreationTime
        # isClustered    = $vm.isClustered
    }
}
$report

(プレーンテキストで表示/ダウンロード)

 

 $report には、各VMの情報をプロパティとその値にまとめたカスタムオブジェクトのコレクションが格納されます。そのまま一覧表示すると、コンソールのウィンドウ幅によっては列が省略されたり、値が途中で切れたりします。この後、プロパティを追加していくと、さらに一覧を確認しにくくなります。そこで、$report | Out-GridView *2を使うと、GUIのグリッドビューの別ウィンドウで列幅の調整や横スクロールができ、確認しやすくなります。また、CSVファイルへの出力も簡単です(画面2)。

 

vol249_scr02
画面2 Get-VMの単純値で必要な項目だけを抜き出して一覧にする。結果はOut-GridView*2で参照すると確認しやすい

*2 ※PowerShell  7.6.6のOut-GridViewには不具合が存在し、応答が返ってこない問題が確認されています(→ OutGridView freezes indefinitely in 7.6.6 #27994|PowerShell Issue GitHub) 。この問題は、PowerShell 7.6.7以降で解消されています。 

 

VMの設定項目を追加する

 

 最初のシンプルなスクリプトに、SecureBoot(On/Off)、TPMEnabled(True/False)、OSType(Windows/Linux)、NestedVirt(入れ子になった仮想化、True/False)、OSDiskPath(OSディスク《VHD/VHDX/物理ディスク》のパス)、OSDiskGB(OSディスクのサイズ、GB)、DataDisks(データディスクの数)、DVDs(DVDドライブの数)、NICs(ネットワークアダプターの数)のプロパティを追加したものが、次のスクリプトです。

 第2世代VMの場合は、Get-VMFirmwareの実行結果からセキュアブートのオン/オフ、TPMのオン/オフ、OSType(セキュアブートテンプレートが"MicrosoftWindows"なら"Windows"、それ以外は"Linux")を取得しています。

 入れ子になった仮想化の状態は、Get-VMProcessorのExposeVirtualizationExtensionsの値から取得しています。

 ディスクの数、DVDの数、ネットワークアダプターの数は、Get-VMHardDiskDrive、Get-VMDVDDrive、Get-VMNetworkAdapterの実行結果から取得しています。また、第2世代VMの場合はSCSIコントローラー、第1世代VMの場合はIDEコントローラーを優先して、コントローラー、コントローラーの場所、ディスクの場所で並べ替え、最初のディスクをOSディスクとみなします。OSディスクが存在する場合は、その割り当てサイズ(ディスク上のサイズではない)をGB単位で取得します。さらに、OSディスクの有無によって残りのディスクをデータディスクの数とします。

 

$report = Get-VM | ForEach-Object {
    $vm = $_
    if ($vm.Generation -eq "2") {
        $firmware    = Get-VMFirmware -VM $vm
        $security    = Get-VMSecurity -VM $vm
        $secureboot  = $firmware.SecureBoot
        $tpmenabled  = $security.TpmEnabled 
        $osType      = if ($firmware.SecureBootTemplate -eq "MicrosoftWindows") {
                "Windows"
            } else {
                "Linux"
            }    
    } else {
        $secureboot  = $null
        $tpmenabled  = $null
        $osType      = $null
    }
    $disks           = @(Get-VMHardDiskDrive -VM $vm)
    $dvds            = @(Get-VMDVDDrive -VM $vm)
    $nics            = @(Get-VMNetworkAdapter -VM $vm)
    $osDisk          = $null
    $controllerType  = switch ($vm.Generation) {
        2 { 'SCSI' }
        1 { 'IDE' }
        default { $null }
    }
    if ($null -ne $controllerType) {
       $osDisk = $disks |
            Where-Object { $_.ControllerType -eq $controllerType } |
            Sort-Object ControllerNumber, ControllerLocation |
            Select-Object -First 1
    }
    $osDiskSizeGB    = if ($osDisk.Path) {
        try {
            [math]::Round((Get-VHD -Path $osDisk.Path -ErrorAction Stop).Size / 1GB, 1)
        }
        catch {
            $null
        }
    } else {
        "(nodisk)"
    }
    [pscustomobject]@{
        VMName           = $vm.Name
        Generation       = $vm.Generation
        ConfigPath       = $vm.ConfigurationLocation
        VMId             = $vm.VMId
        ## Firmware
        ## Security
        SecureBoot       = $secureboot
        TPMEnabled       = $tpmenabled
        OSType           = $ostype
        ## Processor
        vCPUs            = $vm.ProcessorCount
        NestedVirt       = (Get-VMProcessor -VM $vm).ExposeVirtualizationExtensions
        ## Memory
        # MemoryAssigned = $vm.MemoryAssigned
        DynamicMemory    = $vm.DynamicMemoryEnabled
        RAMStartupGB     = [math]::Round($vm.MemoryStartup / 1GB, 1)
        RAMMinimumGB     = [math]::Round($vm.MemoryMinimum / 1GB, 1)  
        RAMMaximumGB     = [math]::Round($vm.MemoryMaximum / 1GB, 1)
        ## HardDrives
        OSDiskPath       = if ($null -ne $osDisk) { $osDisk.Path } else { "(nodisk)" }
        OSDiskGB         = $osDiskSizeGB
        #DataDisks        = [math]::Max($disks.Count - 1, 0)
        DataDisks        = $disks.Count - $(if ($null -ne $osDisk) { 1 } else { 0 })
        ## DVDDrives
        DVDs             = $dvds.Count
        ## NetoworkAdapters
        NICs             = $nics.Count
        Version          = $vm.Version
        CreationTime     = $vm.CreationTime
        # isClustered    = $vm.isClustered
    }
}
$report

(プレーンテキストで表示/ダウンロード)

 

vol249_scr03

画面3 一覧にGet-VMFirmware、Get-VMSecurity、Get-VMPrcessor、Get-VMHardDiskDrive、Get-VMDVDDrive、Get-VMNetworkAdapterの実行結果を加工して、プロパティとして追加

 

 作成中のスクリプトは、スタンドアロンのHyper-Vホストでの実行を想定していますが、Hyper-Vホストのフェールオーバークラスター(Hyper-Vホストクラスター)でも問題なく機能します。Hyper-Vホストクラスターの場合、ローカルのクラスター化されていないVMおよび現在所有しているクラスター化されたVMの一覧を取得できます。スクリプトでコメントアウトしている isClustered    = $vm.isClustered を生かせば、クラスター化されているかいないかを一覧に含めることができますが(画面4)、あまりニーズはないと思いコメントアウトしました。

 

画面4 今回のスクリプトはHyper-Vホストクラスターでも利用可能。isClusteredが必要なら、コメントを外せばよい
画面4 今回のスクリプトはHyper-Vホストクラスターでも利用可能。isClusteredが必要なら、コメントを外せばよい

 

 次回は、プロパティをさらに追加し、VMの一覧を完成させます。また、CSV形式でファイル出力も行います。

 

リファレンス(Microsoft Learn):
Get-ComputerInfo(PowerShell Management)|Get-VMHost(Hyper-V)|Get-VM(Hyper-V)|
|Get-VMProcessor(Hyper-V)|Get-VMFirmware(Hyper-V)|Get-VMSecurity(Hyper-V)|Get-VMNetworkAdapter(Hyper-V)|Get-VMHardDiskDrive(Hyper-V)|Get-VMHardDiskDrive(Hyper-V)|about_PSCustomObject(PowerShell)|Out-GridView(PowerShell Utility) 

Hyper-V 小技・裏技集 目次|(1) |(2)|(3)|(4)|(5)|(6)

blog_yamanxworld_subscribe

blog_yamanxworld_comment

blog_yamanxworld_WP_ws2025

最新記事