PowerShell Script to Compare Installed Hotfixes Between Two Windows Servers


4 views

When maintaining multiple Windows Server environments, it's crucial to ensure patch consistency between development and production systems. PowerShell provides robust capabilities for comparing installed updates across servers.

The primary cmdlet for this task is Get-HotFix:

# Basic hotfix listing
Get-HotFix | Select-Object HotFixID, InstalledOn, InstalledBy, Description

Here's a complete script to compare hotfixes between two servers:

function Compare-ServerHotfixes {
    param(
        [string]$SourceServer,
        [string]$TargetServer
    )
    
    $sourceHotfixes = Invoke-Command -ComputerName $SourceServer -ScriptBlock {
        Get-HotFix | Select-Object HotFixID
    }
    
    $targetHotfixes = Invoke-Command -ComputerName $TargetServer -ScriptBlock {
        Get-HotFix | Select-Object HotFixID
    }
    
    $missingOnTarget = Compare-Object -ReferenceObject $sourceHotfixes.HotFixID -DifferenceObject $targetHotfixes.HotFixID | 
        Where-Object { $_.SideIndicator -eq '<=' } | Select-Object -ExpandProperty InputObject
    
    $missingOnSource = Compare-Object -ReferenceObject $sourceHotfixes.HotFixID -DifferenceObject $targetHotfixes.HotFixID | 
        Where-Object { $_.SideIndicator -eq '=>' } | Select-Object -ExpandProperty InputObject
    
    [pscustomobject]@{
        SourceServer = $SourceServer
        TargetServer = $TargetServer
        MissingOnTarget = $missingOnTarget
        MissingOnSource = $missingOnSource
    }
}

# Example usage
Compare-ServerHotfixes -SourceServer "DEV-SERVER01" -TargetServer "PROD-SERVER02"

For more detailed analysis, consider these enhancements:

# Include additional hotfix properties
$detailedHotfixes = Get-HotFix | Select-Object HotFixID, Description, InstalledOn, InstalledBy

# Export results to CSV for documentation
Compare-ServerHotfixes -SourceServer "DEV" -TargetServer "PROD" | 
    Export-Csv -Path "HotfixComparison.csv" -NoTypeInformation

# Compare multiple servers
$servers = @("DEV01", "DEV02", "PROD01", "PROD02")
$allHotfixes = @{}
foreach ($server in $servers) {
    $allHotfixes[$server] = Invoke-Command -ComputerName $server -ScriptBlock {
        Get-HotFix | Select-Object HotFixID
    }
}

When dealing with different Windows versions or disconnected environments:

# For disconnected environments (export/import method):
# On source server:
Get-HotFix | Export-Clixml -Path "SourceHotfixes.xml"

# On target server (after transferring the file):
$sourceHotfixes = Import-Clixml -Path "SourceHotfixes.xml"
$localHotfixes = Get-HotFix
Compare-Object -ReferenceObject $sourceHotfixes.HotFixID -DifferenceObject $localHotfixes.HotFixID

Remember that querying hotfix information requires administrative privileges. For domain environments, use proper credential delegation:

$cred = Get-Credential
Invoke-Command -ComputerName "SERVER" -Credential $cred -ScriptBlock {
    Get-HotFix
}

When maintaining multiple Windows servers, particularly in dev/prod environments, it's crucial to ensure patch consistency. Comparing installed hotfixes helps identify missing security updates or potential compatibility issues.

The key cmdlet is Get-HotFix, which retrieves QFE (Quick Fix Engineering) updates. We'll extend this with remote execution capabilities:

# Basic hotfix retrieval
$devHotfixes = Get-HotFix -ComputerName DEV-SERVER01
$prodHotfixes = Get-HotFix -ComputerName PROD-SERVER02

For precise comparison, we'll use the HotFixID property:

# Create hash tables for quick lookup
$devHash = @{}
$devHotfixes | ForEach-Object { $devHash[$_.HotFixID] = $true }

# Find missing hotfixes in production
$missingInProd = $prodHotfixes | Where-Object { -not $devHash.ContainsKey($_.HotFixID) }

# Find extra hotfixes in production
$prodHash = @{}
$prodHotfixes | ForEach-Object { $prodHash[$_.HotFixID] = $true }
$extraInProd = $devHotfixes | Where-Object { -not $prodHash.ContainsKey($_.HotFixID) }

When working across domains or with constrained endpoints:

# Using WinRM for remote execution
$session = New-PSSession -ComputerName DEV-SERVER01 -Credential $cred
$remoteHotfixes = Invoke-Command -Session $session -ScriptBlock { Get-HotFix }

Create actionable reports with detailed patch information:

# Output comparison results
$report = @()
$missingInProd | ForEach-Object {
    $report += [PSCustomObject]@{
        Status = "Missing"
        HotFixID = $_.HotFixID
        Description = $_.Description
        InstalledOn = $_.InstalledOn
    }
}

$extraInProd | ForEach-Object {
    $report += [PSCustomObject]@{
        Status = "Extra" 
        HotFixID = $_.HotFixID
        Description = $_.Description
        InstalledOn = $_.InstalledOn
    }
}

$report | Export-Csv -Path "HotfixComparison.csv" -NoTypeInformation

For environments with dozens of servers, consider this optimized approach:

# Parallel execution with jobs
$servers = "DEV-SERVER01","PROD-SERVER02"
$jobs = @{}

foreach ($server in $servers) {
    $jobs[$server] = Start-Job -ScriptBlock {
        param($computer)
        Get-HotFix -ComputerName $computer
    } -ArgumentList $server
}

# Collect results
$results = @{}
foreach ($server in $servers) {
    $results[$server] = Receive-Job -Job $jobs[$server] | 
        Select-Object HotFixID,Description,InstalledOn
    Remove-Job -Job $jobs[$server]
}

Remember these security aspects when implementing:

  • Use constrained endpoints for remote execution
  • Protect credential information in scripts
  • Validate server names to prevent SSRF attacks
  • Consider using certificate-based authentication