Wednesday, October 5, 2011

InnerException: We have to go deeper.

I helped a co-worker with an interesting issue today.  He was writing a PowerShell script that downloads a file.  He wanted to catch any errors with the download, so he had some code like this:

$client = New-Object System.Net.WebClient
try {
  $client.DownloadFile('http://www/files/file.txt', file.txt)
catch [System.Net.WebException] {
  # $_ is set to the ErrorRecord of the exception
  Out-Log $_.Exception.Message
}

This usually works, returning the text of the error, but this time he was getting back:

An exception occurred during a WebClient request.

That's not a very informative error.  Removing the try/catch blocks, he got this on the screen:


System.Net.WebException: An exception occurred during a WebClient request. ---> System.UnauthorizedAccessException: Access to the path 'C:\Users\tojo2000\hosts.txt' is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean 
...


So obviously the information is in there somewhere.  It turns out that WebException usually returns the error code of the request, but if it runs into an error that is not related to the actual download, it will add the second exception to a property of the WebException object called InnerException.  

So the updated code looks something like this:


$client = New-Object System.Net.WebClient
try {
  $client.DownloadFile('http://www/files/file.txt', file.txt)
catch [System.Net.WebException] {
  # $_ is set to the ErrorRecord of the exception
  if ($_.Exception.InnerException) {
    Out-Log $_.Exception.InnerException.Message
  } else {
    Out-Log $_.Exception.Message
  }
}


Now we get the correct output:


Access to the path 'C:\Users\tojo2000\hosts.txt' is denied.