Public/Get-FslErrorCode.ps1

function Get-FslErrorCode {
    <#
    .SYNOPSIS
        Decodes an FSLogix error code into meaning, likely causes and recommended fixes.
    .DESCRIPTION
        Looks the code up in the curated FSLogixDoctor error-code database
        (Data\ErrorCodes.psd1). Accepts hex strings ('0x00000020'), decimal strings
        ('32'), integers (32) and symbolic names ('ERROR_SHARING_VIOLATION').
 
        Codes that are not in the curated database fall back to the generic Win32
        error message, so any code appearing in an FSLogix log line can be decoded.
    .PARAMETER Code
        The error code to decode. Also accepts pipeline input, including the
        ErrorCode property of Get-FslLogError output.
    .PARAMETER ListAvailable
        Lists every code in the curated database.
    .EXAMPLE
        Get-FslErrorCode 0x00000020
 
        Explains the classic 'profile already attached elsewhere' sharing violation.
    .EXAMPLE
        Get-FslLogError -Newest 1 | Get-FslErrorCode
 
        Decodes every error code found in the newest FSLogix Profile log.
    .LINK
        https://github.com/xGreeny/fslogix-doctor/blob/main/docs/error-codes.md
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ListAvailable', Justification = 'The switch selects its parameter set; the value itself is not read.')]
    [CmdletBinding(DefaultParameterSetName = 'Lookup')]
    [OutputType([pscustomobject])]
    param(
        [Parameter(ParameterSetName = 'Lookup', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('ErrorCode')]
        [object]$Code,

        [Parameter(ParameterSetName = 'List', Mandatory)]
        [switch]$ListAvailable
    )

    begin {
        $table = Get-FslDataTable -Name ErrorCodes

        $newResult = {
            param([string]$key, [hashtable]$entry, [bool]$inDatabase)
            [pscustomobject]@{
                PSTypeName = 'FSLogixDoctor.ErrorCode'
                Code       = $key
                Name       = $entry.Name
                Meaning    = $entry.Meaning
                Causes     = @($entry.Causes)
                Fixes      = @($entry.Fixes)
                Source     = $entry.Source
                InDatabase = $inDatabase
            }
        }

        if ($PSCmdlet.ParameterSetName -eq 'List') {
            foreach ($key in ($table.Keys | Sort-Object)) {
                & $newResult $key $table[$key] $true
            }
        }
    }

    process {
        if ($PSCmdlet.ParameterSetName -ne 'Lookup') { return }

        # Whole objects arriving via ValueFromPipeline shadow by-property binding;
        # unwrap anything that carries an ErrorCode or Code property (e.g. output
        # of Get-FslLogError).
        $value = $Code
        if ($value -is [psobject] -and $value -isnot [string] -and $value -isnot [ValueType]) {
            if ($value.PSObject.Properties['ErrorCode']) { $value = $value.ErrorCode }
            elseif ($value.PSObject.Properties['Code']) { $value = $value.Code }
        }
        if ($null -eq $value -or ([string]$value).Trim() -eq '') {
            Write-Verbose 'Skipping pipeline object without an error code.'
            return
        }

        $key = ConvertTo-FslErrorKey -Code $value

        if ($table.ContainsKey($key)) {
            & $newResult $key $table[$key] $true
            return
        }

        # Symbolic name given: search the database by Name.
        if ($key -notmatch '^0x[0-9A-F]{8}$') {
            $match = $table.GetEnumerator() | Where-Object { $_.Value.Name -eq $key } | Select-Object -First 1
            if ($match) {
                & $newResult $match.Key $match.Value $true
                return
            }
            Write-Warning "No FSLogix error code named '$key' found in the database. Try Get-FslErrorCode -ListAvailable."
            return
        }

        # Unknown hex code: fall back to the generic Win32 message. HRESULT-wrapped
        # Win32 codes (0x8007xxxx) carry the Win32 code in the low 16 bits.
        $number = [Convert]::ToUInt32($key.Substring(2), 16)
        $win32Message = $null
        $hresultNote = ''
        # Shift instead of masking: hex literals with the sign bit set (0xFFFF0000,
        # 0x80070000) parse as negative Int32 in PowerShell and break the compare.
        if (($number -shr 16) -eq 0x8007) {
            $hresultNote = ' (HRESULT form of Win32 code {0})' -f ($number -band 0xFFFF)
            $number = $number -band 0xFFFF
        }
        if ($number -le 0xFFFF) {
            $win32Message = (New-Object System.ComponentModel.Win32Exception([int]$number)).Message + $hresultNote
        }
        $meaning = 'Unknown code (not in the curated FSLogix database)'
        if ($win32Message) { $meaning = "Win32: $win32Message (not in the curated FSLogix database)" }
        & $newResult $key @{
            Name    = $null
            Meaning = $meaning
            Causes  = @()
            Fixes   = @('Search the FSLogix logs for surrounding context lines.', 'If you identify this code, please contribute it: https://github.com/xGreeny/fslogix-doctor')
            Source  = $null
        } $false
    }
}