<# .SYNOPSIS Read-only health report of virtual machines on a Hyper-V host after a migration. .DESCRIPTION One row per VM with what typically needs fixing after a VMware conversion: generation, configuration version, static vs dynamic memory, processor compatibility for live migration, Secure Boot template, disk format (dynamic/fixed) and location, switch / VLAN, MAC mode, integration services turned off, leftover checkpoints, cluster role and heartbeat. Nothing is changed. .PARAMETER VMName One or more VM names. Defaults to every VM on the host. .EXAMPLE .\Get-HyperVMigrationReport.ps1 | Out-GridView .EXAMPLE .\Get-HyperVMigrationReport.ps1 -VMName APP01,SQL01 | Export-Csv .\hyperv-report.csv -NoTypeInformation -Delimiter ';' .NOTES Windows Server 2016 or later with the Hyper-V PowerShell module. Run on the host. Integration service names are localized: the script reports them as returned. Source: ANYSYS ICT, https://www.anysys.be/articles/ #> [CmdletBinding()] param( [string[]]$VMName = '*' ) $ErrorActionPreference = 'Stop' foreach ($vm in Get-VM -Name $VMName) { $fw = if ($vm.Generation -eq 2) { Get-VMFirmware -VM $vm } else { $null } $cpu = Get-VMProcessor -VM $vm $mem = Get-VMMemory -VM $vm $nics = @(Get-VMNetworkAdapter -VM $vm) $hdds = @(Get-VMHardDiskDrive -VM $vm) $vhds = @($hdds | Where-Object Path | ForEach-Object { Get-VHD -Path $_.Path -ErrorAction SilentlyContinue }) $snaps = @(Get-VMSnapshot -VM $vm) $isOff = @(Get-VMIntegrationService -VM $vm | Where-Object { -not $_.Enabled } | ForEach-Object Name) [pscustomobject]@{ Name = $vm.Name State = $vm.State Heartbeat = $vm.Heartbeat Generation = $vm.Generation ConfigVersion = $vm.Version Clustered = $vm.IsClustered vCPU = $cpu.Count CpuCompatibility = $cpu.CompatibilityForMigrationEnabled DynamicMemory = $mem.DynamicMemoryEnabled StartupMemoryGB = [math]::Round($mem.Startup / 1GB, 1) SecureBoot = if ($fw) { $fw.SecureBoot } else { 'n/a (Gen1)' } SecureBootTemplate = if ($fw) { $fw.SecureBootTemplate } else { '' } Disks = $hdds.Count VhdTypes = ($vhds.VhdType | Sort-Object -Unique) -join ',' VhdPaths = ($hdds.Path) -join ' | ' Switches = ($nics.SwitchName | Sort-Object -Unique) -join ',' Vlans = ($nics | ForEach-Object { $v = Get-VMNetworkAdapterVlan -VMNetworkAdapter $_; '{0}:{1}' -f $v.OperationMode, $v.AccessVlanId }) -join ',' DynamicMac = ($nics.DynamicMacAddressEnabled | Sort-Object -Unique) -join ',' MacAddresses = ($nics.MacAddress) -join ',' GuestIPs = (@($nics.IPAddresses) -join ',') IntegrationOff = $isOff -join ',' Checkpoints = $snaps.Count } }