dist/temp/WindowsUpdateTools/Private/Get-WUSetupLogsDirect.ps1

function Get-WUSetupLogsDirect {
    <#
    .SYNOPSIS
        Direct Windows Setup log parsing for immediate error detection.
 
    .DESCRIPTION
        Lightweight parser that directly analyzes Windows Setup logs to identify
        specific Windows 11 24H2 failure patterns without external dependencies.
        Used as fallback when SetupDiag is inconclusive or for faster results.
 
    .PARAMETER SetupLogPath
        Path to Windows Setup logs directory (auto-detected if not provided).
 
    .PARAMETER LogPath
        Path to the WindowsUpdateTools log file.
 
    .EXAMPLE
        $analysis = Get-WUSetupLogsDirect -LogPath "C:\Logs\wu.log"
 
    .EXAMPLE
        $analysis = Get-WUSetupLogsDirect -SetupLogPath "C:\$Windows.~BT\Sources\Panther" -LogPath "C:\Logs\wu.log"
 
    .NOTES
        This is a private function used internally by the WindowsUpdateTools module.
        Returns detailed analysis of Windows Setup failures with targeted remediation.
    #>


    [CmdletBinding()]
    param(
        [string]$SetupLogPath,
        [string]$LogPath
    )

    Write-WULog -Message "Starting direct Windows Setup log analysis" -LogPath $LogPath

    $analysis = [PSCustomObject]@{
        AnalysisSuccessful = $false
        SetupLogPath = $null
        FailuresDetected = 0
        FailureReasons = @()
        CriticalErrors = @()
        TargetedRemediation = @()
        BlockingItems = @()
        BlockingDriverDetails = @()
        SoftwareConflicts = @()
        ErrorCodes = @()
    }

    try {
        # Auto-detect setup log path if not provided
        if (-not $SetupLogPath) {
            $setupPaths = @(
                "C:\`$Windows.~BT\Sources\Panther",
                "C:\Windows\Panther", 
                "C:\Windows\Logs\MoSetup"
            )

            foreach ($path in $setupPaths) {
                if (Test-Path "$path\setuperr.log") {
                    $SetupLogPath = $path
                    Write-WULog -Message "Auto-detected setup logs at: $path" -LogPath $LogPath
                    break
                }
            }
        }

        if (-not $SetupLogPath -or -not (Test-Path "$SetupLogPath\setuperr.log")) {
            Write-WULog -Message "No Windows Setup logs found - no recent upgrade attempts detected" -LogPath $LogPath
            return $analysis
        }

        $analysis.SetupLogPath = $SetupLogPath
        $analysis.AnalysisSuccessful = $true

        # Phase 1: Parse setuperr.log for critical 24H2 error patterns
        Write-WULog -Message "Analyzing setuperr.log for critical error patterns..." -LogPath $LogPath
        $setupErrPath = Join-Path $SetupLogPath "setuperr.log"
        $setupErrors = Get-Content $setupErrPath

        # Define error patterns with remediation mapping
        $errorPatterns = @{
            "SdbpGetMatchingInfoBlocksInternal.*TAGREF array insufficient" = @{
                Name = "AppraiserTAGREF"
                Description = "Appraiser compatibility database corruption (TAGREF array insufficient)"
                Remediation = "Reset Windows Appraiser compatibility database"
                Function = "Resolve-WUAppraiserIssues"
                ErrorCode = "TAGREF_CORRUPTION"
            }
            "0x80070057.*WU.*configuration.*targeted scans|Failed to set WU internal configuration property.*0x80070057" = @{
                Name = "DynamicUpdatesConfig"
                Description = "Dynamic Updates configuration failure (0x80070057)"
                Remediation = "Fix Dynamic Updates configuration and add registry fixes"
                Function = "Resolve-WUDynamicUpdatesIssues"
                ErrorCode = "0x80070057"
            }
            "0x80004005.*download.*updates|Failed to download updates.*0x80004005|CDownloadDUUpdates.*0x80004005" = @{
                Name = "DynamicUpdatesDownload"
                Description = "Dynamic Updates download failure (0x80004005)"
                Remediation = "Reset Windows Update components and fix download issues"
                Function = "Resolve-WUDynamicUpdatesIssues"
                ErrorCode = "0x80004005"
            }
            "DriverPackageReader.*0x3|Failed to Open Driver Package 0x3|InitDriverPackageHardwareIds.*0x3" = @{
                Name = "DriverStoreCorruption"
                Description = "Driver Store corruption - missing driver packages (0x3)"
                Remediation = "Repair Driver Store integrity and remove problematic drivers"
                Function = "Resolve-WUDriverStoreIssues"
                ErrorCode = "0x00000003"
            }
            'XML.*format.*"script".*mandatory|Invalid xml format.*script.*attribute is mandatory' = @{
                Name = "ComponentStoreXML"
                Description = "Component Store XML format corruption (missing script attributes)"
                Remediation = "Repair Component Store and fix XML manifest corruption"
                Function = "Resolve-WUComponentStore"
                ErrorCode = "XML_FORMAT"
            }
            "0x00000005.*registry|failed to delete reg tree.*0x00000005|pSPRemoveUpgradeRegTree.*0x00000005" = @{
                Name = "RegistryPermissions"
                Description = "Registry permission/access denied errors (0x00000005)"
                Remediation = "Fix registry permissions and TrustedInstaller ownership"
                Function = "Resolve-WURegistryPermissions"
                ErrorCode = "0x00000005"
            }
            "0x80070490.*driver|Failed to find.*driver.*0x80070490" = @{
                Name = "DriverStoreNotFound"
                Description = "Driver Store corruption - elements not found (0x80070490)"
                Remediation = "Rebuild Driver Store integrity"
                Function = "Resolve-WUDriverStoreIssues"
                ErrorCode = "0x80070490"
            }
        }

        # Check for each error pattern
        foreach ($pattern in $errorPatterns.GetEnumerator()) {
            $patternMatches = $setupErrors | Select-String $pattern.Key
            if ($patternMatches) {
                $analysis.FailuresDetected++
                $analysis.FailureReasons += $pattern.Value.Description
                $analysis.CriticalErrors += $pattern.Value.Name
                $analysis.TargetedRemediation += $pattern.Value.Function
                $analysis.ErrorCodes += $pattern.Value.ErrorCode
                
                Write-WULog -Message "Detected: $($pattern.Value.Description)" -Level Warning -LogPath $LogPath
                Write-WULog -Message " Matches found: $($patternMatches.Count)" -LogPath $LogPath
                Write-WULog -Message " Remediation: $($pattern.Value.Remediation)" -LogPath $LogPath
            }
        }

        # Phase 2: Parse ScanResult.xml for blocking items
        $scanResultPath = Join-Path $SetupLogPath "ScanResult.xml"
        if (Test-Path $scanResultPath) {
            Write-WULog -Message "Analyzing ScanResult.xml for compatibility blocks..." -LogPath $LogPath
            
            try {
                $scanContent = Get-Content $scanResultPath -Raw
                
                # Find blocking drivers - check both unsigned and potentially misidentified drivers
                # Pattern 1: Explicitly marked as having unsigned binaries
                $blockingDriverPattern1 = 'Inf="([^"]+)"[^>]*BlockMigration="True"[^>]*HasSignedBinaries="False"'
                $blockingDrivers1 = [regex]::Matches($scanContent, $blockingDriverPattern1)
                
                # Pattern 2: General blocking drivers (might be misidentified as unsigned)
                $blockingDriverPattern2 = 'Inf="([^"]+)"[^>]*BlockMigration="True"'
                $blockingDrivers2 = [regex]::Matches($scanContent, $blockingDriverPattern2)
                
                # Combine and deduplicate driver INF names
                $allBlockingDrivers = @()
                $allBlockingDrivers += $blockingDrivers1 | ForEach-Object { $_.Groups[1].Value }
                $allBlockingDrivers += $blockingDrivers2 | ForEach-Object { $_.Groups[1].Value }
                $uniqueBlockingDrivers = $allBlockingDrivers | Sort-Object -Unique
                
                foreach ($driverInf in $uniqueBlockingDrivers) {
                    # Determine if setup logs claim this is unsigned
                    $claimedUnsigned = $blockingDrivers1 | Where-Object { $_.Groups[1].Value -eq $driverInf }
                    $logMessage = if ($claimedUnsigned) {
                        "Found blocking driver flagged as unsigned: $driverInf - Verifying actual signature status..."
                    } else {
                        "Found blocking driver: $driverInf - Resolving details..."
                    }
                    Write-WULog -Message $logMessage -Level Warning -LogPath $LogPath
                    
                    # Resolve detailed driver information with actual signature verification
                    $driverDetails = Resolve-WUDriverDetails -OemInfName $driverInf -LogPath $LogPath
                    $analysis.BlockingDriverDetails += $driverDetails
                    
                    # Check for signature status discrepancy
                    if ($claimedUnsigned -and $driverDetails.IsSigned) {
                        Write-WULog -Message "SIGNATURE DISCREPANCY: Setup logs incorrectly flagged $driverInf as unsigned" -Level Warning -LogPath $LogPath
                        Write-WULog -Message " Actual signature status: SIGNED by $($driverDetails.SignerName)" -LogPath $LogPath
                        Write-WULog -Message " This appears to be a Windows Setup compatibility scanner false positive" -LogPath $LogPath
                    }
                    
                    # Create enhanced blocking item description with signature verification
                    $enhancedDescription = "BLOCKING DRIVER: $driverInf"
                    if ($driverDetails.ResolvedSuccessfully) {
                        $enhancedDescription += "`n Original Name: $($driverDetails.OriginalName)"
                        $enhancedDescription += "`n Provider: $($driverDetails.ProviderName)"
                        $enhancedDescription += "`n Device Class: $($driverDetails.ClassName)"
                        $enhancedDescription += "`n Driver Version: $($driverDetails.DriverVersion) ($($driverDetails.DriverDate))"
                        
                        # Enhanced signature reporting
                        if ($claimedUnsigned -and $driverDetails.IsSigned) {
                            $enhancedDescription += "`n SETUP LOG CLAIM: Unsigned (INCORRECT)"
                            $enhancedDescription += "`n ACTUAL STATUS: SIGNED by $($driverDetails.SignerName)"
                            $enhancedDescription += "`n ANALYSIS: False positive - driver is properly signed"
                        } else {
                            $enhancedDescription += "`n Digital Signature: $($driverDetails.IsSigned) ($($driverDetails.SignerName))"
                        }
                        
                        if ($driverDetails.DeviceDescriptions.Count -gt 0) {
                            $enhancedDescription += "`n Device Types: $($driverDetails.DeviceDescriptions -join ', ')"
                        }
                        
                        if ($driverDetails.AssociatedDevices.Count -gt 0) {
                            $enhancedDescription += "`n Associated Hardware:"
                            foreach ($device in $driverDetails.AssociatedDevices) {
                                $status = if ($device.Present) { "Present" } else { "Not Present" }
                                $enhancedDescription += "`n - $($device.Name) ($status)"
                            }
                        } else {
                            $enhancedDescription += "`n Associated Hardware: None detected (driver may be unused)"
                        }
                        
                        # Enhanced recommendation based on actual signature status
                        $enhancedDescription += "`n RECOMMENDATION: "
                        if ($claimedUnsigned -and $driverDetails.IsSigned) {
                            if ($driverDetails.ProviderName -eq "Microsoft" -or $driverDetails.SignerName -like "*Microsoft*") {
                                $enhancedDescription += "This is a Microsoft-signed driver incorrectly flagged by Windows Setup. Safe to keep - investigate Windows Update compatibility settings."
                            } else {
                                $enhancedDescription += "Driver is properly signed but flagged by Setup. Verify Windows 11 24H2 compatibility with manufacturer."
                            }
                        } elseif (-not $driverDetails.IsSigned) {
                            $enhancedDescription += "Remove this unsigned driver before attempting Windows 11 upgrade"
                        } else {
                            $enhancedDescription += "Verify driver compatibility with Windows 11 24H2"
                        }
                        
                        # Enhanced targeted remediation with signature context
                        if ($claimedUnsigned -and $driverDetails.IsSigned) {
                            $analysis.TargetedRemediation += "Investigate-SignedDriverBlock:$driverInf ($($driverDetails.ClassName) - $($driverDetails.ProviderName)) - False positive detected"
                        } else {
                            $analysis.TargetedRemediation += "Remove-BlockingDriver:$driverInf ($($driverDetails.ClassName) - $($driverDetails.ProviderName))"
                        }
                    } else {
                        $enhancedDescription += "`n Could not resolve driver details - manual investigation required"
                        $analysis.TargetedRemediation += "Remove-BlockingDriver:$driverInf"
                    }
                    
                    $analysis.BlockingItems += $enhancedDescription
                    
                    # Log summary of findings with signature verification
                    if ($driverDetails.ResolvedSuccessfully) {
                        $signatureStatus = if ($claimedUnsigned -and $driverDetails.IsSigned) {
                            "SIGNED (Setup log false positive)"
                        } elseif ($driverDetails.IsSigned) {
                            "SIGNED"
                        } else {
                            "UNSIGNED"
                        }
                        Write-WULog -Message " Resolved as: $($driverDetails.ClassName) driver from $($driverDetails.ProviderName)" -LogPath $LogPath
                        Write-WULog -Message " Signature status: $signatureStatus, Associated devices: $($driverDetails.AssociatedDevices.Count)" -LogPath $LogPath
                    } else {
                        Write-WULog -Message " Could not resolve driver details for $driverInf" -Level Warning -LogPath $LogPath
                    }
                }

                # Check for general compatibility blocks
                if ($scanContent -match 'BlockingType="[^N][^o][^n][^e]"') {
                    $blockingItems = [regex]::Matches($scanContent, 'HardwareType="([^"]+)"[^>]*BlockingType="([^"]+)"')
                    foreach ($block in $blockingItems) {
                        if ($block.Groups[2].Value -ne "None") {
                            $analysis.BlockingItems += "Hardware compatibility block: $($block.Groups[1].Value) ($($block.Groups[2].Value))"
                            Write-WULog -Message "Hardware block: $($block.Groups[1].Value) - $($block.Groups[2].Value)" -Level Warning -LogPath $LogPath
                        }
                    }
                }
            }
            catch {
                Write-WULog -Message "Error parsing ScanResult.xml: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
            }
        }

        # Phase 3: Parse diagwrn.xml for software conflicts
        $diagWrnPath = Join-Path $SetupLogPath "diagwrn.xml"
        if (Test-Path $diagWrnPath) {
            Write-WULog -Message "Analyzing diagwrn.xml for software conflicts..." -LogPath $LogPath
            
            try {
                $warnContent = Get-Content $diagWrnPath
                
                # Known problematic software patterns
                $conflictPatterns = @{
                    "FolderLock" = "FolderLock file encryption software"
                    "Intel.*Driver.*Support.*Assistant" = "Intel Driver Support Assistant"
                    "Acronis" = "Acronis backup software"
                    "McAfee" = "McAfee antivirus"
                    "Norton" = "Norton antivirus"
                    "Kaspersky" = "Kaspersky antivirus"
                    "VirtualBox" = "Oracle VirtualBox"
                    "VMware" = "VMware virtualization"
                }

                $phantomLogged = @{}
                foreach ($pattern in $conflictPatterns.GetEnumerator()) {
                    $conflictMatches = $warnContent | Select-String $pattern.Key
                    foreach ($match in $conflictMatches) {
                        $software = $pattern.Value
                        if ($match.Line -match "will remove it") {
                            if (-not $phantomLogged.ContainsKey($software)) {
                                Write-WULog -Message "Cleaning up phantom reference: $software" -LogPath $LogPath
                                $phantomLogged[$software] = $true
                            }
                        } else {
                            $analysis.SoftwareConflicts += $software
                            Write-WULog -Message "Software conflict detected: $software" -Level Warning -LogPath $LogPath
                        }
                    }
                }
            }
            catch {
                Write-WULog -Message "Error parsing diagwrn.xml: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
            }
        }

        # Phase 4: Parse diagerr.xml for additional structured errors
        $diagErrPath = Join-Path $SetupLogPath "diagerr.xml"
        if (Test-Path $diagErrPath) {
            Write-WULog -Message "Checking diagerr.xml for additional error details..." -LogPath $LogPath
            
            try {
                $errMatches = Select-String -Path $diagErrPath -Pattern 'Msg="([^"]+)"' | Select-Object -First 10
                foreach ($match in $errMatches) {
                    $errorMsg = $match.Matches[0].Groups[1].Value
                    # Only log if not already detected in setuperr.log and the message is not empty
                    if (-not [string]::IsNullOrWhiteSpace($errorMsg) -and ($analysis.FailureReasons -notcontains $errorMsg)) {
                        Write-WULog -Message "Additional error from diagerr.xml: $errorMsg" -LogPath $LogPath
                    }
                }
            }
            catch {
                Write-WULog -Message "Error parsing diagerr.xml: $($_.Exception.Message)" -Level Warning -LogPath $LogPath
            }
        }

        # Summary
        Write-WULog -Message "Direct log analysis completed:" -LogPath $LogPath
        Write-WULog -Message " Critical errors found: $($analysis.FailuresDetected)" -LogPath $LogPath
        Write-WULog -Message " Blocking items: $($analysis.BlockingItems.Count)" -LogPath $LogPath
        Write-WULog -Message " Blocking drivers resolved: $($analysis.BlockingDriverDetails.Count)" -LogPath $LogPath
        Write-WULog -Message " Software conflicts: $($analysis.SoftwareConflicts.Count)" -LogPath $LogPath
        Write-WULog -Message " Targeted remediation functions: $($analysis.TargetedRemediation.Count)" -LogPath $LogPath
        
        # Log summary of resolved drivers
        if ($analysis.BlockingDriverDetails.Count -gt 0) {
            Write-WULog -Message "Blocking drivers summary:" -LogPath $LogPath
            foreach ($driver in $analysis.BlockingDriverDetails) {
                if ($driver.ResolvedSuccessfully) {
                    Write-WULog -Message " $($driver.OemInf): $($driver.ClassName) by $($driver.ProviderName) (Signed: $($driver.IsSigned))" -LogPath $LogPath
                } else {
                    Write-WULog -Message " $($driver.OemInf): Resolution failed - $($driver.ErrorMessage)" -Level Warning -LogPath $LogPath
                }
            }
        }

    }
    catch {
        Write-WULog -Message "Error during direct setup log analysis: $($_.Exception.Message)" -Level Error -LogPath $LogPath
        $analysis.AnalysisSuccessful = $false
    }

    return $analysis
}