#Requires -RunAsAdministrator <# .SYNOPSIS Compares two Thunderbolt Dock diagnostic JSON files .DESCRIPTION Compares the working HP image configuration with your custom image and highlights all differences with color-coded output. .PARAMETER WorkingImageJson Path to JSON file from the WORKING HP image .PARAMETER CustomImageJson Path to JSON file from your CUSTOM image .EXAMPLE .\Compare-TBConfig.ps1 -WorkingImageJson "C:\Desktop\TB_Dock_Diagnostic_WORKING.json" -CustomImageJson "C:\Desktop\TB_Dock_Diagnostic_CUSTOM.json" #> param( [Parameter(Mandatory=$false)] [string]$WorkingImageJson, [Parameter(Mandatory=$false)] [string]$CustomImageJson ) # If parameters not provided, use file picker Add-Type -AssemblyName System.Windows.Forms if (-not $WorkingImageJson) { Write-Host "Select the JSON file from the WORKING HP Image..." -ForegroundColor Yellow $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog $openFileDialog.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*" $openFileDialog.Title = "Select WORKING HP Image JSON" $openFileDialog.InitialDirectory = [Environment]::GetFolderPath("Desktop") if ($openFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $WorkingImageJson = $openFileDialog.FileName } else { Write-Error "No file selected for Working Image. Exiting." exit } } if (-not $CustomImageJson) { Write-Host "Select the JSON file from your CUSTOM Image..." -ForegroundColor Yellow $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog $openFileDialog.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*" $openFileDialog.Title = "Select CUSTOM Image JSON" $openFileDialog.InitialDirectory = [Environment]::GetFolderPath("Desktop") if ($openFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $CustomImageJson = $openFileDialog.FileName } else { Write-Error "No file selected for Custom Image. Exiting." exit } } # Verify files exist if (-not (Test-Path $WorkingImageJson)) { Write-Error "Working Image JSON not found: $WorkingImageJson" exit } if (-not (Test-Path $CustomImageJson)) { Write-Error "Custom Image JSON not found: $CustomImageJson" exit } # Output file $comparisonReport = "$env:USERPROFILE\Desktop\TB_Comparison_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html" $comparisonText = "$env:USERPROFILE\Desktop\TB_Comparison_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt" Write-Host "`n============================================" -ForegroundColor Cyan Write-Host "THUNDERBOLT DOCK CONFIGURATION COMPARISON" -ForegroundColor Cyan Write-Host "============================================`n" -ForegroundColor Cyan Write-Host "Working Image: " -NoNewline Write-Host $WorkingImageJson -ForegroundColor Green Write-Host "Custom Image: " -NoNewline Write-Host $CustomImageJson -ForegroundColor Yellow Write-Host "" # Load JSON files try { $workingConfig = Get-Content -Path $WorkingImageJson -Raw | ConvertFrom-Json $customConfig = Get-Content -Path $CustomImageJson -Raw | ConvertFrom-Json } catch { Write-Error "Failed to parse JSON files: $_" exit } # Initialize comparison results $differences = @() $criticalDifferences = @() $warnings = @() # Helper function to compare objects recursively function Compare-Objects { param( [Parameter(Mandatory=$true)] $Working, [Parameter(Mandatory=$true)] $Custom, [Parameter(Mandatory=$true)] [string]$Path, [Parameter(Mandatory=$false)] [string]$Level = "INFO" ) $results = @() # Handle null cases if ($null -eq $Working -and $null -eq $Custom) { return $results } if ($null -eq $Working -and $null -ne $Custom) { $results += [PSCustomObject]@{ Path = $Path WorkingValue = "NOT SET" CustomValue = $Custom Level = $Level Message = "Setting exists in Custom but not in Working image" } return $results } if ($null -ne $Working -and $null -eq $Custom) { $results += [PSCustomObject]@{ Path = $Path WorkingValue = $Working CustomValue = "NOT SET" Level = $Level Message = "Setting exists in Working but not in Custom image" } return $results } # Get type $workingType = $Working.GetType().Name $customType = $Custom.GetType().Name # If types differ if ($workingType -ne $customType) { $results += [PSCustomObject]@{ Path = $Path WorkingValue = "$Working ($workingType)" CustomValue = "$Custom ($customType)" Level = "WARNING" Message = "Different data types" } return $results } # Handle different types if ($Working -is [System.Management.Automation.PSCustomObject]) { $workingProps = $Working.PSObject.Properties.Name $customProps = $Custom.PSObject.Properties.Name $allProps = ($workingProps + $customProps) | Select-Object -Unique foreach ($prop in $allProps) { $newPath = if ($Path) { "$Path.$prop" } else { $prop } if ($workingProps -contains $prop -and $customProps -contains $prop) { $results += Compare-Objects -Working $Working.$prop -Custom $Custom.$prop -Path $newPath -Level $Level } elseif ($workingProps -contains $prop) { $results += [PSCustomObject]@{ Path = $newPath WorkingValue = $Working.$prop CustomValue = "MISSING" Level = $Level Message = "Property missing in Custom image" } } else { $results += [PSCustomObject]@{ Path = $newPath WorkingValue = "MISSING" CustomValue = $Custom.$prop Level = $Level Message = "Property missing in Working image" } } } } elseif ($Working -is [Array]) { if ($Working.Count -ne $Custom.Count) { $results += [PSCustomObject]@{ Path = $Path WorkingValue = "Array with $($Working.Count) items" CustomValue = "Array with $($Custom.Count) items" Level = "WARNING" Message = "Different array lengths" } } # Compare array items (simplified - just compare count and first few items) $maxCompare = [Math]::Min($Working.Count, $Custom.Count) for ($i = 0; $i -lt $maxCompare; $i++) { $results += Compare-Objects -Working $Working[$i] -Custom $Custom[$i] -Path "$Path[$i]" -Level $Level } } else { # Simple value comparison if ($Working -ne $Custom) { $results += [PSCustomObject]@{ Path = $Path WorkingValue = $Working CustomValue = $Custom Level = $Level Message = "Values differ" } } } return $results } # Start comparison Write-Host "Comparing configurations..." -ForegroundColor Cyan # Define critical sections with their importance level $criticalSections = @{ 'SpecificPolicies' = 'CRITICAL' 'RegistryKeys' = 'CRITICAL' 'KernelDMAProtection' = 'CRITICAL' 'Services' = 'HIGH' 'BIOS' = 'HIGH' 'ThunderboltControllers' = 'HIGH' 'USB4Routers' = 'HIGH' 'DockNICs' = 'HIGH' 'NetworkAdapters' = 'MEDIUM' 'BitLocker' = 'MEDIUM' 'DeviceGuard' = 'MEDIUM' 'BCDEdit' = 'MEDIUM' 'DriverStore' = 'LOW' 'SystemInfo' = 'INFO' } # Compare each section foreach ($section in $criticalSections.Keys) { if ($workingConfig.PSObject.Properties.Name -contains $section) { Write-Host "Analyzing: $section..." -ForegroundColor Gray $sectionDiffs = Compare-Objects ` -Working $workingConfig.$section ` -Custom $customConfig.$section ` -Path $section ` -Level $criticalSections[$section] if ($sectionDiffs.Count -gt 0) { $differences += $sectionDiffs if ($criticalSections[$section] -eq 'CRITICAL') { $criticalDifferences += $sectionDiffs } elseif ($criticalSections[$section] -in @('HIGH', 'MEDIUM')) { $warnings += $sectionDiffs } } } } # Display results Write-Host "`n============================================" -ForegroundColor Cyan Write-Host "COMPARISON RESULTS" -ForegroundColor Cyan Write-Host "============================================`n" -ForegroundColor Cyan Write-Host "Total Differences Found: " -NoNewline Write-Host $differences.Count -ForegroundColor $(if ($differences.Count -eq 0) { "Green" } else { "Yellow" }) Write-Host "Critical Differences: " -NoNewline Write-Host $criticalDifferences.Count -ForegroundColor $(if ($criticalDifferences.Count -eq 0) { "Green" } else { "Red" }) Write-Host "High/Medium Priority: " -NoNewline Write-Host $warnings.Count -ForegroundColor $(if ($warnings.Count -eq 0) { "Green" } else { "Yellow" }) # Display Critical Differences if ($criticalDifferences.Count -gt 0) { Write-Host "`n`n=== CRITICAL DIFFERENCES (ACTION REQUIRED) ===" -ForegroundColor Red -BackgroundColor Black Write-Host "These settings are most likely causing your issue:`n" -ForegroundColor Red foreach ($diff in $criticalDifferences) { Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Red Write-Host "Path: " -NoNewline Write-Host $diff.Path -ForegroundColor White Write-Host "Working Image: " -NoNewline -ForegroundColor Green Write-Host $diff.WorkingValue -ForegroundColor White Write-Host "Custom Image: " -NoNewline -ForegroundColor Yellow Write-Host $diff.CustomValue -ForegroundColor White Write-Host "Note: $($diff.Message)" -ForegroundColor Gray Write-Host "" } } # Display Warnings if ($warnings.Count -gt 0) { Write-Host "`n`n=== HIGH/MEDIUM PRIORITY DIFFERENCES ===" -ForegroundColor Yellow Write-Host "These may also affect functionality:`n" -ForegroundColor Yellow foreach ($diff in ($warnings | Select-Object -First 20)) { Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Yellow Write-Host "Path: " -NoNewline Write-Host $diff.Path -ForegroundColor White Write-Host "Working Image: " -NoNewline -ForegroundColor Green Write-Host $diff.WorkingValue -ForegroundColor White Write-Host "Custom Image: " -NoNewline -ForegroundColor Yellow Write-Host $diff.CustomValue -ForegroundColor White Write-Host "" } if ($warnings.Count -gt 20) { Write-Host "... and $($warnings.Count - 20) more differences (see full report)" -ForegroundColor Gray } } # Generate HTML Report $htmlContent = @"
Working Image: $WorkingImageJson
Custom Image: $CustomImageJson
Report Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
Focus on fixing these registry keys and policies first.
| Setting Path | Working Image (✓) | Your Custom Image (✗) | Note |
|---|---|---|---|
| $($diff.Path) | $($diff.WorkingValue) | $($diff.CustomValue) | $($diff.Message) |
| Setting Path | Working Image | Custom Image | Note |
|---|---|---|---|
| $($diff.Path) | $($diff.WorkingValue) | $($diff.CustomValue) | $($diff.Message) |
| Setting Path | Working Image | Custom Image | Note |
|---|---|---|---|
| $($diff.Path) | $($diff.WorkingValue) | $($diff.CustomValue) | $($diff.Message) |