101

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?

jcarpenter2
  • 5,312
  • 4
  • 22
  • 49
  • This worked for me https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-6 Example 7: Catch non success messages from Invoke-WebRequest – user3520245 Aug 21 '19 at 13:28

3 Answers3

147

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 is an enum of type [system.net.httpstatuscode], rather than a simple integer, so you have to explicity convert it to int, or access its 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__
OutstandingBill
  • 2,614
  • 26
  • 38
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 5
    Thanks, that worked. I didn't realize that you could just access the Response object from the Exception object. – jcarpenter2 Oct 01 '13 at 18:09
  • 1
    Yeah, getting to the actual code number was a bit tricky. :-) – Keith Hill Oct 01 '13 at 18:13
  • My go to is using this code from Chris Wahl, http://wahlnetwork.com/2015/02/19/using-try-catch-powershells-invoke-webrequest/ – FoxDeploy Oct 14 '16 at 16:52
  • 11
    A slightly better way: $response = try { Invoke-WebRequest http://localhost/foo } catch { $_.Exception.Response } That way you get something in the $response variable in both cases. But be aware that a failure returns an HtmlWebResponse, but a success returns an HtmlWebResponseObject. In particular, the StatusCode on those are different types (sigh..) – Rob Cannon May 23 '17 at 17:20
  • 2
    But how do you get response content in this case? – Andrew Savinykh Dec 28 '17 at 20:12
  • Passing `-ErrorVariable ErrorBody` (no `$`) as an argument to `Invoke-WebRequest` will cause the response content to be stored in a variable with that name, `$ErrorBody` in this case. That variable can be used to access that content in the catch block. If `Invoke-WebRequest` is successful, that error variable will be empty. – Dan Mangiarelli May 29 '18 at 21:33
  • 7
    A couple of minor tweaks to Rob's great suggestion, to avoid the issue with different types: `$response = try { (Invoke-WebRequest -Uri 'localhost/foo' -ErrorAction Stop).BaseRequest } catch [System.Net.WebException] { $_.Exception.Response }`. I.e. fetching `BaseRequest` ensures that in both success and error scenarios we're getting an `HttpWebReqponse`. Adding `[System.Net.WebException]` ensures we only capture relevant exceptions in this way / don't accidentally sweep up other types of issues. – JohnLBevan Oct 01 '18 at 15:05
  • @JohnLBevan - I think your comment is useful enough to post it as an additional answer, especially with some of the other info in these comments about the different response types. – Taegost Oct 11 '18 at 19:42
  • 1
    Thanks @Taegost. I don't feel my comment is different from the accepted answer; it just adds some more info, so I've edited Keith's existing answer to include this info so people can see it without delving into the comments. – JohnLBevan Oct 12 '18 at 08:11
28

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

Mariusz Pawelski
  • 25,983
  • 11
  • 67
  • 80
6

-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.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
DaveC
  • 81
  • 1
  • 2