4

I have a Powershell script that uses System.Net.HttpWebRequest to communicate with a remote host.

I create the request, set properties accordingly and call getresponse() and getresponsestream() to read the entire response from the server to a string. This works fine as long as the server responds with a "200 OK" message.

If the server responds with a "400 Bad Request" or any other error code, getresponse() and getresponsestream() throw exceptions and return nothing. My problem is there is more detailed error information included in the response header which I need so I can do my own error handling.

How would I be able to retrieve this 400 Bad Request signal?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Justin
  • 415
  • 2
  • 5
  • 9
  • Have you already caught the exception object and looked at the $_.Exception.Message property? And explored the $_.Exception object? – Andy Arismendi Mar 03 '12 at 06:58

2 Answers2

7

Edit: I misunderstood the question at first, but it turns out that you can retrieve the response header by using the HttpWebResponse.GetResponseHeader() method. If an exception occurs, the HttpWebRequest.GetResponse() method returns $null, and you have to use this code to retrieve the HttpWebResponse object, so that you can call GetResponseHeader() on it:

# If an exception occurs, get the HttpWebResponse object from the WebException object
$HttpWebResponse = $Error[0].Exception.InnerException.Response;

I'm pretty sure you'll want to stick with the System.Net.HttpWebRequest instead of the System.Net.WebClient object. Here is an example, similar to what you probably already have:

# Create a HttpWebRequest using the Create() static method
$HttpWebRequest = [System.Net.HttpWebRequest]::Create("http://www.google.com/");

# Get an HttpWebResponse object
$HttpWebResponse = $HttpWebRequest.GetResponse();

# Get the integer value of the HttpStatusCode enumeration
Write-Host -Object $HttpWebResponse.StatusCode.value__;

The GetResponse() method returns a HttpWebResponse object, which has a property named StatusCode, which points to a value in the HttpStatusCode .NET enumeration. Once you get a reference to the enumeration, we use the value__ property to get the integer that is associated with the returned enum value.

If you get a null value from the GetResponse() method, then you'll want to read the most current error message in your catch {..} block. The Exception.ErrorRecord property should be the most helpful.

try {
  $HttpWebResponse = $null;
  $HttpWebRequest = [System.Net.HttpWebRequest]::Create("http://www.asdf.com/asdf");
  $HttpWebResponse = $HttpWebRequest.GetResponse();
  if ($HttpWebResponse) {
    Write-Host -Object $HttpWebResponse.StatusCode.value__;
    Write-Host -Object $HttpWebResponse.GetResponseHeader("X-Detailed-Error");
  }
}
catch {
  $ErrorMessage = $Error[0].Exception.ErrorRecord.Exception.Message;
  $Matched = ($ErrorMessage -match '[0-9]{3}')
  if ($Matched) {
    Write-Host -Object ('HTTP status code was {0} ({1})' -f $HttpStatusCode, $matches.0);
  }
  else {
    Write-Host -Object $ErrorMessage;
  }

  $HttpWebResponse = $Error[0].Exception.InnerException.Response;
  $HttpWebResponse.GetResponseHeader("X-Detailed-Error");
}

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx

http://msdn.microsoft.com/en-us/library/system.net.httpstatuscode.aspx

http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

  • The 3 digit HTTP status code does nothing for me. I need to access custom header "X-Detailed-Error" from the remote host's response. Isn't there some way to invoke getresponse() and have it return a webresponse object regardless of what the status code is? – Justin Mar 03 '12 at 16:46
  • I've updated the example. In the case of an exception occurring, you have to grab the `HttpWebResponse` object by using: `$Error[0].Exception.InnerException.Response`, and then you can call the `GetResponseHeader("X-Detailed-Error");` method. –  Mar 03 '12 at 17:00
0

Ever tried the try and catch statements? This works fine for me.

ex:

$webclient = new-object system.net.webclient
try {
    $domain = $webclient.downloadstring("http://xrsolis.com") # get a non existent domain
} catch {
    write-host "domain inaccessible"
}
Andy Arismendi
  • 50,577
  • 16
  • 107
  • 124
  • That doesn't really help because it doesn't let me access the full response from the server. After the server sends the common HTTP status code it also sends a custom header (X-Detailed-Error) with the exact reason why the request was not processed. I need to be able to access that header. $_.Exception returns the same exception message that I would see in the console with no catch statement ( Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (403) Forbidden.") – Justin Mar 03 '12 at 15:23