<--------------------------------- Script ----------------------------------->>
<# .SYNOPSIS
Hyper-V Host & VM Audit Script for Windows Server Migration (Detailed Per-Disk Rows).
.DESCRIPTION
Exports VM specs, Generation, Switch, MAC, IP, and outputs each physical
and virtual disk as its own dedicated row in the CSV and TXT reports.
#>
# Output Directory
$OutputDir = "C:\VM_Audit"
if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir | Out-Null }
$CSVPath = Join-Path $OutputDir "HyperV_VM_Audit_Disks.csv"
$TXTPath = Join-Path $OutputDir "HyperV_VM_Audit_Disks.txt"
# Get all VMs
$VMs = Get-VM
$AuditRows = foreach ($VM in $VMs) {
# Network Adapters
$Nics = Get-VMNetworkAdapter -VMName $VM.Name
# Attempt to extract Guest IP Addresses via Hyper-V Integration Services (KVP)
$GuestIPs = ($Nics.IPAddresses | Where-Object { $_ -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" }) -join "; "
if (-not $GuestIPs) { $GuestIPs = "Unknown / Guest Shut Down" }
# Query hard disk drives directly attached to the VM
$HardDrives = Get-VMHardDiskDrive -VMName $VM.Name
if ($HardDrives.Count -eq 0) {
# Edge case: VM has no attached drives
[PSCustomObject]@{
VMName = $VM.Name
State = $VM.State
Generation = "Gen $($VM.Generation)"
vCPUs = $VM.ProcessorCount
MemoryStartupGB = [math]::Round($VM.MemoryStartup / 1GB, 2)
DynamicMemory = $VM.DynamicMemoryEnabled
VirtualSwitch = ($Nics.SwitchName) -join "; "
MACAddress = ($Nics.MacAddress) -join "; "
GuestIPAddress = $GuestIPs
DiskType = "No Disks Attached"
ControllerType = "N/A"
ControllerLocation = "N/A"
DiskPathOrNumber = "N/A"
Notes = "Verify Static IPs inside OS upon migration"
}
}
else {
# Loop through each disk so it gets its own dedicated row
foreach ($Drive in $HardDrives) {
$ControllerLoc = "$($Drive.ControllerNumber),$($Drive.ControllerLocation)"
if ($Drive.DiskNumber) {
# Physical Pass-Through Disk
$DiskType = "Physical Disk (Pass-Through)"
$PathOrNum = "Physical Disk #$($Drive.DiskNumber)"
}
else {
# Virtual Hard Disk (.vhdx / .vhd)
$DiskType = "Virtual Disk (VHDX/VHD)"
$PathOrNum = $Drive.Path
}
[PSCustomObject]@{
VMName = $VM.Name
State = $VM.State
Generation = "Gen $($VM.Generation)"
vCPUs = $VM.ProcessorCount
MemoryStartupGB = [math]::Round($VM.MemoryStartup / 1GB, 2)
DynamicMemory = $VM.DynamicMemoryEnabled
VirtualSwitch = ($Nics.SwitchName) -join "; "
MACAddress = ($Nics.MacAddress) -join "; "
GuestIPAddress = $GuestIPs
DiskType = $DiskType
ControllerType = $Drive.ControllerType
ControllerLocation = $ControllerLoc
DiskPathOrNumber = $PathOrNum
Notes = "Verify Static IPs inside OS upon migration"
}
}
}
}
# Export to CSV
$AuditRows | Export-Csv -Path $CSVPath -NoTypeInformation -Encoding UTF8
# Generate Human-Readable Text Summary
$TXTContent = @()
$TXTContent += "========================================================"
$TXTContent += " HYPER-V VM DISK AUDIT REPORT - HOST: $env:COMPUTERNAME"
$TXTContent += " Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$TXTContent += "========================================================`n"
$GroupedVMs = $AuditRows | Group-Object VMName
foreach ($Group in $GroupedVMs) {
$FirstRow = $Group.Group[0]
$TXTContent += "VM NAME: $($FirstRow.VMName)"
$TXTContent += "--------------------------------------------------------"
$TXTContent += "State: $($FirstRow.State)"
$TXTContent += "Generation: $($FirstRow.Generation)"
$TXTContent += "vCPUs: $($FirstRow.vCPUs)"
$TXTContent += "RAM (GB): $($FirstRow.MemoryStartupGB) (Dynamic: $($FirstRow.DynamicMemory))"
$TXTContent += "Virtual Switch: $($FirstRow.VirtualSwitch)"
$TXTContent += "MAC Address: $($FirstRow.MACAddress)"
$TXTContent += "Reported Guest IP:$($FirstRow.GuestIPAddress)"
$TXTContent += "Attached Disks:"
foreach ($DiskRow in $Group.Group) {
$TXTContent += " - [$($DiskRow.DiskType)] Bus: $($DiskRow.ControllerType) ($($DiskRow.ControllerLocation)) | Target: $($DiskRow.DiskPathOrNumber)"
}
$TXTContent += "`n"
}
$TXTContent | Out-File -FilePath $TXTPath -Encoding UTF8
Write-Host "Audit completed successfully!" -ForegroundColor Green
Write-Host "CSV saved to: $CSVPath" -ForegroundColor Yellow
Write-Host "TXT saved to: $TXTPath" -ForegroundColor Yellow