You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移前后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:运行脚本生成对比报告

  1. 迁移前运行修改后的原脚本,生成PreMigration_前缀的JSON和HTML文件;
  2. 完成VM迁移后,修改原脚本的$reportPrefix为PostMigration_,再次运行生成迁移后的文件;
  3. 调整对比脚本中的文件路径,指向对应VM的迁移前后JSON文件,运行脚本即可得到带自动变更标记的对比HTML报告。

额外扩展建议

  • 如果需要批量处理多个VM,可以修改对比脚本,遍历文件夹中的PreMigration_和PostMigration_文件,自动配对生成报告;
  • 若要对比服务详情,可以在对比脚本中扩展逻辑,添加服务列表的对比表格,标记新增、删除或状态变化的服务。

内容的提问来源于stack exchange,提问作者user18863969

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:07:43