Public/Debug-WindowsUpdateAgent.ps1

function Debug-WindowsUpdateAgent {
    <#
    .SYNOPSIS
    Advanced debugging tool for Windows Update Agent COM object operations.
 
    .DESCRIPTION
    This function provides detailed, real-time debugging of Windows Update Agent COM operations
    to diagnose issues like 0x80131501 errors. It includes step-by-step COM object validation,
    method invocation testing, and comprehensive error analysis.
 
    .PARAMETER TestLevel
    Controls the depth of testing:
    - Basic: COM object creation and basic properties
    - Intermediate: Method invocation testing
    - Advanced: Full update search and download simulation
 
    .PARAMETER LogPath
    Path to write detailed debug logs. If not specified, logs to console only.
 
    .EXAMPLE
    Debug-WindowsUpdateAgent -TestLevel Basic -Verbose
 
    .EXAMPLE
    Debug-WindowsUpdateAgent -TestLevel Advanced -LogPath "C:\Temp\WUA-Debug.log"
 
    .NOTES
    Requires administrative privileges.
    Designed specifically to diagnose 0x80131501 and similar COM-related errors.
 
    Author: CSOLVE Scripts - Advanced Diagnostics
    Version: 1.0.0
    #>


    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateSet('Basic', 'Intermediate', 'Advanced')]
        [string]$TestLevel = 'Intermediate',

        [Parameter()]
        [string]$LogPath
    )

    # Enhanced logging function with real-time output
    function Write-DebugLog {
        param(
            [string]$Message,
            [ValidateSet('Info', 'Warning', 'Error', 'Debug', 'Verbose')]
            [string]$Level = 'Info',
            [string]$LogPath
        )
        
        $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff'
        $logEntry = "[$timestamp] [$Level] $Message"
        
        # Always write to console with color coding
        switch ($Level) {
            'Error' { Write-Host $logEntry -ForegroundColor Red }
            'Warning' { Write-Host $logEntry -ForegroundColor Yellow }
            'Debug' { Write-Host $logEntry -ForegroundColor Cyan }
            'Verbose' { Write-Host $logEntry -ForegroundColor Gray }
            default { Write-Host $logEntry -ForegroundColor White }
        }
        
        # Write to log file if specified
        if ($LogPath) {
            try {
                Add-Content -Path $LogPath -Value $logEntry -ErrorAction SilentlyContinue
            } catch {
                # Ignore log file errors to prevent cascading issues
            }
        }
    }

    # Test COM object creation with detailed error reporting
    function Test-ComObjectCreation {
        param(
            [string]$ProgId,
            [string]$Description
        )
        
        Write-DebugLog "Testing COM object creation: $Description ($ProgId)" -Level Info
        
        try {
            $comObject = New-Object -ComObject $ProgId
            Write-DebugLog "SUCCESS: Created $Description" -Level Info
            Write-DebugLog "Object Type: $($comObject.GetType().FullName)" -Level Debug
            
            # Get available methods and properties
            $methods = $comObject | Get-Member -MemberType Method | Select-Object -ExpandProperty Name
            $properties = $comObject | Get-Member -MemberType Property | Select-Object -ExpandProperty Name
            
            Write-DebugLog "Available Methods: $($methods.Count) - $($methods -join ', ')" -Level Verbose
            Write-DebugLog "Available Properties: $($properties.Count) - $($properties -join ', ')" -Level Verbose
            
            return $comObject
        } catch [System.Runtime.InteropServices.COMException] {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
            Write-DebugLog "COM Exception creating $Description" -Level Error
            Write-DebugLog "HResult: $hresult" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
            return $null
        } catch {
            Write-DebugLog "Unexpected error creating $Description" -Level Error
            Write-DebugLog "Exception Type: $($_.Exception.GetType().FullName)" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
            return $null
        }
    }

    # Test method invocation with detailed error capture
    function Test-MethodInvocation {
        param(
            [object]$ComObject,
            [string]$MethodName,
            [array]$Parameters = @(),
            [string]$Description
        )
        
        Write-DebugLog "Testing method: $MethodName on $Description" -Level Info
        
        try {
            if ($Parameters.Count -eq 0) {
                $result = $ComObject.$MethodName()
            } else {
                $result = $ComObject.$MethodName($Parameters)
            }
            
            Write-DebugLog "SUCCESS: Method $MethodName executed" -Level Info
            Write-DebugLog "Result Type: $($result.GetType().FullName)" -Level Debug
            
            return $result
        } catch [System.Management.Automation.MethodInvocationException] {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.InnerException.HResult)
            Write-DebugLog "Method Invocation Exception for $MethodName" -Level Error
            Write-DebugLog "HResult: $hresult" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
            Write-DebugLog "Inner Exception: $($_.Exception.InnerException.Message)" -Level Error
            return $null
        } catch [System.Runtime.InteropServices.COMException] {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
            Write-DebugLog "COM Exception for $MethodName" -Level Error
            Write-DebugLog "HResult: $hresult" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
            return $null
        } catch {
            Write-DebugLog "Unexpected error for $MethodName" -Level Error
            Write-DebugLog "Exception Type: $($_.Exception.GetType().FullName)" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
            return $null
        }
    }

    # Main debugging logic
    try {
        Write-DebugLog "=== Windows Update Agent COM Debug Session Started ===" -Level Info
        Write-DebugLog "Test Level: $TestLevel" -Level Info
        Write-DebugLog "PowerShell Version: $($PSVersionTable.PSVersion)" -Level Info
        Write-DebugLog "OS Version: $([System.Environment]::OSVersion)" -Level Info
        
        if ($LogPath) {
            Write-DebugLog "Debug log file: $LogPath" -Level Info
        }

        # Step 1: Test basic COM object creation
        Write-DebugLog "`n--- PHASE 1: COM Object Creation Testing ---" -Level Info
        
        $updateSession = Test-ComObjectCreation -ProgId "Microsoft.Update.Session" -Description "Update Session"
        if (-not $updateSession) {
            Write-DebugLog "CRITICAL: Cannot create Microsoft.Update.Session - aborting" -Level Error
            return
        }

        # Test UpdateSearcher creation
        $updateSearcher = Test-MethodInvocation -ComObject $updateSession -MethodName "CreateUpdateSearcher" -Description "UpdateSearcher"
        if (-not $updateSearcher) {
            Write-DebugLog "CRITICAL: Cannot create UpdateSearcher - aborting" -Level Error
            return
        }

        # Test UpdateDownloader creation
        $updateDownloader = Test-MethodInvocation -ComObject $updateSession -MethodName "CreateUpdateDownloader" -Description "UpdateDownloader"
        if (-not $updateDownloader) {
            Write-DebugLog "CRITICAL: Cannot create UpdateDownloader - this may be the 0x80131501 issue!" -Level Error
            return
        }

        if ($TestLevel -eq 'Basic') {
            Write-DebugLog "Basic testing completed successfully" -Level Info
            return
        }

        # Step 2: Test intermediate operations
        Write-DebugLog "`n--- PHASE 2: Intermediate Operations Testing ---" -Level Info
        
        # Test UpdateDownloader properties
        try {
            Write-DebugLog "Testing UpdateDownloader properties..." -Level Info
            
            $priority = $updateDownloader.Priority
            Write-DebugLog "Current Priority: $priority" -Level Debug
            
            $updateDownloader.Priority = 4  # ExtraHigh
            Write-DebugLog "Set Priority to ExtraHigh (4)" -Level Debug
            
            $isForced = $updateDownloader.IsForced
            Write-DebugLog "Current IsForced: $isForced" -Level Debug
            
            $updateDownloader.IsForced = $true
            Write-DebugLog "Set IsForced to True" -Level Debug
            
        } catch {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
            Write-DebugLog "Error setting UpdateDownloader properties" -Level Error
            Write-DebugLog "HResult: $hresult" -Level Error
            Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
        }

        if ($TestLevel -eq 'Intermediate') {
            Write-DebugLog "Intermediate testing completed" -Level Info
            return
        }

        # Step 3: Advanced testing - actual update operations
        Write-DebugLog "`n--- PHASE 3: Advanced Update Operations Testing ---" -Level Info
        
        # Test update search
        Write-DebugLog "Testing update search..." -Level Info
        $searchCriteria = "IsHidden=0 and IsInstalled=0 and Type='Software' and BrowseOnly=0"
        Write-DebugLog "Search criteria: $searchCriteria" -Level Debug
        
        $searchResult = Test-MethodInvocation -ComObject $updateSearcher -MethodName "Search" -Parameters @($searchCriteria) -Description "UpdateSearcher.Search"
        
        if ($searchResult) {
            Write-DebugLog "Search found $($searchResult.Updates.Count) updates" -Level Info
            
            if ($searchResult.Updates.Count -gt 0) {
                # Test setting up downloads
                Write-DebugLog "Testing download setup..." -Level Info
                
                try {
                    $updateCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
                    $updateCollection.Add($searchResult.Updates.Item(0))  # Add first update
                    
                    $updateDownloader.Updates = $updateCollection
                    Write-DebugLog "Successfully assigned update collection to downloader" -Level Info
                    Write-DebugLog "Updates in downloader collection: $($updateDownloader.Updates.Count)" -Level Debug
                    
                    # This is where 0x80131501 typically occurs - test the Download method
                    Write-DebugLog "CRITICAL TEST: Attempting Download() method..." -Level Warning
                    Write-DebugLog "This is where 0x80131501 errors typically occur" -Level Warning
                    
                    $downloadResult = Test-MethodInvocation -ComObject $updateDownloader -MethodName "Download" -Description "UpdateDownloader.Download"
                    
                    if ($downloadResult) {
                        Write-DebugLog "Download method succeeded!" -Level Info
                        Write-DebugLog "Download ResultCode: $($downloadResult.ResultCode)" -Level Info
                    } else {
                        Write-DebugLog "Download method failed - this confirms the 0x80131501 issue" -Level Error
                    }
                    
                } catch {
                    $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
                    Write-DebugLog "Error during download setup or execution" -Level Error
                    Write-DebugLog "HResult: $hresult" -Level Error
                    Write-DebugLog "Message: $($_.Exception.Message)" -Level Error
                }
            } else {
                Write-DebugLog "No updates found - cannot test download operations" -Level Warning
            }
        }

        Write-DebugLog "`n--- PHASE 4: Environmental Analysis ---" -Level Info
        
        # Check Windows Update service status
        try {
            $wuService = Get-Service -Name "wuauserv" -ErrorAction SilentlyContinue
            if ($wuService) {
                Write-DebugLog "Windows Update Service Status: $($wuService.Status)" -Level Info
                Write-DebugLog "Windows Update Service StartType: $($wuService.StartType)" -Level Info
            } else {
                Write-DebugLog "Windows Update Service not found" -Level Error
            }
        } catch {
            Write-DebugLog "Error checking Windows Update service: $($_.Exception.Message)" -Level Error
        }

        # Check for Group Policy interference
        try {
            $auOptions = Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "NoAutoUpdate" -ErrorAction SilentlyContinue
            if ($auOptions) {
                Write-DebugLog "Group Policy NoAutoUpdate detected: $($auOptions.NoAutoUpdate)" -Level Warning
            } else {
                Write-DebugLog "No Group Policy interference detected for automatic updates" -Level Info
            }
        } catch {
            Write-DebugLog "Error checking Group Policy settings: $($_.Exception.Message)" -Level Warning
        }

        # Check Windows Update Agent version
        try {
            $wuaVersion = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate" -Name "Services" -ErrorAction SilentlyContinue
            if ($wuaVersion) {
                Write-DebugLog "Windows Update Agent registry path accessible" -Level Info
            }
        } catch {
            Write-DebugLog "Error accessing Windows Update Agent registry: $($_.Exception.Message)" -Level Warning
        }

        Write-DebugLog "`n=== Windows Update Agent COM Debug Session Completed ===" -Level Info

    } catch {
        Write-DebugLog "Critical error in debug session: $($_.Exception.Message)" -Level Error
        Write-DebugLog "Exception Type: $($_.Exception.GetType().FullName)" -Level Error
        if ($_.Exception.HResult -ne 0) {
            $hresult = [System.String]::Format("0x{0:X8}", $_.Exception.HResult)
            Write-DebugLog "HResult: $hresult" -Level Error
        }
    } finally {
        # Cleanup COM objects
        if ($updateDownloader) {
            try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($updateDownloader) | Out-Null } catch { }
        }
        if ($updateSearcher) {
            try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($updateSearcher) | Out-Null } catch { }
        }
        if ($updateSession) {
            try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($updateSession) | Out-Null } catch { }
        }
        
        Write-DebugLog "COM objects released and session cleaned up" -Level Info
    }
}