Search code examples
restpowershellerror-handlingswallowed-exceptions

Powershell is swallowing REST error response


I am using Invoke-WebRequest in Powershell and whenever my request is determined to be invalid by the targeted API endpoint, it obviously denies the request and sends back an HTTP error code like (400) Bad Request but it also includes the reason for the error (provided by the API vendor) but that isn't included in the logs inside of PowerShell.

I confirmed the detailed error is sent back because I see it in PostMan and the vendor confirmed the same. Powershell just doesn't want to show it. Here is an example of my code and the response it is generating.

Invoke-WebRequest -Credential $cred -Uri $url -Method POST -Body $json -ContentType 'application/json'
Invoke-WebRequest : The remote server returned an error: (400) Bad Request.
At \\*****\******$\Appsense\Desktop\Untitled2.ps1:42 char:1
+ Invoke-WebRequest -Credential $cred -Uri $url -Method POST -Body $jso ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) 
    [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands. 
   InvokeWebRequestCommand

How do I capture that more detailed error message?


Solution

  • Two parts to this. First you need to have it throw a terminating error with -ErrorAction Stop. This allows us to then use a try/catch block to catch the exception. With the Exception we can then get the detailed response stored in the Exception Status Description. This is fine for most requests.

    To get the body of the message requires a few more steps. Since we get a WebResponse object, there is no "Nice" Message parameter for us. So we have to use a StreamReader to Stream the content ourselves:

    try
    {
        $Response = Invoke-WebRequest -Credential $cred -Uri $url -Method POST -Body $json -ContentType 'application/json' -ErrorAction Stop
        # This will only execute if the Invoke-WebRequest is successful.
        $StatusCode = $Response.StatusCode
    }
    catch
    {
        #Excepion - Display error codes
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    
        #Get body of me
        $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
        $ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
        $streamReader.Close()
        Write-Host $ErrResp
    }