迁移前后VM信息HTML报告合并需求:生成含变更标识的对比表格格式单文件
解决方案:VM迁移前后报告对比合并
整体思路
要生成带自动变更标记的对比报告,我们先让迁移前后的报告输出结构化JSON数据(比直接解析HTML更高效),再编写脚本读取两份数据、配对对应项并对比,最后生成符合要求的对比HTML表格。
步骤1:修改原PowerShell脚本,输出结构化数据
原脚本只生成HTML报告,我们扩展它同时输出JSON文件,方便后续对比。修改后的脚本如下:
$header = @"<style> h1 { font-family: Arial, Helvetica, sans-serif; color: #e68a00; font-size: 28px; } h2 { font-family: Arial, Helvetica, sans-serif; color: #000099; font-size: 16px; } table { font-size: 12px; border: 0px; font-family: Arial, Helvetica, sans-serif; } td { padding: 4px; margin: 0px; border: 0; } th { background: #395870; background: linear-gradient(#49708f, #293f50); color: #fff; font-size: 11px; text-transform: uppercase; padding: 10px 15px; vertical-align: middle; } tbody tr:nth-child(even) { background: #f0f0f2; } #CreationDate { font-family: Arial, Helvetica, sans-serif; color: #ff3300; font-size: 12px; } .StopStatus { color: #ff0000; } .RunningStatus { color: #008000; } </style> "@ $complist = Get-Content .\Documents\abc.txt $timestamp = Get-Date -Format "yyyyMMddHHmmss" $reportPrefix = "PreMigration_" # 迁移后运行时改为PostMigration_ foreach($comp in $complist) { $pingtest = Test-Connection -ComputerName $comp -Count 4 -ErrorAction SilentlyContinue if($pingtest) { Write-Host "$comp,Online" -ForegroundColor Green # 收集结构化数据 $osData = Get-WmiObject Win32_OperatingSystem | Select-Object Version,Caption,BuildNumber,Manufacturer $processorData = Get-WmiObject Win32_Processor | Select-Object DeviceID,Name,Caption,MaxClockSpeed,SocketDesignation,Manufacturer $biosData = Get-WmiObject -ClassName Win32_BIOS | Select-Object SMBIOSBIOSVersion,Manufacturer,Name,SerialNumber $diskData = Get-WmiObject win32_logicaldisk -Filter "deviceid='C:'" -ComputerName $comp | Select-Object PSComputername ,Caption , @{Name="SizeGB";Expression={($_.Size/1gb) -as [int]}}, @{Name="FreeGB";Expression={($_.Freespace/1gb).Tostring("#.##") }}, @{Name="PercentFree";Expression={(($_.Freespace/$_.Size)*100).Tostring("#.##") }} $networkData = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $comp -Filter "IPEnabled='True'"| Select-Object PSComputerName, @{Name='IpAddress';Expression={$_.IpAddress -join '; '}}, @{Name='IpSubnet';Expression={$_.IpSubnet -join '; '}}, @{Name='DefaultIPgateway';Expression={$_.DefaultIPgateway -join '; '}}, @{Name='DNSServerSearchOrder';Expression={$_.DNSServerSearchOrder -join '; '}},DHCPEnabled,MACAddress $servicesSummary = [PSCustomObject]@{ TotalServices = (Get-WmiObject Win32_Service -ComputerName $comp).count Running = (Get-WmiObject Win32_Service -ComputerName $comp | Where-Object {$_.State -eq 'Running'}).count Stopped = (Get-WmiObject Win32_Service -ComputerName $comp | Where-Object {$_.State -eq 'Stopped'}).count } $servicesDetail = Get-WmiObject Win32_Service -ComputerName $comp| select Name,State,StartMode,StartName |Sort-Object StartMode # 组合所有结构化数据 $vmData = [PSCustomObject]@{ HostName = $comp OperatingSystem = $osData Processor = $processorData BIOS = $biosData DiskUtilization = $diskData Network = $networkData ServicesSummary = $servicesSummary ServicesDetail = $servicesDetail ReportDate = (Get-Date).ToString() } # 输出JSON文件 $vmData | ConvertTo-Json -Depth 10 | Out-File -FilePath "C:\Users\prameshp\documents\$reportPrefix$comp_$timestamp.json" # 生成原HTML报告(保留原有功能) $ComputerName = "<h1>$($reportPrefix.Replace('_',' '))Check : $comp</h1>" $namehost= "<h2>Host Name </h2>$comp" $OSinfo = $osData | ConvertTo-Html -As List -Fragment -PreContent "<h2>Operating System Information</h2>" $ProcessInfo = $processorData | ConvertTo-Html -As List -Fragment -PreContent "<h2>Processor Information</h2>" $BiosInfo = $biosData | ConvertTo-Html -As List -Fragment -PreContent "<h2>BIOS Information</h2>" $ping=ping $comp $pingresult = "<h2>Ping Result</h2>$ping" $ServicesInfo1 = $servicesSummary | ConvertTo-Html -As List -Fragment -PreContent "<h2>Services Information</h2>" $ServicesInfo = $servicesDetail | ConvertTo-Html -Fragment -PreContent "<h2>Services</h2>" $ServicesInfo = $ServicesInfo -replace '<td>Running</td>','<td class="RunningStatus">Running</td>' $ServicesInfo = $ServicesInfo -replace '<td>Stopped</td>','<td class="StopStatus">Stopped</td>' $memory = $diskData | ConvertTo-Html -As List -Fragment -PreContent "<h2>Disk Utilization</h2>" $network = $networkData | ConvertTo-Html -As List -Fragment -PreContent "<h2>Network Information</h2>" ConvertTo-HTML -Head $header -Body "$ComputerName$namehost$OSinfo$ProcessInfo$BiosInfo$memory$network$pingresult$ServicesInfo1$ServicesInfo" -PostContent "<i>report generated: $(Get-Date)</i>" | Out-File -FilePath "C:\Users\prameshp\documents\$reportPrefix$comp_$timestamp.html" } else { Write-Host "$comp,offline" -ForegroundColor Red } } Write-Host "####task completed####"
提示:迁移前运行时保持
$reportPrefix为PreMigration_,迁移后改为PostMigration_,确保文件名包含VM名称方便配对。
步骤2:编写对比脚本,生成带变更标记的HTML报告
这个脚本读取迁移前后的JSON数据,自动对比并生成符合要求的对比表格:
# 配置文件路径 $preMigrationJsonPath = "C:\Users\prameshp\documents\PreMigration_VM01_20240520100000.json" $postMigrationJsonPath = "C:\Users\prameshp\documents\PostMigration_VM01_20240520140000.json" $outputHtmlPath = "C:\Users\prameshp\documents\MigrationComparison_VM01.html" # 读取JSON数据 $preData = Get-Content $preMigrationJsonPath | ConvertFrom-Json $postData = Get-Content $postMigrationJsonPath | ConvertFrom-Json # 定义对比样式 $comparisonHeader = @" <style> h1 { font-family: Arial, Helvetica, sans-serif; color: #e68a00; font-size: 28px; } table { font-size: 12px; border-collapse: collapse; font-family: Arial, Helvetica, sans-serif; width: 100%; } td, th { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background: #395870; background: linear-gradient(#49708f, #293f50); color: #fff; font-size: 11px; text-transform: uppercase; } tbody tr:nth-child(even) { background: #f0f0f2; } .changed { color: #ff3300; font-weight: bold; } .unchanged { color: #008000; } </style> "@ # 生成对比行的工具函数 function New-ComparisonRow { param( [string]$ItemName, [string]$PreValue, [string]$PostValue ) $isChanged = if ($PreValue -eq $PostValue) { "否" } else { "是" } $changedClass = if ($isChanged -eq "是") { "changed" } else { "unchanged" } return "<tr><td>$ItemName</td><td>$PreValue</td><td>$PostValue</td><td class='$changedClass'>$isChanged</td></tr>" } # 构建对比内容 $comparisonRows = @() # 主机基本信息 $comparisonRows += New-ComparisonRow -ItemName "主机名称" -PreValue $preData.HostName -PostValue $postData.HostName # 操作系统信息 $osItems = @( @{Name="系统版本"; Pre=$preData.OperatingSystem.Version; Post=$postData.OperatingSystem.Version}, @{Name="系统名称"; Pre=$preData.OperatingSystem.Caption; Post=$postData.OperatingSystem.Caption}, @{Name="构建版本"; Pre=$preData.OperatingSystem.BuildNumber; Post=$postData.OperatingSystem.BuildNumber}, @{Name="系统厂商"; Pre=$preData.OperatingSystem.Manufacturer; Post=$postData.OperatingSystem.Manufacturer} ) foreach ($item in $osItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # 处理器信息 $processorItems = @( @{Name="处理器ID"; Pre=$preData.Processor.DeviceID; Post=$postData.Processor.DeviceID}, @{Name="处理器名称"; Pre=$preData.Processor.Name; Post=$postData.Processor.Name}, @{Name="处理器描述"; Pre=$preData.Processor.Caption; Post=$postData.Processor.Caption}, @{Name="最大主频"; Pre="$($preData.Processor.MaxClockSpeed) MHz"; Post="$($postData.Processor.MaxClockSpeed) MHz"}, @{Name="插槽类型"; Pre=$preData.Processor.SocketDesignation; Post=$postData.Processor.SocketDesignation}, @{Name="处理器厂商"; Pre=$preData.Processor.Manufacturer; Post=$postData.Processor.Manufacturer} ) foreach ($item in $processorItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # BIOS信息 $biosItems = @( @{Name="BIOS版本"; Pre=$preData.BIOS.SMBIOSBIOSVersion; Post=$postData.BIOS.SMBIOSBIOSVersion}, @{Name="BIOS厂商"; Pre=$preData.BIOS.Manufacturer; Post=$postData.BIOS.Manufacturer}, @{Name="BIOS名称"; Pre=$preData.BIOS.Name; Post=$postData.BIOS.Name}, @{Name="序列号"; Pre=$preData.BIOS.SerialNumber; Post=$postData.BIOS.SerialNumber} ) foreach ($item in $biosItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # 磁盘信息 $diskItems = @( @{Name="盘符"; Pre=$preData.DiskUtilization.Caption; Post=$postData.DiskUtilization.Caption}, @{Name="总容量(GB)"; Pre=$preData.DiskUtilization.SizeGB; Post=$postData.DiskUtilization.SizeGB}, @{Name="可用空间(GB)"; Pre=$preData.DiskUtilization.FreeGB; Post=$postData.DiskUtilization.FreeGB}, @{Name="可用百分比"; Pre="$($preData.DiskUtilization.PercentFree) %"; Post="$($postData.DiskUtilization.PercentFree) %"} ) foreach ($item in $diskItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # 网络信息 $networkItems = @( @{Name="IP地址"; Pre=$preData.Network.IpAddress; Post=$postData.Network.IpAddress}, @{Name="子网掩码"; Pre=$preData.Network.IpSubnet; Post=$postData.Network.IpSubnet}, @{Name="默认网关"; Pre=$preData.Network.DefaultIPgateway; Post=$postData.Network.DefaultIPgateway}, @{Name="DNS服务器"; Pre=$preData.Network.DNSServerSearchOrder; Post=$postData.Network.DNSServerSearchOrder}, @{Name="DHCP启用"; Pre=$preData.Network.DHCPEnabled; Post=$postData.Network.DHCPEnabled}, @{Name="MAC地址"; Pre=$preData.Network.MACAddress; Post=$postData.Network.MACAddress} ) foreach ($item in $networkItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # 服务汇总信息 $serviceSummaryItems = @( @{Name="总服务数"; Pre=$preData.ServicesSummary.TotalServices; Post=$postData.ServicesSummary.TotalServices}, @{Name="运行中服务数"; Pre=$preData.ServicesSummary.Running; Post=$postData.ServicesSummary.Running}, @{Name="已停止服务数"; Pre=$preData.ServicesSummary.Stopped; Post=$postData.ServicesSummary.Stopped} ) foreach ($item in $serviceSummaryItems) { $comparisonRows += New-ComparisonRow -ItemName $item.Name -PreValue $item.Pre -PostValue $item.Post } # 组合所有内容生成HTML $bodyContent = @" <h1>VM迁移前后对比报告 - $($preData.HostName)</h1> <table> <tr> <th>项</th> <th>迁移前详情</th> <th>迁移后详情</th> <th>是否变更</th> </tr> $($comparisonRows -join '') </table> <p><i>报告生成时间: $(Get-Date)</i></p> "@ # 输出最终对比报告 ConvertTo-Html -Head $comparisonHeader -Body $bodyContent | Out-File -FilePath $outputHtmlPath Write-Host "对比报告已生成: $outputHtmlPath"
步骤3:运行脚本生成对比报告
- 迁移前运行修改后的原脚本,生成
PreMigration_前缀的JSON和HTML文件; - 完成VM迁移后,修改原脚本的
$reportPrefix为PostMigration_,再次运行生成迁移后的文件; - 调整对比脚本中的文件路径,指向对应VM的迁移前后JSON文件,运行脚本即可得到带自动变更标记的对比HTML报告。
额外扩展建议
- 如果需要批量处理多个VM,可以修改对比脚本,遍历文件夹中的
PreMigration_和PostMigration_文件,自动配对生成报告; - 若要对比服务详情,可以在对比脚本中扩展逻辑,添加服务列表的对比表格,标记新增、删除或状态变化的服务。
内容的提问来源于stack exchange,提问作者user18863969
相关产品推荐
相关产品推荐

