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

セイテクエンジニアのブログ  かつて山市良と呼ばれたおじさんのブログ  vol.248 複数VMの設定を一括で差分比較|Hyper-V 健康診断

 

 

vol.248 複数VMの設定を一括で差分比較|Hyper-V 健康診断

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

 引き続き、Hyper-Vホストの構成情報を1つのCLIXMLファイル(.xml)として保存する棚卸スクリプト「get-hypervhostinventory.ps1」(プレーンテキストで表示/ダウンロード)で保存した2つの棚卸データの差分比較を行います。今回の対象はHyper-Vの仮想マシン(VM)です。

 

棚卸データのVMに関連するデータ構造

 

 棚卸データのVMのデータは、CLIXMLファイル(.xml)からImport-Clixmlで読み込んだオブジェクトのVirtualMachinesプロパティ下に格納されています。ここには、Get-VMの実行結果に加え、VMごとのGet-VMProcessor(VCPUの設定)、Get-VMMemory(動的メモリなどの設定)、Get-VMFirmware(セキュアブート、セキュアブートテンプレート、ブート順など)、Get-VMSecurity(TPMのオン/オフなど)、Get-VMNetworkAdapter(ネットワークアダプターの割り当て)、Get-VMHardDiskDrive(ハードドライブの割り当て)、Get-VMSnapshot(✓位ポイント)の実行結果、およびクラスター化されているかどうかによって棚卸スクリプトでセットしたHAプロパティ(※Get-VMのisClusteredプロパティがあったので追加は不要でした)が、Get-VMのプロパティ直下のプロパティまたはコレクションとして含まれています。Get-VMだけでも大量のプロパティを持つ上に、VMに紐づく他のデータを含めると、そのデータは複雑であり、VM数が多いと巨大なコレクションになります。

 

Virtual Machines Get-VMが返すオブジェクト
Virtual Machines.HA

VMがクラスター化されたVMかどうか(True/False)
※Get-VMのisClusteredプロパティがあったので追加は不要でした。比較も不要です。

Virtual Machines.VCPU VMのGet-VMProcessorが返すオブジェクト(コレクション)
Virtual Machines.VRAM VMのGet-VMMemoryが返すオブジェクト(コレクション)
Virtual Machines.VMFirmware VMのGet-VMFirmwareが返すオブジェクト(コレクション)
Virtual Machines.VMSecurity VMのGet-VMSecurityが返すオブジェクト(コレクション)
Virtual Machines.VNIC VMのGet-VMNetworkAdapterが返すオブジェクト(コレクション)
Virtual Machines.VHD VMのGet-VMHardDiskDriveが返すオブジェクト(コレクション)
Virtual Machines.VMSnapshot VMのGet-VMSnapshotが返すオブジェクト(コレクション)

※棚卸データ全体のデータ構造については、前々回の記事の一覧表を参照してください。

 

VMの一括比較スクリプト

 

 次のPowerShellスクリプト「Compare-HyperVVMs.ps1」は、棚卸データのVirtualMachinesプロパティの配下をVMごとに突き合わせて比較し、差分を返すスクリプトです。追加されたVMと削除されたVMにも対応しています。

 

 Get-VMの実行結果のすべてのプロパティを突き合わあせて比較すると、ノイズが多いだけでなく、同じ内容に見えても差分(複合プロパティなど)として判断されてしまうことがあります。また、動的に変化する値(Get-VMのStatusやCPUUsage、MemoryAssigned、MemoryDemand、UpTimeなど)のプロパティは比較しても意味がありません。そこで、このスクリプトではまず、前回の「Compare-Properties.ps1」と同様に、文字列(string)、数値(decimal、Int32、Int64、Doubleなど)、真偽値(Boolen)、日時(DateTime)、列挙値(Enum)など、1つの値として比較できる単純値のプロパティだけを対象にすることに加え(Compare-SimpleProperties関数を参照)、動的に変化する値とコレクションを除外しています(Compare-SimpleProperties関数を呼び出す際の-ExcludePropertyを参照)。

 

 その上で除外したコレクションの中で重要なもの(Groups、ComPort1、ComPort2、VMIntegrationService)と、Get-VM以外(Get-VMProcessorなど)で取得したコレクションを個別に処理します。なお、Get-VM(VirtualMachines)のFibreChannelHostBusAdapters、DVDDrives、HardDrives、およびNetworkAdaptersは数だけを比較しています。HDDカテゴリではディスクごとにコントローラー、場所、パスを比較、VNICカテゴリではすべてのネットワークアダプターのMACアドレスで比較しています。

 

 最初は単純値のプロパティを突き合わせて比較するだけのシンプルなスクリプトだったのですが、色々と付け足していくうちに、巨大化、複雑化してしまいました(反省)。でも、私の環境では期待どおりに動いているので良しとします。

 

[Compare-HyperVVMs.ps1](プレーンテキストで表示/ダウンロード)

param(
    [Parameter(Mandatory)]
    [AllowNull()]
    $oldVMs,
    [Parameter(Mandatory)]
    [AllowNull()]
    $newVMs,
    [ValidateSet("VMonly", "All")]
    [string]$Category = ""
)
if ($Category -eq "") {
    $Category = "All"
    if (($oldVms -ne $null) -and ($oldVms.Count -gt 0)) {
        $objTypes = $oldVms[0].PSObject.TypeNames
        if ($objTypes -contains "Microsoft.HyperV.PowerShell.VirtualMachine") {
             $Category = "VMonly"
        }
    }
    if (($newVms -ne $null) -and ($newVms.Count -gt 0)) {
        $objTypes = $newVms[0].PSObject.TypeNames
        if ($objTypes -contains "Microsoft.HyperV.PowerShell.VirtualMachine") {
             $Category = "VMonly"
        }
    }
}

$result = @()

function Compare-SimpleProperties {
    param(
        $OldObject,
        $NewObject,
        [string]$Category,
        $VM,
        [string[]]$ExcludeProperty = @()
    )

    if ($null -eq $OldObject -and $null -eq $NewObject) {
        return
    }

    # オブジェクト自体の追加・削除
    if ($null -eq $OldObject) {
        return [pscustomobject]@{
            ChangeType = 'Added'
            VMName     = $VM.Name
            VMId       = $VM.VMId
            Category   = $Category
            Property   = $null
            OldValue   = $null
            NewValue   = $null
        }
    }

    if ($null -eq $NewObject) {
        return [pscustomobject]@{
            ChangeType = 'Removed'
            VMName     = $VM.Name
            VMId       = $VM.VMId
            Category   = $Category
            Property   = $null
            OldValue   = $null
            NewValue   = $null
        }
    }

    foreach ($prop in $NewObject.PSObject.Properties.Name) {

        if ($prop -in $ExcludeProperty) {
            continue
        }

        $oldValue = $OldObject.$prop
        $newValue = $NewObject.$prop

        # 新旧とも単純値だけを対象にする
        $oldSimple =
            $null -eq $oldValue -or
            $oldValue.GetType().IsPrimitive -or
            $oldValue -is [string] -or
            $oldValue -is [decimal] -or
            $oldValue -is [datetime] -or
            $oldValue -is [guid] -or
            $oldValue.GetType().IsEnum

        $newSimple =
            $null -eq $newValue -or
            $newValue.GetType().IsPrimitive -or
            $newValue -is [string] -or
            $newValue -is [decimal] -or
            $newValue -is [datetime] -or
            $newValue -is [guid] -or
            $newValue.GetType().IsEnum

        if (-not $oldSimple -or -not $newSimple) {
            continue
        }

        # Deserialized Enumなどの型差を避け、表示上の値で比較
        $oldText = if ($null -eq $oldValue) { $null } else { $oldValue.ToString() }
        $newText = if ($null -eq $newValue) { $null } else { $newValue.ToString() }

        if ($oldText -ne $newText) {
            [pscustomobject]@{
                ChangeType = 'Changed'
                VMName     = $VM.Name
                VMId       = $VM.VMId
                Category   = $Category
                Property   = $prop
                OldValue   = $oldText
                NewValue   = $newText
            }
        }
    }
}


# 既存VM / 追加VM
foreach ($newVM in $newVMs) {

    $oldVM = $oldVMs | Where-Object VMId -eq $newVM.VMId

    # 追加されたVM
    if (-not $oldVM) {
        $result += [pscustomobject]@{
            ChangeType = 'Added'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = $null
            OldValue   = $null
            NewValue   = $null
        }

        continue
    }


    # -----------------------------
    # Get-VM 本体
    # -----------------------------
    $result += Compare-SimpleProperties `
        -OldObject $oldVM `
        -NewObject $newVM `
        -Category 'VM' `
        -VM $newVM `
        -ExcludeProperty @(
            'CPUUsage'
            'MemoryAssigned'
            'MemoryDemand'
            'MemoryStatus'
            'NumaAligned'
            'NumaNodesCount'
            'NumaSocketCount'
            'Heartbeat'
            'IntegrationServicesState'
            'Uptime'
            'OperationalStatus'
            'PrimaryOperationalStatus'
            'SecondaryOperationalStatus'
            'StatusDescriptions'
            'PrimaryStatusDescription'
            'SecondaryStatusDescription'
            'Status'
            'ReplicationHealth'
            'ReplicationState'
            'State'
            'SizeOfSystemFiles'
            'GuestControlledCacheTypes'
            'LowMemoryMappedIoSpace'
            'HighMemoryMappedIoSpace'
            'HighMemoryMappedIoBaseAddress'
            'VMIntegrationService'
            'HA'
            'VCPU'
            'VRAM'
            'VMFirmware'
            'VMSecurity'
            'VNIC'
            'VHD'
            'VMSnapshot'
        )

    # -----------------------------
    # Get-VM のコレクションプロパティの比較
    # -----------------------------
    # Groups
    $oldValue = @($oldVM.Groups) |
        ForEach-Object { $_.Name } |
        Sort-Object
    $newValue = @($newVM.Groups) |
        ForEach-Object { $_.Name } |
        Sort-Object
    if (($oldValue -join ',') -ne ($newValue -join ',')) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'Groups'
            OldValue   = $oldValue -join ','
            NewValue   = $newValue -join ','
        }
    }
    # ComPort1 Pathで比較
  $oldValue = $oldVM.ComPort1.Path
    $newValue = $newVM.ComPort1.Path
    if ($oldValue -ne $newValue) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'ComPort1'
            OldValue   = $oldValue
            NewValue   = $newValue
        }
    }
    # ComPort2 Pathで比較
  $oldValue = $oldVM.ComPort2.Path
    $newValue = $newVM.ComPort2.Path
    if ($oldValue -ne $newValue) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'ComPort2'
            OldValue   = $oldValue
            NewValue   = $newValue
        }
    }
    # FibreChannelHostBusAdapters Countで比較
    $oldCount = @($oldVM.FibreChannelHostBusAdapters).Count
    $newCount = @($newVM.FibreChannelHostBusAdapters).Count
    if ($oldCount -ne $newCount) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'FibreChannelHostBusAdapters.Count'
            OldValue   = $oldCount
            NewValue   = $newCount
        }
    }
    # DVDDrives Countで比較
    $oldCount = @($oldVM.DVDDrives).Count
    $newCount = @($newVM.DVDDrives).Count
    if ($oldCount -ne $newCount) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'DVDDrives.Count'
            OldValue   = $oldCount
            NewValue   = $newCount
        }
    }
    # HardDrives Countで比較
    $oldCount = @($oldVM.HardDrives).Count
    $newCount = @($newVM.HardDrives).Count
    if ($oldCount -ne $newCount) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'HardDrives.Count'
            OldValue   = $oldCount
            NewValue   = $newCount
        }
    }
    # NetworkAdapters  Countで比較
    $oldCount = @($oldVM.NetworkAdapters).Count
    $newCount = @($newVM.NetworkAdapters).Count
    if ($oldCount -ne $newCount) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VM'
            Property   = 'NetworkAdapters.Count'
            OldValue   = $oldCount
            NewValue   = $newCount
        }
    }
    # VMIntegrationService
    $oldServices = @($oldVM.VMIntegrationService)
    $newServices = @($newVM.VMIntegrationService)

    foreach ($newService in $newServices) {

        $oldService = $oldServices |
            Where-Object Name -eq $newService.Name

        if (-not $oldService) {
            $result += [pscustomobject]@{
                ChangeType = 'Added'
                VMName     = $newVM.Name
                VMId       = $newVM.VMId
                Category   = 'IntegrationService'
                Property   = $newService.Name
                OldValue   = $null
                NewValue   = if ($newService.Enabled) {
                    'Enabled'
                }
                else {
                    'Disabled'
                }
            }

            continue
        }

        if ($oldService.Enabled -ne $newService.Enabled) {
            $result += [pscustomobject]@{
                ChangeType = 'Changed'
                VMName     = $newVM.Name
                VMId       = $newVM.VMId
                Category   = 'IntegrationService'
                Property   = $newService.Name
                OldValue   = if ($oldService.Enabled) {
                    'Enabled'
                }
                else {
                    'Disabled'
                }
                NewValue   = if ($newService.Enabled) {
                    'Enabled'
                }
                else {
                    'Disabled'
                }
            }
        }
    }

    foreach ($oldService in $oldServices) {

        if ($oldService.Name -notin $newServices.Name) {
            $result += [pscustomobject]@{
                ChangeType = 'Removed'
                VMName     = $newVM.Name
                VMId       = $newVM.VMId
                Category   = 'IntegrationService'
                Property   = $oldService.Name
                OldValue   = if ($oldService.Enabled) {
                    'Enabled'
                }
                else {
                    'Disabled'
                }
                NewValue   = $null
            }
        }
    }

    # -----------------------------
    # Get-VM 以外の関連プロパティの比較
    # -----------------------------
    if ($Category -eq 'All') {

    # -----------------------------
    # HA
    # -----------------------------
    # VirtualMachines (Get-VM) の .IsClustered と同じなので比較しない
    # -----------------------------
    # VCPU (Get-VMProcessor)
    # -----------------------------
    $result += Compare-SimpleProperties `
        -OldObject $oldVM.VCPU `
        -NewObject $newVM.VCPU `
        -Category 'VCPU' `
        -VM $newVM `
        -ExcludeProperty @(
           'Dummy'
        )
    # -----------------------------
    # VRAM (Get-VMMemory)
    # -----------------------------
    $result += Compare-SimpleProperties `
        -OldObject $oldVM.VRAM `
        -NewObject $newVM.VRAM `
        -Category 'VRAM' `
        -VM $newVM `
        -ExcludeProperty @(
           'MemoryEncryptionEnabled'
        )
    # -----------------------------
    # VMFirmware (Get-VMFirmware)
    # -----------------------------
    $result += Compare-SimpleProperties `
        -OldObject $oldVM.VMFirmware `
        -NewObject $newVM.VMFirmware `
        -Category 'VMFirmware' `
        -VM $newVM `
        -ExcludeProperty @(
           'Dummy'
        )
    # BootOrder
    $oldBootOrder = @($oldVM.VMFirmware.BootOrder) |
        ForEach-Object { $_.FirmwarePath }
    $newBootOrder = @($newVM.VMFirmware.BootOrder) |
        ForEach-Object { $_.FirmwarePath}
    if (($oldBootOrder -join ',') -ne ($newBootOrder -join ',')) {
        $oldBootOrder = @($oldVM.VMFirmware.BootOrder) |
            ForEach-Object {
                if ($null -eq $_.BootType) {
                    'Unknown'
                } else {
                    $_.BootType.ToString()
                }
            }
        $newBootOrder = @($newVM.VMFirmware.BootOrder) |
            ForEach-Object {
                if ($null -eq $_.BootType) {
                    'Unknown'
                } else {
                    $_.BootType.ToString()
                }
            }
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VMFirmware'
            Property   = 'BootOrder'
            OldValue   = $oldBootOrder -join ','
            NewValue   = $newBootOrder -join ','
        }
    }

    # -----------------------------
    # VMSecurity (Get-VMSecurity)
    # -----------------------------
    $result += Compare-SimpleProperties `
        -OldObject $oldVM.VMSecurity `
        -NewObject $newVM.VMSecurity `
        -Category 'VMSecurity' `
        -VM $newVM `
        -ExcludeProperty @(
           'Dummy'
        )

    # -----------------------------
    # VNIC (Get-VMNetworkAdapter)
    # -----------------------------
    $oldMac = @($oldVM.VNIC.MacAddress) | Sort-Object
    $newMac = @($newVM.VNIC.MacAddress) | Sort-Object

    if (($oldMac -join ',') -ne ($newMac -join ',')) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VNIC'
            Property   = 'MACAddress'
            OldValue   = $oldMac -join ','
            NewValue   = $newMac -join ','
        }
    }

    # -----------------------------
    # VHD (Get-VMHardDiskDrive)
    # -----------------------------
    $oldvals = @($oldVM.VHD)
    $newvals = @($newVM.VHD)
    $oldvals = @($oldvals | Sort-Object | ForEach-Object {
        @(
            $_.ControllerType
            $_.ControllerNumber
            $_.ControllerLocation
            $_.DiskNumber
            $_.Path
        ) -join '_'
    })
    $newvals = @($newvals | Sort-Object | ForEach-Object {
        @(
            $_.ControllerType
            $_.ControllerNumber
            $_.ControllerLocation
            $_.DiskNumber
            $_.Path
        ) -join '_'
    })
    for ($i = 0; $i -lt [Math]::Max($oldvals.Count, $newvals.Count); $i++) {
        $diff = if ($i -ge $oldvals.Count) { "Added" }
              elseif ($i -ge $newvals.Count) { "Removed" }
              elseif ($oldvals[$i] -eq $newvals[$i]) { "NoChanged" }
              else { "Changed" }
        if($diff -ne "NoChanged") {
            $result += [pscustomobject]@{
                ChangeType = $diff
                VMName     = $newVM.Name
                VMId       = $newVM.VMId
                Category   = "VHD"
                Property   = "Disk$i"
                OldValue   = $oldvals[$i]
                NewValue   = $newvals[$i]
            }
        }
    }

    # -----------------------------
    # VMSnapshot (Get-VMSnapshot)
    # -----------------------------
    $oldCount = @($oldVM.VMSnapshot).Count
    $newCount = @($newVM.VMSnapshot).Count

    if ($oldCount -ne $newCount) {
        $result += [pscustomobject]@{
            ChangeType = 'Changed'
            VMName     = $newVM.Name
            VMId       = $newVM.VMId
            Category   = 'VMSnapshot'
            Property   = 'Count'
            OldValue   = $oldCount
            NewValue   = $newCount
        }
    }
    }
    # -----------------------------
    # Get-VM 以外の関連プロパティの比較(ここまで)
    # -----------------------------
}


# 削除されたVM
foreach ($oldVM in $oldVMs) {

    if ($oldVM.VMId -notin $newVMs.VMId) {
        $result += [pscustomobject]@{
            ChangeType = 'Removed'
            VMName     = $oldVM.Name
            VMId       = $oldVM.VMId
            Category   = 'VM'
            Property   = $null
            OldValue   = $null
            NewValue   = $null
        }
    }
}

$result

 

スクリプトの実行例

 

 前回も説明しましたが、棚卸スクリプト「get-hypervhostinventory.ps1」でCLIXMLファイル(.xml)に保存した新旧棚卸データは、次のコマンドラインを実行することで、それぞれ別の変数にオブジェクトとして読み込むことができます。

$oldinv = Import-Clixml .\HyperVHost-Inventory-コンピューター名-XXXXXX-XXXXXX.xml
$newinv = Import-Clixml .\HyperVHost-Inventory-コンピューター名-YYYYYY-YYYYYY.xml

 

 スクリプトには、Import-Clixmlで読み込んだ新旧オブジェクトのVirtualMachinesプロパティを次のように渡して実行します。なお、@()は省略できますが、@()で囲むことでVM一覧が1台の場合でも配列として扱えるようになります。

$oldVMs = @($oldinv.VirtualMachines)
$newVMs = @($newinv.VirtualMachines)
.\Compare-HyperVVMs.ps1 $oldVMs $NewVMs |Format-Table -AutoSize

 

 差分は次のような形式のオブジェクトとして出力されます。長い文字列の値の影響で画面出力が途切れてしまう場合は、Out-GridVew*1 を利用すると便利です(画面1)。Categoryのカテゴリは、Get-VMに含まれるものがVM(およびHA)、それ以外のコレクションについてはVCPU、VRAM、VMFirmware、VMSecurity、VHD、VMSnapshotになります。また、値に変更がある場合は、ChangeTypeがChangedになりますが、追加/削除されたVMについては、Added/Removedと表示し、Property/OldValue/NewValueは空欄になります。

ChangeType VMName    VMId                                 Category Property     OldValue NewValue
---------- ------    ----                                 -------- --------     -------- --------
Changed    VM名      XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX カテゴリ プロパティ名 旧い値   新しい値

 

画面1 新旧棚卸データのVMデータを比較して、差分を出力する

画面1 新旧棚卸データのVMデータを比較して、差分を出力する

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

 

 なお、比較処理と比較結果を簡潔にするため、一部のプロパティについては数や、コレクションのプロパティを連結した値の差異を比較しています。詳細を調べたい場合は、棚卸データの該当箇所を参照してください。例えば、次のように実行すれば、指定したVMのVHDコレクションの新旧を一覧表示できます(画面2)。Compare-HyperVVMs.ps1スクリプトでは、SCSI_0_0__パスのように連結して比較し、差異がある場合は連結値をVHDカテゴリのDisk0、Disk1プロパティの値として出力します。

$targetvm = "VM名またはVMId"
foreach($vm in $oldvms) {
    if(($vm.Name -eq $targetvm) -or ($vm.Vmid -eq $targetvm)) {
        $vm.VHD |Select ControllerType,ControllerNumber,ControllerLocation,Path | Format-Table -AutoSize
    }
}
foreach($vm in $newvms) {
    if(($vm.Name -eq $targetvm) -or ($vm.Vmid -eq $targetvm)) {
        $vm.VHD |Select ControllerType,ControllerNumber,ControllerLocation,Path | Format-Table -AutoSize
    }
}

 

画面2 ハードドライブの数の差異の詳細を確認する

画面2 ハードドライブの数の差異の詳細を確認する

 

 次の画面3のように、最新の棚卸データ(例えば$newinv)と現在のGet-VMの実行結果をこのスクリプトで比較することもできます。ただし、その場合、比較対象はカテゴリVMとなるため、VCPU、VRAM、VMFirmware、VMSecurity、VNIC、VHD、VMSnapshotのカテゴリは比較されません。その結果、ハードドライブの追加/削除、チェックポイントの作成/適用/削除、ネットワークアダプターの追加/削除、セキュアブート、TPMのオン/オフ、ブート順の変更などは差分として出力されないことに注意してください。*2

*2 VRAMカテゴリ(Get-VMMemory)のDynamicMemoryEnabled、Startup、Maximum、Minimumプロパティは、VMカテゴリ(Get-VM)のDynamicMemoryEnabled、MemoryStartup、MemoryMinimum、MemoryMaximumプロパティの変化として検出されます。

vol248_scr03-2

画面3 最新の棚卸データと現在のGet-VMの実行結果を確認する

 

 なお、次のように実行した場合、どうなるでしょうか。

$oldvm = @(Get-VM -Name vm01)
# vm01 の設定を変更する

$newvm = @(Get-VM -Name vm01)
.\Compare-HyperVVMS.ps1 $oldvm $newvm

 

 答えは、差分はまったく検出されません。なぜなら、「vol.235 Get-VMで状態を取得する裏技|Hyper-V 小技・裏技集」で説明したように、Microsoft.HyperV.PowerShell.VirtualMachineタイプのオブジェクトのプロパティは動的に最新の情報を反映するからです。次のようにExport-Clixml/Import-Clixmlすることでオブジェクトのメンバーをデシリアライズ化(Deserialized.Microsoft.HyperV.PowerShell.
VirtualMachine)すれば、$newvmsと比較できるようになります。

$oldvm = @(Get-VM -Name vm01)
$oldvm | Export-Clixml .\oldvm.xml

$oldvm = @(Import-Clixml .\oldvm.xml)

# vm01 の設定を変更する

$newvm = @(Get-VM -Name vm01)
.\Compare-HyperVVMS.ps1 $oldvm $newvm

 今回まで使用してきた棚卸データは、後から構成情報を比較できるよう、できるだけ多くの情報を、可能な限り元の形式(PowerShellオブジェクトの構造と型)を保って保存するという考えに基づいています。これまで、概要の参照や差分の検索に使うスクリプトをいくつか紹介しました。スクリプトが対応していない情報についても、保存されたデータのプロパティを直接参照したり、必要に応じてスクリプトを作成したりすることで活用できます。

 

 次回からは少し視点を変え、資産としてのVMやVHDの管理について検討します。

 

サーバー設定仕様書の自動生成サービス、SSD-assistanceのご紹介

 弊社の主力製品の1つ設定仕様書自動生成サービス「SSD-assistance」は、設定仕様書作成のためのデータ収集やドキュメント作成の手間と時間を省き、高品質で標準化された設定仕様書を自動生成するサービスです。SSD-assistanceは、「Hyper-V ホスト 設定仕様書」の作成に対応している上、「差分比較リスト」で構成の変更差分を視覚的に強調表示させることができます。ここまでの記事でやってきたことと同等のことは、実はSSD-assistanceを利用すれば誰でも、簡単に、すぐに実現することができます。ただこの連載記事では、SSD-assistanceでは手の届かない、Hyper-Vの深くて、細かいところまで手を伸ばせればと考えています。

Hyper-Vホスト設定仕様書のサンプル

Hyper-Vホスト設定仕様書のサンプル(クリックで拡大)

差分比較リストのサンプル

差分比較リストのサンプル(クリックで拡大)

 

 

リファレンス(Microsoft Learn):

Get-VM(Hyper-V)|Get-VMProcessor(Hyper-V)|Get-VMMemory(Hyper-V)|Get-VMFirmware(Hyper-V)|Get-VMSecurity(Hyper-V)|Get-VMNetworkAdapter(Hyper-V)|Get-VMHardDiskDrive(Hyper-V)|Get-VMSnapshot(Hyper-V)|Export-Clixml(PowerShell Utility)|Import-Clixml(PowerShell Utility)

 

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

blog_yamanxworld_subscribe

blog_yamanxworld_comment

blog_yamanxworld_WP_ws2025

最新記事