Private/Code.ps1

# What a code means.
#
# A status or an error code is never shown to a Technician bare. The code stays - it is
# what gets looked up - and what it means stands beside it. These are the decoders the
# Kinds share: the error numbers of Windows, HTTP statuses, the sign-in statuses of
# Windows and of Microsoft Entra ID. A code none of them knows comes back with nothing,
# and is then shown as it is: that is a gap to close and not a reason to hide the code.
#
# All pure. Where a table here is not Microsoft's own documentation, it says where it is from.

function ConvertTo-CodeNumber {
    <#
    .SYNOPSIS
        A code as a number, however it was written: 1067, '0x5', 'C000006D'. $null for
        what is none. Pure.
    #>

    [CmdletBinding()]
    [OutputType([long])]
    param([AllowNull()]$Code, [switch]$Hex)

    $text = "$Code".Trim()
    if (-not $text) { return $null }
    $number = [long]0
    if ($text -match '^(?i)0x([0-9a-f]+)$') {
        if ([long]::TryParse($Matches[1], [Globalization.NumberStyles]::HexNumber, [cultureinfo]::InvariantCulture, [ref]$number)) { return $number }
        return $null
    }
    if ($Hex -and $text -match '^(?i)[0-9a-f]{8}$') {
        if ([long]::TryParse($text, [Globalization.NumberStyles]::HexNumber, [cultureinfo]::InvariantCulture, [ref]$number)) { return $number }
    }
    if ([long]::TryParse($text, [Globalization.NumberStyles]::Integer, [cultureinfo]::InvariantCulture, [ref]$number)) { return $number }
    $null
}

function Get-Win32ErrorText {
    <#
    .SYNOPSIS
        What Windows itself says of one of its error numbers, in the language Windows
        runs in. Nothing for zero and for a number it has no words for. Pure.
    .DESCRIPTION
        The exit code of a service, the error of a Group Policy run, the low word of an
        HRESULT that begins 0x8007. Windows carries the sentences; a number it does not
        know comes back as "Unknown error (0x...)", which is no meaning and is dropped.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Code)

    $number = ConvertTo-CodeNumber -Code $Code
    if ($null -eq $number -or $number -le 0 -or $number -gt [int]::MaxValue) { return '' }
    try {
        $message = "$((New-Object System.ComponentModel.Win32Exception ([int]$number)).Message)".Trim()
        if ($message -match '(?i)^(Unknown error|Unbekannter Fehler)' -or $message -match '\(0x[0-9a-f]+\)$') { return '' }
        $message
    }
    catch { '' }
}

function Get-WindowsMessageText {
    <#
    .SYNOPSIS
        The sentence a library of Windows carries for one of its codes, in the language
        Windows runs in. Nothing for a code it has none for. Reads Windows; changes nothing.
    .DESCRIPTION
        ntdll.dll carries one for every status of Windows (NTSTATUS), winhttp.dll for
        every WinHTTP error; Get-Win32ErrorText does not reach either. A sentence with a
        place left open for a value ("%hs") has [...] there; a title in braces
        before it is kept as its beginning; of a long one the first sentence is kept.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([Parameter(Mandatory)][ValidateSet('ntdll.dll', 'winhttp.dll')][string]$Library, [AllowNull()]$Id)

    if ($null -eq $Id) { return '' }
    try {
        if (-not ('Gutcheck.WindowsMessage' -as [type])) {
            Add-Type -Namespace Gutcheck -Name WindowsMessage -MemberDefinition @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibraryEx(string file, IntPtr reserved, uint flags);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr module);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int FormatMessage(uint flags, IntPtr source, uint id, uint language, System.Text.StringBuilder buffer, int size, IntPtr arguments);
'@

        }
        $number = [uint32]([long]$Id -band 0xFFFFFFFFL)
        # As a data file only: nothing of the library is run.
        $module = [Gutcheck.WindowsMessage]::LoadLibraryEx($Library, [IntPtr]::Zero, 0x2)
        if ($module -eq [IntPtr]::Zero) { return '' }
        try {
            $buffer = New-Object System.Text.StringBuilder 2048
            # From the module, inserts left as they are.
            $length = [Gutcheck.WindowsMessage]::FormatMessage(0x800 -bor 0x200, $module, $number, 0, $buffer, $buffer.Capacity, [IntPtr]::Zero)
            if ($length -le 0) { return '' }
            $text = $buffer.ToString()
        }
        finally { [void][Gutcheck.WindowsMessage]::FreeLibrary($module) }

        # Line by line: a title in braces becomes the beginning, and a line that ends
        # without a full stop gets one, so that the lines do not run into each other.
        $lines = @($text -split '\r?\n' | ForEach-Object { $_.Trim() } | Where-Object { $_ } | ForEach-Object {
            $line = $_ -replace '^\{([^}]*)\}$', '$1:' -replace '^\{([^}]*)\}\s*', '$1: '
            if ($line -notmatch '[.:!?,;]$') { $line + '.' } else { $line }
        })
        $text = $lines -join ' '
        # A place left open for a value: [...] stands where the value would.
        $text = $text -replace '"?(0x)?%[0-9]*!?[a-zA-Z]+!?"?', '[...]' -replace '%[0-9]+', '[...]'
        $text = ($text -replace '\s+', ' ').Trim()
        if ($text.Length -gt 160) {
            $end = $text.IndexOf('. ')
            if ($end -gt 20) { $text = $text.Substring(0, $end + 1) }
        }
        $text.TrimEnd('.')
    }
    catch { '' }
}

function Get-HttpStatusText {
    <#
    .SYNOPSIS
        What an HTTP status means, in a Technician's words. Nothing for one this has no
        word for and whose class says nothing either. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Status)

    $number = ConvertTo-CodeNumber -Code $Status
    if ($null -eq $number) { return '' }
    switch ([int]$number) {
        200 { return Get-Text 'Value.Code.Http.200' }
        204 { return Get-Text 'Value.Code.Http.204' }
        301 { return Get-Text 'Value.Code.Http.301' }
        302 { return Get-Text 'Value.Code.Http.302' }
        307 { return Get-Text 'Value.Code.Http.302' }
        400 { return Get-Text 'Value.Code.Http.400' }
        401 { return Get-Text 'Value.Code.Http.401' }
        403 { return Get-Text 'Value.Code.Http.403' }
        404 { return Get-Text 'Value.Code.Http.404' }
        407 { return Get-Text 'Value.Code.Http.407' }
        408 { return Get-Text 'Value.Code.Http.408' }
        429 { return Get-Text 'Value.Code.Http.429' }
        500 { return Get-Text 'Value.Code.Http.500' }
        502 { return Get-Text 'Value.Code.Http.502' }
        503 { return Get-Text 'Value.Code.Http.503' }
        504 { return Get-Text 'Value.Code.Http.504' }
    }
    if ($number -ge 300 -and $number -lt 400) { return Get-Text 'Value.Code.Http.3xx' }
    if ($number -ge 500 -and $number -lt 600) { return Get-Text 'Value.Code.Http.5xx' }
    ''
}

function Format-CodeWithMeaning {
    <#
    .SYNOPSIS
        A code with what it means behind it; the code alone where nothing is known. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyString()][string]$Code, [AllowNull()][AllowEmptyString()][string]$Meaning)

    if (-not "$Code".Trim()) { return '' }
    if (-not "$Meaning".Trim()) { return "$Code".Trim() }
    (Get-Text 'Value.Code.WithMeaning') -f "$Code".Trim(), "$Meaning".Trim()
}

function Format-HttpStatus {
    <#
    .SYNOPSIS
        An HTTP status with what it means behind it. Pure.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Status)

    Format-CodeWithMeaning -Code "$Status" -Meaning (Get-HttpStatusText -Status $Status)
}

function Get-NtStatusText {
    <#
    .SYNOPSIS
        What a sign-in status of Windows (NTSTATUS) means. Nothing for one not known here. Pure.
    .DESCRIPTION
        The ones a sign-in ends in, as Microsoft documents them for logon events
        (event 4625, "Status" and "Sub Status"), and the ones Microsoft's article on
        troubleshooting the primary refresh token names for the "Attempt Status" of
        dsregcmd /status: the network was not there, or the logon session was gone.
        Any other status is said as Windows says it, unless -KnownHere asks for the
        ones worded here only.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Code, [switch]$KnownHere)

    $number = ConvertTo-CodeNumber -Code $Code -Hex
    if ($null -eq $number) { return '' }
    switch ('{0:X8}' -f ($number -band 0xFFFFFFFFL)) {
        'C000006D' { return Get-Text 'Value.Code.NtStatus.LogonFailure' }
        'C000006A' { return Get-Text 'Value.Code.NtStatus.WrongPassword' }
        'C0000064' { return Get-Text 'Value.Code.NtStatus.NoSuchUser' }
        'C0000234' { return Get-Text 'Value.Code.NtStatus.LockedOut' }
        'C0000072' { return Get-Text 'Value.Code.NtStatus.Disabled' }
        'C0000071' { return Get-Text 'Value.Code.NtStatus.PasswordExpired' }
        'C0000224' { return Get-Text 'Value.Code.NtStatus.PasswordMustChange' }
        'C0000193' { return Get-Text 'Value.Code.NtStatus.AccountExpired' }
        'C000006F' { return Get-Text 'Value.Code.NtStatus.LogonHours' }
        'C0000070' { return Get-Text 'Value.Code.NtStatus.Workstation' }
        'C000005E' { return Get-Text 'Value.Code.NtStatus.NoLogonServers' }
        'C0000133' { return Get-Text 'Value.Code.NtStatus.TimeDifference' }
        'C000015B' { return Get-Text 'Value.Code.NtStatus.LogonType' }
        'C000005F' { return Get-Text 'Value.Code.NtStatus.NoLogonSession' }
        'C00000BE' { return Get-Text 'Value.Code.NtStatus.BadNetworkPath' }
        'C00000C4' { return Get-Text 'Value.Code.NtStatus.UnexpectedNetworkError' }
        'C00000D0' { return Get-Text 'Value.Code.NtStatus.RequestNotAccepted' }
        'C000023C' { return Get-Text 'Value.Code.NtStatus.NetworkUnreachable' }
    }
    if ($KnownHere) { return '' }
    # Not one of those: Windows has a sentence for every status it knows.
    Get-WindowsMessageText -Library 'ntdll.dll' -Id $number
}

function Get-HResultText {
    <#
    .SYNOPSIS
        What an HRESULT means: a Win32 error it wraps, a sign-in status of Windows, or
        one of the sign-in broker's own. Nothing for one not known here. Pure.
    .DESCRIPTION
        0x8007nnnn is the Win32 error nnnn. 0xCAAnnnnn are the codes of the Microsoft
        account and work account broker (AAD/WAM) that Office logs; the ones named here
        are those Microsoft's troubleshooting articles for Office sign-in name, and
        0xCAA82EEn carry a WinHTTP error in their low word (12002 timeout, 12007 name not
        resolved, 12029 cannot connect, 12030 connection aborted, 12175 no secure
        connection). The same WinHTTP errors wrapped as 0x80072nnn are named here too:
        Windows keeps their sentences in winhttp.dll and not where Get-Win32ErrorText
        reads, so it has none for them. The errors of AppX deployment (0x80073CFn) need no
        table: they are Win32 errors Windows has words for.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Code)

    $number = ConvertTo-CodeNumber -Code $Code -Hex
    if ($null -eq $number) { return '' }
    $hex = '{0:X8}' -f ($number -band 0xFFFFFFFFL)

    switch ($hex) {
        '80072EE2' { return Get-Text 'Value.Code.WinHttp.Timeout' }
        '80072EE7' { return Get-Text 'Value.Code.WinHttp.NameNotResolved' }
        '80072EFD' { return Get-Text 'Value.Code.WinHttp.CannotConnect' }
        '80072EFE' { return Get-Text 'Value.Code.WinHttp.ConnectionAborted' }
        '80072F8F' { return Get-Text 'Value.Code.WinHttp.SecureFailure' }
        'CAA82EFE' { return Get-Text 'Value.Code.WinHttp.ConnectionAborted' }
        'CAA82F8F' { return Get-Text 'Value.Code.WinHttp.SecureFailure' }
    }
    # Any other WinHTTP error (12000 to 12999), wrapped either way: winhttp.dll has it.
    if ($hex -match '^(8007|CAA8)(2[EF][0-9A-F]{2}|3[0-2][0-9A-F]{2})$') {
        $low = $number -band 0xFFFF
        if ($low -ge 12000 -and $low -le 12999) {
            $said = Get-WindowsMessageText -Library 'winhttp.dll' -Id $low
            if ($said) { return $said }
        }
    }
    if ($hex.StartsWith('8007')) { return Get-Win32ErrorText -Code ($number -band 0xFFFF) }
    switch ($hex) {
        # These three as the event of the Windows sign-in log words them beside the code
        # (read off Microsoft-Windows-AAD/Operational 1098 on a Windows 11 machine):
        # "A login hint was sent that doesn't match any WebAccount in the system",
        # "Token broker operation failed", and invalid_request.
        'CAA100D8' { return Get-Text 'Value.Code.Wam.LoginHint' }
        'CAA5001C' { return Get-Text 'Value.Code.Wam.BrokerFailed' }
        'CAA20002' { return Get-Text 'Value.Code.Wam.InvalidRequest' }
        'CAA20003' { return Get-Text 'Value.Code.Wam.InvalidGrant' }
        'CAA2000C' { return Get-Text 'Value.Code.Wam.InteractionRequired' }
        'CAA70004' { return Get-Text 'Value.Code.Wam.ServerNotFound' }
        'CAA70007' { return Get-Text 'Value.Code.Wam.ServerNotResponding' }
        'CAA82EE2' { return Get-Text 'Value.Code.Wam.Timeout' }
        'CAA82EE7' { return Get-Text 'Value.Code.Wam.NameNotResolved' }
        'CAA82EFD' { return Get-Text 'Value.Code.Wam.CannotConnect' }
    }
    # One of the broker's own that is not named above: at least whose code it is. A
    # Technician who knows that it is the sign-in, and not the network or the program,
    # knows where to look and what to search for.
    if ($hex.StartsWith('CAA')) { return Get-Text 'Value.Code.Wam.Other' }
    # An HRESULT of another facility can share its number with no status of Windows,
    # and must not borrow one's sentence: only a plain status (0xC000....) is asked for.
    if ($hex.StartsWith('C000')) { return Get-NtStatusText -Code $number }
    Get-NtStatusText -Code $number -KnownHere
}

function Get-AadStsText {
    <#
    .SYNOPSIS
        What an error number of Microsoft Entra ID (AADSTS) means. Nothing for one not
        known here. Pure.
    .DESCRIPTION
        The ones a user's sign-in ends in, as Microsoft documents them under "Microsoft
        Entra authentication and authorization error codes". 70044 is not in that table:
        it is the session's counterpart of 70043, as the sign-in itself words it ("The
        session has expired or is invalid due to sign-in frequency checks by Conditional
        Access").
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()]$Code)

    $number = ConvertTo-CodeNumber -Code ("$Code" -replace '(?i)^\s*AADSTS', '')
    if ($null -eq $number) { return '' }
    switch ([long]$number) {
        50020  { return Get-Text 'Value.Code.Aad.50020' }
        50034  { return Get-Text 'Value.Code.Aad.50034' }
        50053  { return Get-Text 'Value.Code.Aad.50053' }
        50055  { return Get-Text 'Value.Code.Aad.50055' }
        50057  { return Get-Text 'Value.Code.Aad.50057' }
        50058  { return Get-Text 'Value.Code.Aad.50058' }
        50074  { return Get-Text 'Value.Code.Aad.50074' }
        50076  { return Get-Text 'Value.Code.Aad.50076' }
        50079  { return Get-Text 'Value.Code.Aad.50079' }
        50097  { return Get-Text 'Value.Code.Aad.50097' }
        50105  { return Get-Text 'Value.Code.Aad.50105' }
        50126  { return Get-Text 'Value.Code.Aad.50126' }
        50133  { return Get-Text 'Value.Code.Aad.50133' }
        50155  { return Get-Text 'Value.Code.Aad.50155' }
        50158  { return Get-Text 'Value.Code.Aad.50158' }
        50173  { return Get-Text 'Value.Code.Aad.50173' }
        53000  { return Get-Text 'Value.Code.Aad.53000' }
        53001  { return Get-Text 'Value.Code.Aad.53001' }
        53003  { return Get-Text 'Value.Code.Aad.53003' }
        65001  { return Get-Text 'Value.Code.Aad.65001' }
        70008  { return Get-Text 'Value.Code.Aad.70008' }
        70043  { return Get-Text 'Value.Code.Aad.70043' }
        70044  { return Get-Text 'Value.Code.Aad.70043' }
        135011 { return Get-Text 'Value.Code.Aad.135011' }
        700016 { return Get-Text 'Value.Code.Aad.700016' }
        700082 { return Get-Text 'Value.Code.Aad.700082' }
    }
    ''
}

function Get-OAuthErrorText {
    <#
    .SYNOPSIS
        What an OAuth error word of Microsoft Entra ID means (invalid_grant and the like).
        Nothing for one not known here. Pure.
    .DESCRIPTION
        The words the token endpoint answers with, as Microsoft documents them for the
        OAuth 2.0 authorization code flow ("Error codes for token endpoint errors"). The
        AAD log and dsregcmd /status carry them beside the AADSTS number, which says more.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyString()][string]$Code)

    switch ("$Code".Trim().ToLowerInvariant()) {
        'invalid_grant'           { return Get-Text 'Value.Code.Wam.InvalidGrant' }
        'interaction_required'    { return Get-Text 'Value.Code.Wam.InteractionRequired' }
        'consent_required'        { return Get-Text 'Value.Code.Aad.65001' }
        'invalid_client'          { return Get-Text 'Value.Code.OAuth.InvalidClient' }
        'unauthorized_client'     { return Get-Text 'Value.Code.OAuth.UnauthorizedClient' }
        'temporarily_unavailable' { return Get-Text 'Value.Code.OAuth.TemporarilyUnavailable' }
    }
    ''
}

function Get-MicrosoftAppText {
    <#
    .SYNOPSIS
        Which program an application id of Microsoft's is, as a Technician knows it. One
        it does not know is said to be another, with the id; none is said to be none. Pure.
    .DESCRIPTION
        Every program that signs in to Microsoft 365 does so as an application with an
        id of its own, and the sign-in log of Windows names that id with each error. The
        ids here are the ones that sign in on a Windows PC, as Microsoft's own sign-in
        documentation and the directory itself name them (collected in the public list
        merill/microsoft-info, MicrosoftApps.csv, read 2026-10-10; the ones marked there
        as contributed by the community are Edge, the Office app from the Store, the
        company portal, the accounts control and the device management client).
 
        Outlook as part of Office has no id of its own: it signs in as "Microsoft
        Office", as Word and Excel do. Which of them it was the log does not say.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([AllowNull()][AllowEmptyString()][string]$ClientId)

    $id = "$ClientId".Trim().ToLowerInvariant()
    if (-not $id) { return Get-Text 'Value.Code.App.NotNamed' }
    switch ($id) {
        'd3590ed6-52b3-4102-aeff-aad2292ab01c' { return Get-Text 'Value.Code.App.Office' }
        '5d661950-3475-41cd-a2c3-d671a3162bc1' { return Get-Text 'Value.Code.App.Outlook' }
        '27922004-5251-4030-b22d-91ecd9a37ea4' { return Get-Text 'Value.Code.App.OutlookMobile' }
        'ab9b8c07-8f02-4f72-87fa-80105867a763' { return Get-Text 'Value.Code.App.OneDrive' }
        '6a9b9266-8161-4a7b-913a-a9eda19da220' { return Get-Text 'Value.Code.App.OneDrive' }
        'b26aadf8-566f-4478-926f-589f601d9c74' { return Get-Text 'Value.Code.App.OneDrive' }
        'ecd6b820-32c2-49b6-98a6-444530e5a77a' { return Get-Text 'Value.Code.App.Edge' }
        'd7b530a4-7680-4c23-a8bf-c52c121d2e87' { return Get-Text 'Value.Code.App.EdgeNewTab' }
        '1fec8e78-bce4-4aaf-ab1b-5451cc387264' { return Get-Text 'Value.Code.App.Teams' }
        '5e3ce6c0-2b1f-4285-8d4b-75ee78787346' { return Get-Text 'Value.Code.App.TeamsWeb' }
        '29d9ed98-a469-4536-ade2-f981bc1d605e' { return Get-Text 'Value.Code.App.Broker' }
        'a40d7d7d-59aa-447e-a655-679a4107e548' { return Get-Text 'Value.Code.App.AccountsControl' }
        '38aa3b87-a06d-4817-b275-7a316988d93b' { return Get-Text 'Value.Code.App.Hello' }
        '26a7ee05-5602-4d76-a7ba-eae8b7b67941' { return Get-Text 'Value.Code.App.Search' }
        '1b3c667f-cde3-4090-b60b-3d2abd0117f0' { return Get-Text 'Value.Code.App.Spotlight' }
        '4765445b-32c6-49b0-83e6-1d93765276ca' { return Get-Text 'Value.Code.App.OfficeHome' }
        '0ec893e0-5785-4de6-99da-4ed124e5296c' { return Get-Text 'Value.Code.App.OfficeStore' }
        'c0ab8ce9-e9a0-42e7-b064-33d422df41f1' { return Get-Text 'Value.Code.App.Copilot' }
        'cf36b471-5b44-428c-9ce7-313bf84528de' { return Get-Text 'Value.Code.App.Bing' }
        '9ba1a5c7-f17a-4de9-a1f1-6178c8d51223' { return Get-Text 'Value.Code.App.CompanyPortal' }
        'fc0f3af4-6835-4174-b806-f7db311fd2f3' { return Get-Text 'Value.Code.App.IntuneAgent' }
        'de50c81f-5f80-4771-b66b-cebd28ccdfc1' { return Get-Text 'Value.Code.App.DeviceManagement' }
    }
    (Get-Text 'Value.Code.App.Other') -f $id
}