Hi S-1-1-0! Today's topic is described in the post header :)

I guess most of you have encountered with some application/system issues. Sometimes the only information you have is Win32 error code and nothing else. To find a text message for particular error you usually use Google/Bing and/or other tools, like Err.exe from Windows Server 2003 Resource Kit. Yesterday I wrote a PowerShell script that will convert Win32 error code to a readable text. The code uses FormatMessage() WinAPI function. Here is a known limitation, this function doesn't handle network-related errors (that are defined in wininet.h header file). Hopefully my script resolves this limitation by adding a reference to the wininet.dll library when it is necessary. Here is a code snippet:

function Get-ErrorMessage {
[OutputType('System.String')]
[CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$ErrorCode
    )
$signature = @'
[DllImport("kernel32.dll", SetLastError=true)]
public static extern uint FormatMessage(
    uint dwFlags,
    IntPtr lpSource,
    int dwMessageId,
    uint dwLanguageId,
    ref IntPtr lpBuffer,
    uint nSize,
    IntPtr Arguments
);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr LoadLibrary(
    string lpFileName
);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern bool FreeLibrary(
    IntPtr hModule
);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr LocalFree(
    IntPtr hMem
);
'@
    try {Add-Type -MemberDefinition $signature -Name Kernel32 -Namespace PKI}
    catch {Write-Warning $Error[0].Exception.Message; return}
    $StartBase = 12000
    $EndBase = 12176
    $ErrorHex = "{0:x8}" -f $ErrorCode
    $HighBytes = iex 0x$($ErrorHex.Substring(0,4))
    $LowBytes = iex 0x$($ErrorHex.Substring(4,4))
    $lpMsgBuf = [IntPtr]::Zero
    if ($LowBytes -gt $StartBase -and $LowBytes -lt $EndBase) {
        $hModule = [PKI.Kernel32]::LoadLibrary("wininet.dll")
        $dwChars = [PKI.Kernel32]::FormatMessage(0xb00,$hModule,$LowBytes,0,[ref]$lpMsgBuf,0,[IntPtr]::Zero)
        [void][PKI.Kernel32]::FreeLibrary($hModule)
    } else {$dwChars = [PKI.Kernel32]::FormatMessage(0x1300,[IntPtr]::Zero,$ErrorCode,0,[ref]$lpMsgBuf,0,[IntPtr]::Zero)}

    if ($dwChars -ne 0) {
        ([Runtime.InteropServices.Marshal]::PtrToStringAnsi($lpMsgBuf)).Trim()
        [void][PKI.Kernel32]::LocalFree($lpMsgBuf)
    } else {
        Write-Error -Category ObjectNotFound `

        -ErrorId "ElementNotFoundException" `

        -Message "No error messages are assoicated with error code: 0x$ErrorHex ($ErrorCode). Operation failed."
    }
}

The usage is very simple:

[↓] [vPodans] Get-ErrorMessage 0x80070005
Access is denied.
[↓] [vPodans] # short notation of this error:
[↓] [vPodans] Get-ErrorMessage 5
Access is denied.
[↓] [vPodans] Get-ErrorMessage 0x80072ee6
The URL does not use a recognized protocol
[↓] [vPodans] 0x80072ee6
-2147012890
[↓] [vPodans] Get-ErrorMessage -2147012890
The URL does not use a recognized protocol
[↓] [vPodans] Get-ErrorMessage 1
Incorrect function.
[↓] [vPodans]

as you see, it accepts errors in 3 formats:

  • Hex string. This must be a hex string prepended by '0x' prefix.
  • Signed integer (either positive or negative, depending on actual value).
  • Error code short (low bytes) part.

Even though the script won't handle any Win32 errors, but, most of them — definitely and this function will be included as a part of my upcoming PowerShell PKI module update.

HTH


Share this article:

Comments:

Garric

That's great!

Kim

What a great work! Thanks for sharing it.


Post your comment:

Please, solve this little equation and enter result below. Captcha