Public/Get-AzLocalTSGFix.ps1

<#
.SYNOPSIS
    Find known issues and fixes for Azure Local and AKS Arc errors.
.DESCRIPTION
    Searches the local TSG index for matching known issues and fixes.
    Accepts error messages directly or from log files.
.PARAMETER ErrorText
    Error message text to search for.
.PARAMETER Path
    Path to a log file containing errors.
.PARAMETER Top
    Number of top results to return (default: 5).
.PARAMETER UpdateCache
    Update the index before searching.
.PARAMETER Json
    Output results as JSON.
.EXAMPLE
    Get-AzLocalTSGFix -ErrorText "Microsoft.Health.FaultType.Cluster.ValidationReport.Failed"
    Searches for fixes related to cluster validation failures.
.EXAMPLE
    Get-AzLocalTSGFix -Path ".\deployment.log" -Top 3 -UpdateCache
    Searches the log file contents and updates cache first.
.EXAMPLE
    Get-AzLocalTSGFix -ErrorText "AKS node NotReady" -Json | Out-File results.json
    Outputs results as JSON to a file.
#>

function Get-AzLocalTSGFix {
    [CmdletBinding(DefaultParameterSetName = 'Text')]
    param(
        [Parameter(ParameterSetName = 'Text', Mandatory, Position = 0)]
        [string]$ErrorText,

        [Parameter(ParameterSetName = 'File', Mandatory)]
        [string]$Path,

        [Parameter()]
        [int]$Top = 5,

        [Parameter()]
        [switch]$UpdateCache,

        [Parameter()]
        [switch]$Json
    )

    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    # Update cache if requested
    if ($UpdateCache) {
        Write-Host "==> Updating index..." -ForegroundColor Cyan
        Update-AzLocalTSGIndex -Force:$Force
        Write-Host ""
    }

    # Read input
    $inputText = if ($PSCmdlet.ParameterSetName -eq 'File') {
        Read-LogInput -Path $Path
    } else {
        Read-LogInput -ErrorText $ErrorText
    }

    Write-Verbose "Input text length: $($inputText.Length) characters"

    # Normalize input to tokens
    $queryTokens = ConvertTo-NormalizedTokens -InputText $inputText
    Write-Verbose "Query tokens: $($queryTokens -join ', ')"

    if ($queryTokens.Count -eq 0) {
        Write-Warning "No meaningful tokens extracted from input. Try providing more specific error details."
        return
    }

    # Load index
    Write-Verbose "Loading index..."
    $indexEntries = Load-Index

    if ($indexEntries.Count -eq 0) {
        Write-Warning "Index is empty. Run 'Update-AzLocalTSGIndex' first to build the index."
        Write-Host ""
        Write-Host "Quick start:" -ForegroundColor Cyan
        Write-Host " Update-AzLocalTSGIndex" -ForegroundColor Gray
        return
    }

    Write-Verbose "Searching $($indexEntries.Count) indexed documents..."

    # Score and rank candidates
    $results = @(Invoke-ScoreCandidates -QueryTokens $queryTokens -IndexEntries $indexEntries -Top $Top)

    # Record analytics
    $topMatch = if ($results.Count -gt 0) { $results[0].Title } else { $null }
    $topConfidence = if ($results.Count -gt 0) { $results[0].Confidence } else { 0 }
    Add-SearchAnalytics -ErrorText $ErrorText -ResultCount $results.Count -TopMatch $topMatch -TopConfidence $topConfidence

    if ($results.Count -eq 0) {
        Write-Warning "No matching issues found."
        Write-Host ""
        Write-Host "Suggestions:" -ForegroundColor Cyan
        Write-Host " - Try different keywords or error codes" -ForegroundColor Gray
        Write-Host " - Update the index: Update-AzLocalTSGIndex -Force" -ForegroundColor Gray
        return
    }

    # Output results
    if ($Json) {
        return $results | ConvertTo-Json -Depth 10
    } else {
        Write-Host ""
        Write-Host "Found $($results.Count) potential fix(es)" -ForegroundColor Green
        Write-Host ""

        for ($i = 0; $i -lt $results.Count; $i++) {
            $result = $results[$i]
            $rank = $i + 1

            # Simple header
            Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor DarkGray
            Write-Host "FIX #$rank" -ForegroundColor Cyan -NoNewline
            Write-Host " - $($result.Title)" -ForegroundColor White
            
            # Traffic light system for match confidence
            $matchColor = 'Red'
            if ($rank -eq 1) {
                $matchColor = 'Green'  # Best match
            } elseif ($rank -eq 2) {
                $matchColor = 'Yellow'  # Second best
            }
            # Third and beyond stay Red
            
            Write-Host "Match: " -ForegroundColor Gray -NoNewline
            Write-Host "$($result.Confidence)%" -ForegroundColor $matchColor
            Write-Host ""
            
            # Show clickable URL first
            $esc = [char]27
            $url = $result.Url
            $clickableUrl = "$esc]8;;$url$esc\Full guide: $url$esc]8;;$esc\"
            Write-Host $clickableUrl -ForegroundColor Cyan
            
            # Show brief summary if available
            if ($result.FixSummary) {
                Write-Host ""
                Write-Host "$($result.FixSummary)" -ForegroundColor Gray
            }
            Write-Host ""

            # Show fix steps if available
            if ($result.FixSteps -and $result.FixSteps.Count -gt 0) {
                
                # Show ALL steps completely
                foreach ($step in $result.FixSteps) {
                    
                    if ($step.Type -eq 'Code') {
                        Write-Host "STEP $($step.Number): Run these commands" -ForegroundColor Yellow
                        Write-Host ""
                        
                        # Show all commands with bullet points
                        $codeLines = $step.Content -split "`n"
                        
                        foreach ($line in $codeLines) {
                            if ($line.Trim() -ne '') {
                                Write-Host " • $line" -ForegroundColor White
                            }
                        }
                        Write-Host ""
                    } elseif ($step.Type -eq 'Text') {
                        Write-Host "STEP $($step.Number): " -ForegroundColor Yellow -NoNewline
                        Write-Host "$($step.Content)" -ForegroundColor White
                        Write-Host ""
                    }
                }
            } else {
                Write-Host "No automated fix steps found." -ForegroundColor DarkGray
                Write-Host "See full guide above for manual troubleshooting." -ForegroundColor DarkGray
                Write-Host ""
            }
        }

        Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor DarkGray
        Write-Host ""
        Write-Host "💡 Tip: Copy each step and run it in PowerShell | Use -Top 5 for more results" -ForegroundColor Gray
        Write-Host ""

        # Return nothing to avoid duplicate output
        return
    }
}