Powershell web request without throwing exception on 4xx/5xx

Powershell

Powershell Problem Overview


I'm writing a powershell script that needs to make a web request and inspect the status code of the response.

I have tried writing this:

$client = new-object system.net.webclient

$response = $client.DownloadData($url)

as well as this:

$response = Invoke-WebRequest $url

but whenever the web page has a status code that's not a success status code, PowerShell goes ahead and throws an exception instead of giving me the actual response object.

How can I get the status code of the page even when it fails to load?

Powershell Solutions


Solution 1 - Powershell

Try this:

try { $response = Invoke-WebRequest http://localhost/foo } catch {
      $_.Exception.Response.StatusCode.Value__}

It is kind of a bummer that this throws an exception but that's the way it is.

Update per comments

To ensure that such errors still return a valid response, you can capture those exceptions of type WebException and fetch the related Response.

Since the response on the exception is of type System.Net.HttpWebResponse, whilst the response from a successful Invoke-WebRequest call is of type Microsoft.PowerShell.Commands.HtmlWebResponseObject, to return a compatible type from both scenarios we need to take the successful response's BaseResponse, which is also of type System.Net.HttpWebResponse.

This new response type's status code an enum of type [system.net.httpstatuscode], rather than a simple integer, so you have to explicity convert it to int, or access it's Value__ property as described above to get the numeric code.

#ensure we get a response even if an error's returned
$response = try { 
    (Invoke-WebRequest -Uri 'localhost/foo' -ErrorAction Stop).BaseResponse
} catch [System.Net.WebException] { 
    Write-Verbose "An exception was caught: $($_.Exception.Message)"
    $_.Exception.Response 
} 

#then convert the status code enum to int by doing this
$statusCodeInt = [int]$response.BaseResponse.StatusCode
#or this
$statusCodeInt = $response.BaseResponse.StatusCode.Value__

Solution 2 - Powershell

Since Powershell version 7.0 Invoke-WebRequest have -SkipHttpErrorCheck switch parameter.

> -SkipHttpErrorCheck > > This parameter causes the cmdlet to ignore HTTP error statuses and > continue to process responses. The error responses are written to the > pipeline just as if they were successful. > > This parameter was introduced in PowerShell 7.

docs pull request

Solution 3 - Powershell

-SkipHttpErrorCheck is the best solution for PowerShell 7+, but if you can't use that yet then here is a simple alternative that is useful for interactive, command-line Poweshell sessions.

When you see the an error description for a 404 response, i.e.,

> The remote server returned an error: (404) Not Found.

Then you can see the 'last error' from the command-line by entering this:

$Error[0].Exception.Response.StatusCode

Or

$Error[0].Exception.Response.StatusDescription

Or whatever else you would like to know from the `Response’ object.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjcarpenter2View Question on Stackoverflow
Solution 1 - PowershellKeith HillView Answer on Stackoverflow
Solution 2 - PowershellMariusz PawelskiView Answer on Stackoverflow
Solution 3 - PowershellDaveCView Answer on Stackoverflow