Public/Install-WindowsUpdate.ps1

function Install-WindowsUpdate {
    <#
    .SYNOPSIS
    Downloads and installs Windows Updates using the Microsoft Update API.
 
    .DESCRIPTION
    This function uses the Microsoft.Update.Session COM object to search for, download, and install Window # Download u # Download updates
   
    The download process is optimized using BITS (Background Intelligent Transfer Service) with high priority
    and forced execution to bypass throttling, following best practices from the PSWindowsUpdate module.
    It provides comprehensive logging, error handling, and integration with the WindowsUpdateTools module's diagnostic capabilities.
 
    .PARAMETER Criteria
    The search criteria for updates. Default searches for critical updates that are not hidden or already installed.
 
    .PARAMETER AcceptEula
    Automatically accept End User License Agreements for updates that require them.
 
    .PARAMETER IncludeDrivers
    Include driver updates in the search. By default, only software updates are included.
 
    .PARAMETER SuppressReboot
    Suppress automatic reboot even if updates require it. A warning will be logged instead.
 
    .PARAMETER DownloadOnly
    Download updates but do not install them. Updates will be left in a pending state ready for installation.
    Useful for pre-staging updates before a maintenance window.
 
    .PARAMETER UseWindowsUpdate
    Force the use of Windows Update servers instead of WSUS (if configured).
 
    .PARAMETER DownloadPriority
    Sets the BITS download priority (1=Low, 2=Normal, 3=High, 4=ExtraHigh). Default is 4 for fastest downloads.
 
    .PARAMETER DisableForcedDownload
    Disables forced download mode. By default, downloads bypass BITS throttling for faster performance.
 
    .PARAMETER MaxRetries
    Maximum number of retry attempts for downloads that fail. Default is 3.
 
    .PARAMETER RetryDelay
    Delay in seconds between retry attempts. Default is 30 seconds.
 
    .PARAMETER AutoRepair
    Automatically attempt to repair Windows Update issues if installation fails.
    When enabled, will run comprehensive remediation using existing module functions.
 
    .PARAMETER AnalyzeConfiguration
    Performs comprehensive Windows Update configuration analysis without installing updates.
    Shows system information, service status, COM object health, policy settings, and recommendations.
 
    .EXAMPLE
    Install-WindowsUpdate
    Installs all available critical software updates.
 
    .EXAMPLE
    Install-WindowsUpdate -IncludeDrivers -AcceptEula -AutoRepair
    Installs all available updates including drivers, automatically accepting any EULAs and enabling auto-repair.
 
    .EXAMPLE
    Install-WindowsUpdate -Criteria "IsInstalled=0 and Type='Software' and BrowseOnly=0" -SuppressReboot -AutoRepair
    Installs software updates with custom criteria, suppresses automatic reboot, and enables auto-repair on failure.
 
    .EXAMPLE
    Install-WindowsUpdate -DownloadOnly -AcceptEula
    Downloads all available updates without installing them, leaving them in pending state.
 
    .EXAMPLE
    Install-WindowsUpdate -DownloadPriority 2 -DisableForcedDownload
    Installs updates with normal BITS priority and standard throttling (for bandwidth-limited environments).
 
    .EXAMPLE
    Install-WindowsUpdate -AnalyzeConfiguration
    Performs a detailed analysis of the Windows Update environment and provides recommendations.
 
    .OUTPUTS
    System.Object
    Returns an object containing installation results and statistics.
 
    .NOTES
    Requires administrative privileges and the Windows Update service to be available.
    Uses the Microsoft.Update.Session COM object which is part of the Windows Update Agent.
    Provides user-friendly error messages for common Windows Update failures.
     
    Author: CSOLVE Scripts
    Version: 1.5.82
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter()]
        [string]$Criteria = "IsHidden=0 and IsInstalled=0 and Type='Software' and BrowseOnly=0",
        
        [Parameter()]
        [switch]$AcceptEula,
        
        [Parameter()]
        [switch]$IncludeDrivers,
        
        [Parameter()]
        [switch]$SuppressReboot,
        
        [Parameter()]
        [switch]$DownloadOnly,
        
        [Parameter()]
        [switch]$UseWindowsUpdate,
        
        [Parameter()]
        [ValidateRange(1, 4)]
        [int]$DownloadPriority = 4,
        
        [Parameter()]
        [switch]$DisableForcedDownload,
        
        [Parameter()]
        [int]$MaxRetries = 3,
        
        [Parameter()]
        [int]$RetryDelay = 30,
        
        [Parameter()]
        [switch]$AutoRepair,
        
        [Parameter()]
        [switch]$AnalyzeConfiguration
    )

    $result = @{
        Success = $false
        SearchCompleted = $false
        UpdatesFound = 0
        UpdatesDownloaded = 0
        UpdatesInstalled = 0
        UpdatesFailed = 0
        RebootRequired = $false
        Errors = @()
        InstalledUpdates = @()
        FailedUpdates = @()
        Duration = $null
    }

    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

    try {
        # Helper function to get user-friendly HRESULT descriptions
        function Get-WUHResultDescription {
            param($HResult)
            
            # Convert to unsigned 32-bit for lookup
            $unsignedHResult = [UInt32]($HResult -band 0xFFFFFFFF)
            
            switch ($unsignedHResult) {
                0x80240001 { "WU_E_NO_SERVICE - Windows Update Agent was unable to provide the service" }
                0x80240002 { "WU_E_MAX_CAPACITY_REACHED - The maximum capacity of the service was exceeded" }
                0x80240003 { "WU_E_UNKNOWN_ID - An ID cannot be found" }
                0x00240003 { "WU_E_UNKNOWN_ID - An ID cannot be found (success variant)" }
                0x80240004 { "WU_E_NOT_INITIALIZED - The object could not be initialized" }
                0x80240005 { "WU_E_RANGEOVERLAP - The update handler requested a byte range overlapping a previously requested range" }
                0x80240006 { "WU_E_TOOMANYRANGES - The requested number of byte ranges exceeds the maximum number" }
                0x80240007 { "WU_E_INVALIDINDEX - The index to a collection was invalid" }
                0x80240008 { "WU_E_ITEMNOTFOUND - The key for the item queried could not be found" }
                0x80240009 { "WU_E_OPERATIONINPROGRESS - Another conflicting operation was in progress" }
                0x8024000A { "WU_E_COULDNOTCANCEL - Cancellation of the operation was not allowed" }
                0x8024000B { "WU_E_CALL_CANCELLED - Operation was cancelled" }
                0x8024000C { "WU_E_NOUPDATE - Operation tried to add a duplicate item to a list" }
                0x8024000D { "WU_E_INVALIDINSTALLATIONORDER - Could not perform a search for updates" }
                0x8024000E { "WU_E_NOT_ALLOWED - Operation was not allowed" }
                0x80240010 { "WU_E_DUPLICATE_ITEM - Operation tried to add a duplicate item to a list" }
                0x80240011 { "WU_E_INVALID_INSTALL_REQUESTED - Cannot install update because it requires user input" }
                0x80240012 { "WU_E_INSTALL_NOT_ALLOWED - Operation tried to install while another installation was in progress" }
                0x80240013 { "WU_E_NOT_APPLICABLE - Operation was not performed because there are no applicable updates" }
                0x80240016 { "WU_E_DOWNLOAD_FAILED - Operation failed because the download of the update failed" }
                0x80240017 { "WU_E_INSTALL_FAILED - Installation failed for the update" }
                0x80240018 { "WU_E_DOWNLOAD_NOT_ALLOWED - Operation tried to download when downloads are not allowed" }
                0x80240019 { "WU_E_INVALID_UPDATE_TYPE - Operation was not allowed because the update contains invalid metadata" }
                0x8024001A { "WU_E_URL_NOT_FOUND - Operation failed because the URL does not exist" }
                0x8024001B { "WU_E_UNINSTALL_NOT_ALLOWED - Operation could not be completed because the update does not support uninstall" }
                0x8024001C { "WU_E_INVALID_PRODUCT_LICENSE - Search may have missed some updates because the Windows Installer is less than version 3.1" }
                0x8024001D { "WU_E_MISSING_HANDLER - A component required by Windows Update Agent was missing" }
                0x8024001E { "WU_E_LEGACYSERVER - An operation was not completed because it requires a newer version of the server" }
                0x8024001F { "WU_E_BIN_SOURCE_ABSENT - The update's binary source was absent" }
                0x80240020 { "WU_E_SOURCE_ABSENT - The update's source was absent" }
                0x80240021 { "WU_E_WU_DISABLED - Access to Windows Update was disabled" }
                0x80240022 { "WU_E_CALL_CANCELLED_BY_POLICY - Operation was cancelled by Windows Update Agent policy" }
                0x80240023 { "WU_E_INVALID_PROXY_SERVER - The proxy list was invalid" }
                0x80240024 { "WU_E_INVALID_FILE - The file is in the wrong format" }
                0x80240025 { "WU_E_INVALID_CRITERIA - The search criteria string was invalid" }
                0x80240026 { "WU_E_INVALID_LICENSE - License terms could not be downloaded" }
                0x80240027 { "WU_E_INVALID_SERIALNUMBER - The serial number is invalid" }
                0x80240028 { "WU_E_INVALID_VOLUME_LABEL - The volume label is invalid" }
                0x80240029 { "WU_E_INVALID_PRODUCT_LICENSE - Search may have missed some updates because the Windows Installer is less than version 3.1" }
                0x8024002A { "WU_E_UPDATE_NOT_PROCESSED - The update was not processed" }
                0x8024002B { "WU_E_INVALID_OPERATION_FOR_STATE - The operation cannot be performed on a Windows Update Agent if the agent is paused" }
                0x8024002C { "WU_E_INVALID_INSTALL_REQUESTED - The install request is invalid" }
                0x8024002D { "WU_E_INVALID_UNINSTALL_REQUESTED - The uninstall request is invalid" }
                0x8024002E { "WU_E_SHUTDOWN_IN_PROGRESS - Agent is shutting down" }
                0x8024002F { "WU_E_UNEXPECTED - An operation failed due to an unexpected condition" }
                0x80240030 { "WU_E_NETWORK_NOT_AVAILABLE - A network error occurred" }
                0x80240031 { "WU_E_MISSING_METADATA - The metadata for the update was not found" }
                0x80240032 { "WU_E_METADATA_NOT_FOUND - The metadata for the update was not found" }
                0x80240033 { "WU_E_TRANSPORT_ERROR - Agent was unable to download the update" }
                0x80240034 { "WU_E_TIMEOUT - Operation timed out" }
                0x80240035 { "WU_E_INVALID_FILE_FORMAT - The file has an invalid format" }
                0x80240036 { "WU_E_INVALID_SIGNATURE - The signature of the file could not be verified" }
                0x80240037 { "WU_E_INVALID_VOLUMEID - An invalid volume ID was encountered" }
                0x80240038 { "WU_E_OUTOFRANGE - The data is out of range" }
                0x80240039 { "WU_E_INVALIDWUAVERSION - The data contains a version that is not supported" }
                0x8024003A { "WU_E_SEARCH_COMPLETED_WITH_SOME_FAILURES - The search completed successfully but some updates were skipped" }
                0x8024003B { "WU_E_DOWNLOAD_COMPLETED_WITH_SOME_FAILURES - The download completed successfully but some updates failed to download" }
                0x8024003C { "WU_E_WINHTTP_INVALID_FILE - The downloaded file has an unexpected content type" }
                0x8024003D { "WU_E_INVALID_NOTIFICATION_INFO - Invalid notification information was provided" }
                0x8024003E { "WU_E_INVALID_SERIALNUMBER_LICENSE - The serial number specified in the license is invalid" }
                0x8024003F { "WU_E_INVALID_VOLUMEID_LICENSE - The volume ID specified in the license is invalid" }
                0x80240040 { "WU_E_INVALID_PRODUCT_LICENSE_LICENSE - The product license is invalid" }
                0x80240041 { "WU_E_INVALID_PRODUCT_LICENSE_OFFLINE - The product license is not valid for offline installation" }
                0x80240042 { "WU_E_INVALID_PRODUCT_LICENSE_VERSION - The product license version is not supported" }
                0x80240043 { "WU_E_INVALID_PRODUCT_LICENSE_CONTENTS - The product license contents are invalid" }
                0x80240044 { "WU_E_INVALID_PRODUCT_LICENSE_MISSING - The product license is missing required information" }
                0x80070005 { "E_ACCESSDENIED - Access is denied" }
                0x8007000E { "E_OUTOFMEMORY - Ran out of memory" }
                0x80072EE2 { "WININET_E_TIMEOUT - The operation timed out" }
                0x80072EFD { "WININET_E_CANNOT_CONNECT - The attempt to connect to the server failed" }
                0x80072F0D { "WININET_E_INVALID_CA - The function is unfamiliar with the Certificate Authority" }
                0x80072F17 { "WININET_E_SEC_CERT_DATE_INVALID - SSL certificate date is invalid" }
                0x80072F19 { "WININET_E_SEC_CERT_REV_FAILED - SSL certificate revocation check failed" }
                0x80131501 { "Windows Update Agent COM corruption" }
                default { "Unknown error (0x$($unsignedHResult.ToString('X8')))" }
            }
        }
        
        # Configuration Analysis Mode
        if ($AnalyzeConfiguration.IsPresent) {
            Write-WULog "=== WINDOWS UPDATE CONFIGURATION ANALYSIS ===" -Level Info
            Write-WULog "Performing comprehensive pre-requisite checks..." -Level Info
            
            try {
                # 1. System Information
                Write-WULog "--- System Information ---" -Level Info
                $systemInfo = Get-WUSystemInfo
                Write-WULog "Operating System: $($systemInfo.OSVersion)" -Level Info
                Write-WULog "Architecture: $($systemInfo.Architecture)" -Level Info
                Write-WULog "Build Number: $($systemInfo.BuildNumber)" -Level Info
                Write-WULog "Edition: $($systemInfo.Edition)" -Level Info
                
                # 2. Windows Update Configuration
                Write-WULog "--- Windows Update Configuration ---" -Level Info
                $config = Get-WUConfiguration
                if ($config.WSUS) {
                    Write-WULog "WSUS Server: $($config.WSUS.Server)" -Level Info
                    Write-WULog "WSUS Port: $($config.WSUS.Port)" -Level Info
                    Write-WULog "WSUS Status Port: $($config.WSUS.StatusServer)" -Level Info
                } else {
                    Write-WULog "WSUS: Not configured (using Microsoft Update)" -Level Info
                }
                
                if ($config.GroupPolicy) {
                    Write-WULog "Group Policy Settings:" -Level Info
                    foreach ($policy in $config.GroupPolicy.GetEnumerator()) {
                        Write-WULog " $($policy.Key): $($policy.Value)" -Level Info
                    }
                }
                
                # 3. Service Health Check
                Write-WULog "--- Service Health Check ---" -Level Info
                $serviceResults = Test-WUServices -LogPath $logPath
                
                # Display individual service status
                foreach ($service in $serviceResults.Services) {
                    $status = if ($service.Status -eq "Running") { "[OK]" } else { "[FAIL]" }
                    Write-WULog "$status $($service.DisplayName) ($($service.Name)): $($service.Status) (Start Type: $($service.StartType))" -Level Info
                    if ($service.Issues -and $service.Issues.Count -gt 0) {
                        foreach ($issue in $service.Issues) {
                            Write-WULog " Issue: $issue" -Level Warning
                        }
                    }
                }
                
                # 4. COM Object Testing
                Write-WULog "--- COM Object Testing ---" -Level Info
                $comTest = Test-WUCOMObject
                if ($comTest) {
                    Write-WULog "[OK] Windows Update COM objects are functional" -Level Info
                } else {
                    Write-WULog "[FAIL] COM Object Issues Detected" -Level Warning
                }
                
                # 5. System Health Assessment
                Write-WULog "--- System Health Assessment ---" -Level Info
                try {
                    $health = Test-WUSystemHealth -LogPath $logPath
                    if ($health.HealthScore) {
                        Write-WULog "Overall Health Score: $($health.HealthScore)%" -Level Info
                    } else {
                        Write-WULog "Health assessment completed" -Level Info
                    }
                    
                    if ($health.Issues -and $health.Issues.Count -gt 0) {
                        Write-WULog "Issues Detected:" -Level Warning
                        foreach ($issue in $health.Issues) {
                            if ($issue -is [string]) {
                                Write-WULog " [WARNING] $issue" -Level Warning
                            } else {
                                Write-WULog " [WARNING] $($issue.Category): $($issue.Description)" -Level Warning
                                if ($issue.Recommendation) {
                                    Write-WULog " Recommendation: $($issue.Recommendation)" -Level Info
                                }
                            }
                        }
                    } else {
                        Write-WULog "[OK] No issues detected" -Level Info
                    }
                } catch {
                    Write-WULog "System health assessment failed: $($_.Exception.Message)" -Level Error
                    Write-WULog "Stack trace: $($_.ScriptStackTrace)" -Level Debug
                }
                
                # 6. Disk Space Check
                Write-WULog "--- Disk Space Analysis ---" -Level Info
                try {
                    $systemDrive = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $env:SystemDrive }
                    $freeSpaceGB = [math]::Round($systemDrive.FreeSpace / 1GB, 2)
                    $totalSpaceGB = [math]::Round($systemDrive.Size / 1GB, 2)
                    $usedPercentage = [math]::Round(($systemDrive.Size - $systemDrive.FreeSpace) / $systemDrive.Size * 100, 1)
                    
                    Write-WULog "System Drive ($($env:SystemDrive)): $freeSpaceGB GB free of $totalSpaceGB GB ($usedPercentage% used)" -Level Info
                    if ($freeSpaceGB -lt 10) {
                        Write-WULog "[WARNING] Low disk space detected - may impact update installation" -Level Warning
                    }
                } catch {
                    Write-WULog "Could not check disk space: $($_.Exception.Message)" -Level Warning
                }
                
                # 7. Network Connectivity Test
                Write-WULog "--- Network Connectivity Test ---" -Level Info
                try {
                    $testUrls = @(
                        "update.microsoft.com",
                        "windowsupdate.microsoft.com", 
                        "download.microsoft.com"
                    )
                    
                    foreach ($url in $testUrls) {
                        $result = Test-NetConnection -ComputerName $url -Port 443 -InformationLevel Quiet -ErrorAction SilentlyContinue
                        $status = if ($result) { "[OK]" } else { "[FAIL]" }
                        Write-WULog "$status $url connectivity" -Level Info
                    }
                } catch {
                    Write-WULog "Network connectivity test failed: $($_.Exception.Message)" -Level Warning
                }
                
                # 8. Pending Updates Check
                Write-WULog "--- Pending Updates Check ---" -Level Info
                try {
                    $pending = Get-WUPendingUpdates
                    if ($pending -and $pending.Count -gt 0) {
                        Write-WULog "Found $($pending.Count) pending updates:" -Level Info
                        foreach ($update in $pending) {
                            $downloadStatus = if ($update.IsDownloaded) { "Downloaded" } else { "Not Downloaded" }
                            Write-WULog " * $($update.Title) ($($update.SizeMB) MB) - $downloadStatus" -Level Info
                        }
                    } else {
                        Write-WULog "[OK] No pending updates found" -Level Info
                    }
                } catch {
                    Write-WULog "Could not check pending updates: $($_.Exception.Message)" -Level Warning
                }
                
                # 9. Recent Update History
                Write-WULog "--- Recent Update History ---" -Level Info
                try {
                    $history = Get-WUUpdateHistory | Select-Object -First 5
                    if ($history -and $history.Count -gt 0) {
                        Write-WULog "Last 5 update operations:" -Level Info
                        foreach ($item in $history) {
                            Write-WULog " $($item.Date): $($item.Title) - $($item.Result)" -Level Info
                        }
                    } else {
                        Write-WULog "No recent update history found" -Level Info
                    }
                } catch {
                    Write-WULog "Could not retrieve update history: $($_.Exception.Message)" -Level Warning
                }
                
                # 10. Recommendations
                Write-WULog "--- ANALYSIS COMPLETE ---" -Level Info
                Write-WULog "=== RECOMMENDATIONS ===" -Level Info
                
                $recommendations = @()
                
                # Service recommendations
                if ($services) {
                    $stoppedServices = $services | Where-Object { $_.Status -ne "Running" }
                    if ($stoppedServices -and $stoppedServices.Count -gt 0) {
                        $recommendations += "Start stopped Windows Update services: $($stoppedServices.Name -join ', ')"
                    }
                }
                
                # COM object recommendations
                if (-not $comTest) {
                    $recommendations += "Repair Windows Update COM objects using: Invoke-WUComprehensiveRemediation"
                }
                
                # Health recommendations
                if ($health.HealthScore -and $health.HealthScore -lt 80) {
                    $recommendations += "System health score is low ($($health.HealthScore)%) - consider running comprehensive remediation"
                }
                
                # Disk space recommendations
                if ($freeSpaceGB -and $freeSpaceGB -lt 10) {
                    $recommendations += "Free up disk space before installing large updates"
                }
                
                # Policy recommendations
                if ($config.WSUS -and $config.WSUS.Server) {
                    $recommendations += "Verify WSUS server accessibility if updates are failing"
                }
                
                if ($recommendations.Count -gt 0) {
                    foreach ($rec in $recommendations) {
                        Write-WULog "[RECOMMENDATION] $rec" -Level Info
                    }
                } else {
                    Write-WULog "[OK] System appears ready for Windows Update operations" -Level Info
                }
                
                Write-WULog "=== END ANALYSIS ===" -Level Info
                
                # Return analysis results and exit if only analyzing
                $analysisResult = @{
                    Success = $true
                    AnalysisComplete = $true
                    SystemInfo = $systemInfo
                    Configuration = $config
                    Services = $services
                    COMObjects = $comTest
                    SystemHealth = $health
                    Recommendations = $recommendations
                }
                
                return $analysisResult
                
            } catch {
                Write-WULog "Configuration analysis failed: $($_.Exception.Message)" -Level Error
                Write-WULog "Stack trace: $($_.ScriptStackTrace)" -Level Verbose
                return @{
                    Success = $false
                    AnalysisComplete = $false
                    Error = $_.Exception.Message
                }
            }
        }
        
        Write-WULog "Starting Windows Update installation process" -Level Info
        
        # Check if running as administrator
        if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
            throw "This function requires administrative privileges. Please run as administrator."
        }

        # Modify criteria to include drivers if requested
        if ($IncludeDrivers) {
            $Criteria = $Criteria -replace "Type='Software'", "(Type='Software' or Type='Driver')"
            Write-WULog "Including driver updates in search criteria" -Level Info
        }

        Write-WULog "Using search criteria: $Criteria" -Level Info

        # Initialize COM objects
        Write-WULog "Initializing Windows Update Session" -Level Info
        $updateSession = New-Object -ComObject "Microsoft.Update.Session"
        $updateSearcher = $updateSession.CreateUpdateSearcher()
        $updateDownloader = $updateSession.CreateUpdateDownloader()
        $updateInstaller = $updateSession.CreateUpdateInstaller()

        # PATCH: Configure downloader properties immediately after creation (like debug tool)
        # Moving this early prevents COM corruption that occurs when set right before download
        try {
            # CRITICAL: Read current values first to stabilize COM object (like debug tool does)
            $currentPriority = $updateDownloader.Priority
            $currentIsForced = $updateDownloader.IsForced
            Write-WULog "Current downloader state: Priority=$currentPriority, IsForced=$currentIsForced" -Level Verbose
            
            $updateDownloader.Priority = $DownloadPriority    # 1=Low, 2=Normal, 3=High, 4=ExtraHigh
            $updateDownloader.IsForced = -not $DisableForcedDownload.IsPresent     # Force download, bypass BITS throttling
            Write-WULog "Early downloader configuration: Priority=$DownloadPriority, IsForced=$(-not $DisableForcedDownload.IsPresent)" -Level Verbose
        } catch {
            Write-WULog "ERROR: Failed to configure downloader properties: $($_.Exception.Message)" -Level Error
            throw "Failed to configure downloader properties: $($_.Exception.Message)"
        }

        # Configure update source
        if ($UseWindowsUpdate) {
            $updateSearcher.ServerSelection = 2  # Use Microsoft Update servers
            Write-WULog "Configured to use Microsoft Update servers" -Level Info
        } else {
            $updateSearcher.ServerSelection = 0  # Use default (may be WSUS if configured)
            Write-WULog "Using default update server configuration" -Level Info
        }

        # Manage Windows Update service and dependencies
        $wuService = Get-Service -Name "wuauserv" -ErrorAction SilentlyContinue
        if (-not $wuService) {
            throw "Windows Update service (wuauserv) not found"
        }

        # Check related services that may affect downloads
        $bitsService = Get-Service -Name "BITS" -ErrorAction SilentlyContinue
        $cryptsvcService = Get-Service -Name "cryptsvc" -ErrorAction SilentlyContinue
        
        Write-WULog "Service Status Check:" -Level Info
        Write-WULog " Windows Update (wuauserv): $($wuService.Status)" -Level Info
        if ($bitsService) { Write-WULog " BITS: $($bitsService.Status)" -Level Info }
        if ($cryptsvcService) { Write-WULog " Cryptographic Services: $($cryptsvcService.Status)" -Level Info }

        $originalServiceState = $wuService.Status
        $originalStartType = $wuService.StartType

        Write-WULog "Windows Update service state: $originalServiceState, Start type: $originalStartType" -Level Info

        # Ensure required services are running
        if ($wuService.Status -ne "Running") {
            if ($wuService.StartType -eq "Disabled") {
                Write-WULog "Temporarily enabling Windows Update service" -Level Warning
                Set-Service -Name "wuauserv" -StartupType Manual
            }
            
            Write-WULog "Starting Windows Update service" -Level Info
            Start-Service -Name "wuauserv" -ErrorAction Stop
        }
        
        # Ensure BITS is running (required for downloads)
        if ($bitsService -and $bitsService.Status -ne "Running") {
            Write-WULog "Starting BITS service (required for downloads)" -Level Info
            try {
                Start-Service -Name "BITS" -ErrorAction Stop
            } catch {
                Write-WULog "Warning: Could not start BITS service: $($_.Exception.Message)" -Level Warning
            }
        }
        
        # Wait for service to fully start
        $timeout = 30
        $elapsed = 0
        while ((Get-Service -Name "wuauserv").Status -ne "Running" -and $elapsed -lt $timeout) {
            Start-Sleep -Seconds 1
            $elapsed++
        }
        
        if ((Get-Service -Name "wuauserv").Status -ne "Running") {
            throw "Failed to start Windows Update service within $timeout seconds"
        }

        # Test COM object before proceeding
        if (-not (Test-WUCOMObject)) {
            Write-WULog -Level Error -Message "Core Windows Update components are not available. Aborting."
            return
        }

        # Check for Windows Update policies that might interfere
        Write-WULog "=== WINDOWS UPDATE POLICY ANALYSIS ===" -Level Verbose
        
        # Check Group Policy settings that commonly cause 0x80240022
        $policyChecks = @{
            "NoAutoUpdate" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
            "UseWUServer" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
            "WUServer" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
            "WUStatusServer" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
            "DisableWindowsUpdateAccess" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
            "ElevateNonAdmins" = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
        }
        
        foreach ($policyName in $policyChecks.Keys) {
            $regPath = $policyChecks[$policyName]
            try {
                $value = Get-ItemProperty -Path $regPath -Name $policyName -ErrorAction SilentlyContinue
                if ($value) {
                    Write-WULog "POLICY: $policyName = $($value.$policyName) (at $regPath)" -Level Warning
                    
                    # Specific policy warnings
                    switch ($policyName) {
                        "NoAutoUpdate" {
                            if ($value.$policyName -eq 1) {
                                Write-WULog "WARNING: Automatic Updates are disabled by Group Policy" -Level Warning
                            }
                        }
                        "UseWUServer" {
                            if ($value.$policyName -eq 1) {
                                Write-WULog "WARNING: System is configured to use WSUS/internal update server" -Level Warning
                            }
                        }
                        "DisableWindowsUpdateAccess" {
                            if ($value.$policyName -eq 1) {
                                Write-WULog "CRITICAL: Windows Update access is completely disabled by policy!" -Level Error
                            }
                        }
                    }
                }
            } catch {
                # Policy not set, which is normal
            }
        }
        
        # Check if WSUS is configured
        try {
            $wsusServer = Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Name "WUServer" -ErrorAction SilentlyContinue
            if ($wsusServer) {
                Write-WULog "WSUS Server configured: $($wsusServer.WUServer)" -Level Info
            }
        } catch { }
        
        # Check Windows Update service configuration in registry
        try {
            $wuServiceConfig = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\wuauserv" -ErrorAction SilentlyContinue
            if ($wuServiceConfig) {
                Write-WULog "Windows Update service Start type: $($wuServiceConfig.Start)" -Level Verbose
                Write-WULog "Windows Update service Image path: $($wuServiceConfig.ImagePath)" -Level Verbose
            }
        } catch { }

        Write-WULog "=== END POLICY ANALYSIS ===" -Level Verbose

        # Search for updates
        Write-WULog "Searching for updates..." -Level Info
        $searchResult = $updateSearcher.Search($Criteria)
        $result.SearchCompleted = $true
        $result.UpdatesFound = $searchResult.Updates.Count

        Write-WULog "Found $($searchResult.Updates.Count) updates" -Level Info

        if ($searchResult.Updates.Count -eq 0) {
            Write-WULog "No updates found matching the specified criteria" -Level Info
            return $result
        }

        # Process each update
        $updateCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
        $updatesToProcess = @()

        foreach ($update in $searchResult.Updates) {
            $updateInfo = @{
                Title = $update.Title
                Description = $update.Description
                SizeInMB = [math]::Round($update.MaxDownloadSize / 1MB, 2)
                SecurityBulletinIDs = $update.SecurityBulletinIDs
                KBArticleIDs = $update.KBArticleIDs
                Update = $update
            }

            # Handle EULA acceptance
            if (-not $update.EulaAccepted) {
                if ($AcceptEula) {
                    Write-WULog "Accepting EULA for update: $($update.Title)" -Level Warning
                    $update.AcceptEula()
                } else {
                    Write-WULog "Skipping update (EULA not accepted): $($update.Title)" -Level Warning
                    $result.Errors += "EULA not accepted for update: $($update.Title)"
                    continue
                }
            }

            # Check if update requires user input
            if ($update.InstallationBehavior.CanRequestUserInput) {
                Write-WULog "Skipping update (requires user input): $($update.Title)" -Level Warning
                $result.Errors += "Update requires user input: $($update.Title)"
                continue
            }

            $updatesToProcess += $updateInfo
            $updateCollection.Add($update) | Out-Null
        }

        if ($updateCollection.Count -eq 0) {
            Write-WULog "No updates available for installation after filtering" -Level Info
            return $result
        }

        # Download updates
        Write-WULog "Downloading updates..." -Level Info
        $updateDownloader.Updates = $updateCollection
        
        # CRITICAL: Read Updates.Count immediately after assignment to stabilize COM object state
        # This prevents 0x80131501 - the count access "solidifies" the COM object after assignment
        try {
            $updatesCount = $updateDownloader.Updates.Count
            Write-WULog "Successfully assigned $updatesCount updates to downloader" -Level Verbose
        } catch {
            Write-WULog "WARNING: Could not read updates count after assignment - may indicate COM corruption" -Level Warning
        }
        
        # CRITICAL: Call Download() IMMEDIATELY like the working debug tool does
        # Any delay or additional COM interaction corrupts the object state
        Write-WULog "IMMEDIATE DOWNLOAD: Calling Download() method now (debug tool pattern)..." -Level Verbose
        try {
            $downloadResult = $updateDownloader.Download()
            Write-WULog "SUCCESS: Download() method completed!" -Level Info
            Write-WULog "Download ResultCode: $($downloadResult.ResultCode)" -Level Info
            
            # Detailed download result code interpretation
            $downloadResultCodeMeaning = switch ($downloadResult.ResultCode) {
                0 { "Not Started" }
                1 { "In Progress" }
                2 { "Succeeded" }
                3 { "Succeeded with Errors" }
                4 { "Failed" }
                5 { "Aborted" }
                default { "Unknown ($($downloadResult.ResultCode))" }
            }
            Write-WULog "Download result meaning: $downloadResultCodeMeaning" -Level Info
            
            # Check if we can access download HResult for failure details
            try {
                Write-WULog "Download HRESULT: 0x$($downloadResult.HResult.ToString('X8'))" -Level Verbose
            } catch {
                Write-WULog "Download HRESULT: Not available ($($_.Exception.Message))" -Level Verbose
            }
            
            # If download failed, get details about each update's download result
            if ($downloadResult.ResultCode -eq 4) {
                Write-WULog "=== DOWNLOAD FAILURE ANALYSIS ===" -Level Error
                for ($i = 0; $i -lt $downloadResult.GetUpdateResult.Count; $i++) {
                    $updateDownloadResult = $downloadResult.GetUpdateResult($i)
                    $update = $updateCollection.Item($i)
                    Write-WULog "Update $($i + 1): $($update.Title)" -Level Error
                    Write-WULog " Download Result Code: $($updateDownloadResult.ResultCode)" -Level Error
                    Write-WULog " Download HRESULT: 0x$($updateDownloadResult.HResult.ToString('X8'))" -Level Error
                    
                    # Get user-friendly error description for download failure
                    $downloadErrorDescription = Get-WUHResultDescription -HResult $updateDownloadResult.HResult
                    Write-WULog " Download Error: $downloadErrorDescription" -Level Error
                }
            }
            
            # If download succeeded with errors, analyze which updates had issues
            if ($downloadResult.ResultCode -eq 3) {
                Write-WULog "=== DOWNLOAD SUCCEEDED WITH ERRORS ANALYSIS ===" -Level Warning
                for ($i = 0; $i -lt $downloadResult.GetUpdateResult.Count; $i++) {
                    $updateDownloadResult = $downloadResult.GetUpdateResult($i)
                    $update = $updateCollection.Item($i)
                    
                    $downloadResultMeaning = switch ($updateDownloadResult.ResultCode) {
                        0 { "Not Started" }
                        1 { "In Progress" }
                        2 { "Succeeded" }
                        3 { "Succeeded with Errors" }
                        4 { "Failed" }
                        5 { "Aborted" }
                        default { "Unknown ($($updateDownloadResult.ResultCode))" }
                    }
                    
                    Write-WULog "Update $($i + 1): $($update.Title)" -Level Warning
                    Write-WULog " Individual Download Result: $($updateDownloadResult.ResultCode) ($downloadResultMeaning)" -Level Warning
                    Write-WULog " Individual Download HRESULT: 0x$($updateDownloadResult.HResult.ToString('X8'))" -Level Warning
                    Write-WULog " Is Downloaded: $($update.IsDownloaded)" -Level Warning
                    
                    if ($updateDownloadResult.HResult -ne 0) {
                        $downloadErrorDescription = Get-WUHResultDescription -HResult $updateDownloadResult.HResult
                        Write-WULog " Download Issue: $downloadErrorDescription" -Level Warning
                    }
                }
            }
            
        } catch {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
            Write-WULog "ERROR: Download failed with HResult: $hresult" -Level Error
            Write-WULog "ERROR: Exception: $($_.Exception.Message)" -Level Error
            throw "Download failed: $($_.Exception.Message)"
        }

        $result.UpdatesDownloaded = $updateCollection.Count
        
        # If DownloadOnly is specified, skip installation
        if ($DownloadOnly) {
            Write-WULog "DownloadOnly mode: Skipping installation. $($updateCollection.Count) update(s) downloaded and pending." -Level Info
            $result.Success = $true
            
            # Report download sizes
            $totalDownloadedMB = 0
            for ($i = 0; $i -lt $updateCollection.Count; $i++) {
                $update = $updateCollection.Item($i)
                $sizeMB = [math]::Round($update.MaxDownloadSize / 1MB, 2)
                $totalDownloadedMB += $sizeMB
                Write-WULog " Downloaded: $($update.Title) ($sizeMB MB)" -Level Info
            }
            Write-WULog "Total downloaded: $([math]::Round($totalDownloadedMB, 2)) MB" -Level Info
            Write-WULog "Updates are now in pending state and ready for installation" -Level Info
            
            $stopwatch.Stop()
            $result.Duration = $stopwatch.Elapsed
            return $result
        }


        # Install updates
        if ($PSCmdlet.ShouldProcess("$($updateCollection.Count) Windows Updates", "Install")) {
            # Skip download validation if we just completed a successful download
            # The IsDownloaded property can be unreliable immediately after download completion
            if ($downloadResult.ResultCode -eq 2) {
                Write-WULog "Skipping download validation - download completed successfully" -Level Verbose
            } elseif ($downloadResult.ResultCode -eq 3) {
                Write-WULog "Download completed with errors - validating individual update download status..." -Level Warning
                $notDownloaded = @()
                for ($i = 0; $i -lt $updateCollection.Count; $i++) {
                    $update = $updateCollection.Item($i)
                    if (-not $update.IsDownloaded) {
                        $notDownloaded += $update.Title
                        Write-WULog "Update not downloaded: $($update.Title)" -Level Warning
                    } else {
                        Write-WULog "Update successfully downloaded: $($update.Title)" -Level Verbose
                    }
                }
                
                if ($notDownloaded.Count -gt 0) {
                    $errorMsg = "Cannot install updates that are not fully downloaded: $($notDownloaded -join ', ')"
                    Write-WULog $errorMsg -Level Error
                    $result.Errors += $errorMsg
                    throw $errorMsg
                }
            } else {
                # Only validate if download didn't complete successfully
                Write-WULog "Validating download status before installation..." -Level Verbose
                $notDownloaded = @()
                for ($i = 0; $i -lt $updateCollection.Count; $i++) {
                    $update = $updateCollection.Item($i)
                    if (-not $update.IsDownloaded) {
                        $notDownloaded += $update.Title
                    }
                }
                
                if ($notDownloaded.Count -gt 0) {
                    $errorMsg = "Cannot install updates that are not fully downloaded: $($notDownloaded -join ', ')"
                    Write-WULog $errorMsg -Level Error
                    $result.Errors += $errorMsg
                    throw $errorMsg
                }
            }
            
            Write-WULog "Installing $($updateCollection.Count) updates..." -Level Info
            $updateInstaller.Updates = $updateCollection
            
            try {
                # Pre-installation debugging
                Write-WULog "=== PRE-INSTALLATION DEBUG ===" -Level Verbose
                Write-WULog "DEBUG: Update installer object type: $($updateInstaller.GetType().FullName)" -Level Verbose
                Write-WULog "DEBUG: Update collection count: $($updateCollection.Count)" -Level Verbose
                Write-WULog "DEBUG: Updates to install: $($updateCollection.Count)" -Level Verbose
                
                # Check each update's state before installation
                for ($i = 0; $i -lt $updateCollection.Count; $i++) {
                    $update = $updateCollection.Item($i)
                    Write-WULog "DEBUG: Pre-install Update $($i + 1): $($update.Title)" -Level Verbose
                    Write-WULog "DEBUG: IsDownloaded: $($update.IsDownloaded)" -Level Verbose
                    Write-WULog "DEBUG: IsInstalled: $($update.IsInstalled)" -Level Verbose
                    Write-WULog "DEBUG: Size: $([math]::Round($update.MaxDownloadSize / 1MB, 2)) MB" -Level Verbose
                    Write-WULog "DEBUG: IsMandatory: $($update.IsMandatory)" -Level Verbose
                    Write-WULog "DEBUG: RebootRequired: $($update.RebootRequired)" -Level Verbose
                    Write-WULog "DEBUG: IsHidden: $($update.IsHidden)" -Level Verbose
                    Write-WULog "DEBUG: IsUninstallable: $($update.IsUninstallable)" -Level Verbose
                    if ($update.BundledUpdates.Count -gt 0) {
                        Write-WULog "DEBUG: Bundled updates: $($update.BundledUpdates.Count)" -Level Verbose
                    }
                }
                
                # Check installer properties
                Write-WULog "DEBUG: Installer AllowSourcePrompts: $($updateInstaller.AllowSourcePrompts)" -Level Verbose
                Write-WULog "DEBUG: Installer ClientApplicationID: $($updateInstaller.ClientApplicationID)" -Level Verbose
                Write-WULog "DEBUG: Installer ForceQuiet: $($updateInstaller.ForceQuiet)" -Level Verbose
                Write-WULog "DEBUG: Installer IsBusy: $($updateInstaller.IsBusy)" -Level Verbose
                Write-WULog "DEBUG: Installer ParentHwnd: $($updateInstaller.ParentHwnd)" -Level Verbose
                Write-WULog "DEBUG: Installer ParentWindow: $($updateInstaller.ParentWindow)" -Level Verbose
                
                Write-WULog "=== STARTING INSTALLATION ===" -Level Verbose
                
                # Start installation with progress monitoring (direct execution - no background job)
                $installStartTime = Get-Date
                Write-Progress -Activity "Installing Windows Updates" -Status "Starting installation..." -PercentComplete 0
                Write-WULog "Starting installation..." -Level Info
                
                # Execute installation directly (COM objects can't be serialized to background jobs)
                Write-WULog "DEBUG: Calling updateInstaller.Install() now..." -Level Verbose
                $installResult = $updateInstaller.Install()
                Write-WULog "DEBUG: updateInstaller.Install() returned" -Level Verbose
                
                # Check if installation got stuck in "In Progress" state
                if ($installResult.ResultCode -eq 1) {
                    Write-WULog "WARNING: Installation returned 'In Progress' status - this may indicate a stuck installation" -Level Warning
                    Write-WULog "DEBUG: Waiting 30 seconds to see if installation completes..." -Level Verbose
                    Start-Sleep -Seconds 30
                    
                    # Check if it's still in progress after waiting
                    if ($installResult.ResultCode -eq 1) {
                        Write-WULog "ERROR: Installation appears to be stuck in 'In Progress' state after 30 seconds" -Level Error
                        Write-WULog "This often indicates policy interference or Windows Update Agent corruption" -Level Error
                    }
                }
                
                Write-Progress -Activity "Installing Windows Updates" -Status "Installation completed" -PercentComplete 100
                Write-Progress -Activity "Installing Windows Updates" -Completed
                
                $installEndTime = Get-Date
                $installDuration = $installEndTime - $installStartTime
                Write-WULog "Installation completed in $($installDuration.ToString('mm\:ss'))" -Level Info
                
                # Debug installation result object
                Write-WULog "=== POST-INSTALLATION DEBUG ===" -Level Verbose
                Write-WULog "Installation result object type: $($installResult.GetType().FullName)" -Level Verbose
                Write-WULog "Installation result code: $($installResult.ResultCode)" -Level Verbose
                
                # Detailed result code interpretation
                $installResultCodeMeaning = switch ($installResult.ResultCode) {
                    0 { "Not Started" }
                    1 { "In Progress" }
                    2 { "Succeeded" }
                    3 { "Succeeded with Errors" }
                    4 { "Failed" }
                    5 { "Aborted" }
                    default { "Unknown ($($installResult.ResultCode))" }
                }
                Write-WULog "Installation result meaning: $installResultCodeMeaning" -Level Verbose
                
                # Special handling for policy cancellation error
                if ($installResult.ResultCode -eq 4 -and $installResult.HResult -eq -2145124318) {
                    Write-WULog "=== POLICY CANCELLATION DETECTED ===" -Level Error
                    Write-WULog "Installation was cancelled by Windows Update policy (0x80240022)" -Level Error
                    Write-WULog "This typically means:" -Level Error
                    Write-WULog " 1. Group Policy is blocking Windows Update installation" -Level Error
                    Write-WULog " 2. WSUS is configured but not accessible" -Level Error
                    Write-WULog " 3. Windows Update service policies are restricting operations" -Level Error
                    Write-WULog " 4. Third-party software is interfering with Windows Update" -Level Error
                    Write-WULog "Check the policy analysis above for specific policy conflicts" -Level Error
                }
                
                Write-WULog "Number of update results: $($installResult.GetUpdateResult.Count)" -Level Verbose
                Write-WULog "Reboot required: $($installResult.RebootRequired)" -Level Verbose
                
                # Check if we can access HResult
                try {
                    Write-WULog "Installation HRESULT: 0x$($installResult.HResult.ToString('X8'))" -Level Verbose
                } catch {
                    Write-WULog "Installation HRESULT: Not available ($($_.Exception.Message))" -Level Verbose
                }
                
                Write-WULog "=== PROCESSING UPDATE RESULTS ===" -Level Verbose
                
                # Process installation results
                for ($i = 0; $i -lt $installResult.GetUpdateResult.Count; $i++) {
                    $updateResult = $installResult.GetUpdateResult($i)
                    $update = $updateCollection.Item($i)
                    
                    Write-WULog "Processing update $($i + 1): $($update.Title)" -Level Verbose
                    Write-WULog "Update result code: $($updateResult.ResultCode)" -Level Verbose
                    
                    # Detailed update result code interpretation
                    $updateResultCodeMeaning = switch ($updateResult.ResultCode) {
                        0 { "Not Started" }
                        1 { "In Progress" }
                        2 { "Succeeded" }
                        3 { "Succeeded with Errors" }
                        4 { "Failed" }
                        5 { "Aborted" }
                        default { "Unknown ($($updateResult.ResultCode))" }
                    }
                    Write-WULog "Update result meaning: $updateResultCodeMeaning" -Level Verbose
                    Write-WULog "Update HRESULT: 0x$($updateResult.HResult.ToString('X8'))" -Level Verbose
                    Write-WULog "Update restart required: $($updateResult.RestartRequired)" -Level Verbose
                    
                    # Check post-installation state
                    Write-WULog "DEBUG: Post-install IsDownloaded: $($update.IsDownloaded)" -Level Verbose
                    Write-WULog "DEBUG: Post-install IsInstalled: $($update.IsInstalled)" -Level Verbose
                    
                    $updateStatus = @{
                        Title = $update.Title
                        ResultCode = $updateResult.ResultCode
                        HResult = $updateResult.HResult
                        RestartRequired = $updateResult.RestartRequired
                    }

                    switch ($updateResult.ResultCode) {
                        1 { # In Progress
                            Write-WULog "WARNING: Installation reports 'In Progress' for: $($update.Title)" -Level Warning
                            Write-WULog "DEBUG: This should not happen in synchronous mode - indicates a stuck installation" -Level Warning
                            Write-WULog "DEBUG: Overall installation HRESULT was: 0x$($installResult.HResult.ToString('X8'))" -Level Warning
                            Write-WULog "DEBUG: Update IsDownloaded after install attempt: $($update.IsDownloaded)" -Level Warning
                            Write-WULog "DEBUG: Update IsInstalled after install attempt: $($update.IsInstalled)" -Level Warning
                            
                            # Check if this correlates with policy cancellation
                            if ($installResult.HResult -eq -2145124318) {
                                Write-WULog "ANALYSIS: 'In Progress' state caused by policy cancellation (0x80240022)" -Level Error
                                Write-WULog "The installation was cancelled by Group Policy before it could complete" -Level Error
                            } else {
                                Write-WULog "ANALYSIS: 'In Progress' state with unexpected overall HRESULT" -Level Warning
                                Write-WULog "This may indicate Windows Update Agent corruption or service issues" -Level Warning
                            }
                            
                            $result.Errors += "Installation stuck in 'In Progress' state for: $($update.Title) - likely policy interference or corruption"
                            # Don't count as installed - this is an error condition
                        }
                        2 { # Succeeded
                            # CRITICAL VALIDATION: Verify the update is actually installed
                            # Some installations report "Succeeded" but don't actually install
                            if ($update.IsInstalled -eq $true) {
                                $result.UpdatesInstalled++
                                $result.InstalledUpdates += $updateStatus
                                Write-WULog "Successfully installed: $($update.Title)" -Level Info
                            } else {
                                # FAKE SUCCESS DETECTION: Installation claimed success but update not installed
                                Write-WULog "CRITICAL: Installation reported SUCCESS but update is NOT INSTALLED!" -Level Error
                                Write-WULog "Title: $($update.Title)" -Level Error
                                Write-WULog "ResultCode: $($updateResult.ResultCode) (Succeeded)" -Level Error
                                Write-WULog "IsInstalled: $($update.IsInstalled) (FALSE - should be TRUE)" -Level Error
                                Write-WULog "HRESULT: 0x$($updateResult.HResult.ToString('X8'))" -Level Error
                                
                                # Additional diagnostics for fake success
                                Write-WULog "DIAGNOSIS: This is a 'fake success' - possible causes:" -Level Warning
                                Write-WULog " 1. Windows Update Agent corruption" -Level Warning
                                Write-WULog " 2. Policy interference after installation started" -Level Warning
                                Write-WULog " 3. Insufficient permissions or service issues" -Level Warning
                                Write-WULog " 4. Component store corruption preventing final commit" -Level Warning
                                
                                # Check for specific error patterns
                                if ($updateResult.HResult -ne 0) {
                                    Write-WULog "Non-zero HRESULT suggests underlying issue: 0x$($updateResult.HResult.ToString('X8'))" -Level Error
                                }
                                
                                $result.UpdatesFailed++
                                $result.FailedUpdates += $updateStatus
                                $result.Errors += "FAKE SUCCESS: $($update.Title) - Installation reported success but update not installed (possible corruption or policy interference)"
                                
                                # Mark overall operation as failed due to fake success
                                $result.Success = $false
                            }
                        }
                        3 { # Succeeded with errors
                            $result.UpdatesInstalled++
                            $result.InstalledUpdates += $updateStatus
                            Write-WULog "Installed with errors: $($update.Title)" -Level Warning
                        }
                        4 { # Failed
                            $result.UpdatesFailed++
                            $result.FailedUpdates += $updateStatus
                            
                            # Get user-friendly error description
                            $errorDescription = Get-WUHResultDescription -HResult $updateResult.HResult
                            Write-WULog "Failed to install: $($update.Title) - $errorDescription" -Level Error
                            $result.Errors += "Failed to install: $($update.Title) - $errorDescription"
                        }
                        5 { # Aborted
                            $result.UpdatesFailed++
                            $result.FailedUpdates += $updateStatus
                            Write-WULog "Installation aborted: $($update.Title)" -Level Error
                            $result.Errors += "Installation aborted: $($update.Title)"
                        }
                        default {
                            Write-WULog "Unknown result code $($updateResult.ResultCode) for: $($update.Title)" -Level Warning
                            Write-WULog "DEBUG: This is result code 0 - indicating installation never started or was aborted" -Level Warning
                            Write-WULog "DEBUG: HRESULT details: 0x$($updateResult.HResult.ToString('X8'))" -Level Warning
                            Write-WULog "DEBUG: This suggests a fundamental issue preventing installation from starting" -Level Warning
                            
                            # Treat as failed
                            $result.UpdatesFailed++
                            $result.FailedUpdates += $updateStatus
                            $result.Errors += "Installation failed to start for: $($update.Title) (Result code $($updateResult.ResultCode), HRESULT: 0x$($updateResult.HResult.ToString('X8')))"
                        }
                    }

                    if ($updateResult.RestartRequired) {
                        $result.RebootRequired = $true
                    }
                }

                # Handle reboot requirement and set success status
                if ($result.RebootRequired) {
                    if ($SuppressReboot) {
                        Write-WULog "Updates installed successfully but a restart is required. Restart has been suppressed." -Level Warning
                    } else {
                        Write-WULog "Updates installed successfully. A restart is required and will be initiated." -Level Warning
                        # Note: In a real implementation, you might want to integrate with your module's reboot handling
                        # For now, we'll just log the requirement
                    }
                } else {
                    Write-WULog "Updates installed successfully. No restart required." -Level Info
                }
                
        # CRITICAL: Final validation - detect any remaining fake successes
        Write-WULog "=== FINAL INSTALLATION VALIDATION ===" -Level Verbose
        Write-WULog "Performing post-installation verification..." -Level Info
        
        $actuallyInstalled = 0
        $fakeSuccesses = 0
        
        foreach ($updateInfo in $updatesToProcess) {
            $originalUpdate = $updateInfo.Update
            try {
                # Re-check installation status after claimed success
                $isActuallyInstalled = $originalUpdate.IsInstalled
                Write-WULog "Final check - $($originalUpdate.Title): IsInstalled = $isActuallyInstalled" -Level Verbose
                
                if ($isActuallyInstalled) {
                    $actuallyInstalled++
                    
                    # Microsoft-recommended pattern: Verify installation depth
                    # Check if bundled updates were also properly installed
                    if ($originalUpdate.BundledUpdates.Count -gt 0) {
                        Write-WULog "Verifying $($originalUpdate.BundledUpdates.Count) bundled updates for: $($originalUpdate.Title)" -Level Verbose
                        $bundledFailed = 0
                        for ($b = 0; $b -lt $originalUpdate.BundledUpdates.Count; $b++) {
                            $bundledUpdate = $originalUpdate.BundledUpdates.Item($b)
                            if (-not $bundledUpdate.IsInstalled) {
                                $bundledFailed++
                                Write-WULog "Bundled update not installed: $($bundledUpdate.Title)" -Level Warning
                            }
                        }
                        if ($bundledFailed -gt 0) {
                            Write-WULog "WARNING: Main update installed but $bundledFailed bundled updates failed" -Level Warning
                        }
                    }
                } else {
                    $fakeSuccesses++
                    Write-WULog "CONFIRMED FAKE SUCCESS: $($originalUpdate.Title) - not actually installed despite success report" -Level Error
                    
                    # Microsoft-pattern: Additional validation for complex updates
                    # Check if this is a superseded update (common cause of fake success)
                    try {
                        if ($originalUpdate.IsSuperseded) {
                            Write-WULog "ANALYSIS: Update was superseded during installation - this may explain the fake success" -Level Warning
                        }
                    } catch { }
                }
            } catch {
                Write-WULog "Could not verify final installation status for: $($originalUpdate.Title) - $($_.Exception.Message)" -Level Warning
                
                # Microsoft-pattern: Attempt alternative verification
                try {
                    # Re-search for the update to see if it's still available (indicating not installed)
                    Write-WULog "Attempting alternative verification via re-search..." -Level Verbose
                    $verificationSearcher = $updateSession.CreateUpdateSearcher()
                    $verificationCriteria = "UpdateID='$($originalUpdate.Identity.UpdateID)' and IsInstalled=0"
                    $verificationResult = $verificationSearcher.Search($verificationCriteria)
                    
                    if ($verificationResult.Updates.Count -gt 0) {
                        Write-WULog "Alternative verification: Update still appears as not installed" -Level Warning
                        $fakeSuccesses++
                    } else {
                        Write-WULog "Alternative verification: Update no longer appears in not-installed search" -Level Verbose
                        $actuallyInstalled++
                    }
                } catch {
                    Write-WULog "Alternative verification failed: $($_.Exception.Message)" -Level Verbose
                }
            }
        }
        
        Write-WULog "Installation validation complete:" -Level Info
        Write-WULog " Updates actually installed: $actuallyInstalled" -Level Info
        Write-WULog " Fake successes detected: $fakeSuccesses" -Level Info
        
        if ($fakeSuccesses -gt 0) {
            Write-WULog "CRITICAL: $fakeSuccesses fake success(es) detected!" -Level Error
            Write-WULog "This indicates Windows Update API integrity issues." -Level Error
            Write-WULog "" -Level Info
            Write-WULog "Microsoft-recommended remediation steps:" -Level Warning
            Write-WULog " 1. Policy Analysis: Check for Group Policy conflicts blocking final installation commit" -Level Warning
            Write-WULog " 2. Component Store: Run 'dism /online /cleanup-image /restorehealth' as Administrator" -Level Warning
            Write-WULog " 3. Update Agent: Reset Windows Update components using 'Repair-WindowsUpdate'" -Level Warning
            Write-WULog " 4. Service Health: Verify Windows Update service and dependencies are functioning" -Level Warning
            Write-WULog " 5. Registry Integrity: Check for corrupted Windows Update registry keys" -Level Warning
            Write-WULog " 6. Event Logs: Review Windows Update logs in Event Viewer for detailed errors" -Level Warning
            Write-WULog "" -Level Info
            Write-WULog "Based on Microsoft documentation patterns, fake successes commonly indicate:" -Level Info
            Write-WULog " - Group Policy preventing final installation commit after download/prepare phases" -Level Info
            Write-WULog " - Windows Update Agent COM object corruption requiring service reset" -Level Info
            Write-WULog " - Component Store corruption preventing update registration" -Level Info
            Write-WULog " - Insufficient system resources during final installation phase" -Level Info
            
            # Check if this appears to be Group Policy interference
            $groupPolicyDetected = $false
            try {
                $auPolicy = Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "NoAutoUpdate" -ErrorAction SilentlyContinue
                if ($auPolicy -and $auPolicy.NoAutoUpdate -eq 1) {
                    $groupPolicyDetected = $true
                    Write-WULog "" -Level Info
                    Write-WULog "GROUP POLICY INTERFERENCE DETECTED!" -Level Warning
                    Write-WULog "Automatic updates are disabled via Group Policy, which can cause fake successes." -Level Warning
                    Write-WULog "The installation API can download and prepare updates but policy blocks final commit." -Level Warning
                    Write-WULog "" -Level Info
                    Write-WULog "SOLUTION: Use 'Repair-WindowsUpdate -GroupPolicy' to temporarily allow installations:" -Level Info
                    Write-WULog " 1. Repair-WindowsUpdate -GroupPolicy # Temporarily allow updates and create backup" -Level Info
                    Write-WULog " 2. Install-WindowsUpdate # Install updates" -Level Info
                    Write-WULog " 3. reg import <backup_file> # Restore policies (path shown in repair output)" -Level Info
                }
            } catch { }
            
            # Override success status if fake successes detected (Microsoft pattern: strict validation)
            if ($result.Success -and $fakeSuccesses -gt 0) {
                $result.Success = $false
                Write-WULog "Installation marked as FAILED due to fake success detection (following Microsoft validation standards)" -Level Error
                
                # Add specific remediation suggestion to result
                if ($groupPolicyDetected) {
                    $result.Errors += "FAKE SUCCESS due to Group Policy interference - Use 'Repair-WindowsUpdate -GroupPolicy' to temporarily allow installations"
                } else {
                    $result.Errors += "FAKE SUCCESS detected - Installation API reported success but updates not actually installed"
                }
            }
        } else {
            Write-WULog "Installation validation successful: All claimed successes verified as genuine" -Level Info
        }

        # Set success status based on whether any updates were installed or if there were critical errors
        if ($result.UpdatesInstalled -gt 0 -or ($result.UpdatesFound -eq 0 -and $result.Errors.Count -eq 0)) {
            $result.Success = $true
            Write-WULog "Installation operation completed successfully" -Level Info
        } else {
            # Check if "In Progress" errors are due to pending reboot (common and normal)
            $inProgressErrors = $result.Errors | Where-Object { $_ -like "*In Progress*" }
            $hasRebootRequired = $result.RebootRequired -or $installResult.RebootRequired
            
            if ($inProgressErrors.Count -gt 0 -and $hasRebootRequired) {
                Write-WULog "Installation shows 'In Progress' but reboot is required - this is normal, not an error" -Level Info
                $result.Success = $true
                Write-WULog "Installation operation completed successfully (pending reboot)" -Level Info
            } else {
                $result.Success = $false
                
                if ($AutoRepair) {
                    Write-WULog "Installation operation completed with errors - initiating automatic repair" -Level Warning
                    $repairResults = Invoke-WUAutoRepair -Errors $result.Errors
                    $result.Errors += $repairResults
                } else {
                    Write-WULog "Installation operation completed with errors. Use -AutoRepair to attempt automatic remediation." -Level Warning
                }
            }
        }
        } catch {
            Write-WULog "=== INSTALLATION EXCEPTION CAUGHT ===" -Level Error
            Write-WULog "Exception type: $($_.Exception.GetType().FullName)" -Level Error
            Write-WULog "Exception message: $($_.Exception.Message)" -Level Error
            Write-WULog "Exception HRESULT: 0x$($_.Exception.HResult.ToString('X8'))" -Level Error
            Write-WULog "Exception at: $($_.InvocationInfo.ScriptLineNumber):$($_.InvocationInfo.OffsetInLine)" -Level Error
            
            if ($_.Exception.HResult -eq -2145124330) {
                # WU_E_INSTALL_NOT_ALLOWED
                $errorMsg = Get-WUHResultDescription -HResult $_.Exception.HResult
                Write-WULog $errorMsg -Level Error
                $result.Errors += $errorMsg
            } else {
                $errorDescription = Get-WUHResultDescription -HResult $_.Exception.HResult
                Write-WULog $errorDescription -Level Error
                $result.Errors += $errorDescription
                throw
            }
        }
        }

    } catch {
        # This is the top-level catch block. It ensures a friendly message is always logged.
        $errorMessage = if ($_) {
            if ($_.Exception -and $_.Exception.HResult -ne 0) {
                Get-WUHResultDescription -HResult $_.Exception.HResult
            } else {
                # If a string was thrown, use it directly.
                "Windows Update installation failed: $_"
            }
        } else {
            "An unknown error occurred during Windows Update installation."
        }
        
        Write-WULog $errorMessage -Level Error
        $result.Errors += $errorMessage
        # We do not re-throw here, allowing the 'finally' block to run and return the results object.
    } finally {
        # Restore original service state
        try {
            $currentService = Get-Service -Name "wuauserv" -ErrorAction SilentlyContinue
            if ($currentService -and $originalServiceState -eq "Stopped") {
                Write-WULog "Restoring Windows Update service to original state" -Level Info
                Set-Service -Name "wuauserv" -StartupType $originalStartType
                Stop-Service -Name "wuauserv" -Force -ErrorAction SilentlyContinue
            }
        } catch {
            Write-WULog "Warning: Could not restore original Windows Update service state: $($_.Exception.Message)" -Level Warning
        }

        # Clean up COM objects
        try {
            if ($updateInstaller) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateInstaller) | Out-Null }
            if ($updateDownloader) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateDownloader) | Out-Null }
            if ($updateSearcher) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateSearcher) | Out-Null }
            if ($updateSession) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateSession) | Out-Null }
            if ($updateCollection) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateCollection) | Out-Null }
        } catch {
            # Ignore COM cleanup errors
        }

        $stopwatch.Stop()
        
        # Handle Duration property based on result type
        if ($result -is [hashtable] -and $result.ContainsKey('Duration')) {
            $result.Duration = $stopwatch.Elapsed
            Write-WULog "Windows Update installation completed in $($result.Duration.ToString('hh\:mm\:ss'))" -Level Info
            Write-WULog "Summary - Success: $($result.Success), Found: $($result.UpdatesFound), Downloaded: $($result.UpdatesDownloaded), Installed: $($result.UpdatesInstalled), Failed: $($result.UpdatesFailed)" -Level Info
            
            # Format and display the final report for normal installation mode
            Format-WUResult -Result $result
        } else {
            # Analysis mode - result has different structure
            $duration = $stopwatch.Elapsed
            Write-WULog "Configuration analysis completed in $($duration.ToString('hh\:mm\:ss'))" -Level Info
            
            # Don't call Format-WUResult for analysis results as it expects different structure
            if ($result.Success) {
                Write-WULog "=== Analysis completed successfully ===" -Level Info
            } else {
                Write-WULog "=== Analysis completed with errors ===" -Level Warning
            }
        }
    }

    return $result
}