Sessl
Sessl

Reputation: 63

ErrorVariable output

I'm searching for two days now for a solution or something that helps me to understand why.

For some actions I want to send any error to the "-ErrorVariable create_error". No problem. After that, I just want the exception of the error message:

$create_error = $create_error.Exception

The output of the variable is now:

$create_error
Access to the path '2021' is denied.

But if I use this variable as body text for an email, I get the following email text:

    System.UnauthorizedAccessException: Access to the path '2021' is denied. 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.Directory.InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, Boolean checkHost) 
    at System.IO.DirectoryInfo.CreateSubdirectoryHelper(String path, Object directorySecurity) 
    at System.IO.DirectoryInfo.CreateSubdirectory(String path) 
    at Microsoft.PowerShell.Commands.FileSystemProvider.CreateDirectory(String path, Boolean streamOutput)

Sendmail:

Send-MailMessage -To $to -From $from -Subject $subject -Body $create_error

Any ideas how I get in an email only the human readable error message?

Thank you! Best regards!

Upvotes: 2

Views: 4506

Answers (1)

mklement0
mklement0

Reputation: 437823

tl;dr:

To get just the error messages associated with PowerShell error records collected with the common -ErrorVariable parameter:

$create_error.ForEach('ToString') # Call .ToString() on all records

Note: If your variable contains only a single error record (not wrapped in a collection), simply call .ToString(), such as when accessing a single error in the session-wide automatic $Error collection:

Get-Item NoSuch -ErrorAction SilentlyContinue # provoke an error
# Access the most recent error individually:
$Error[0].ToString() # -> 'Cannot find path '...\NoSuch' because it does not exist.'

Background information:

The common -ErrorVariable parameter collects the non-terminating errors that occur during execution of a given command as System.Management.Automation.ErrorRecord objects in an array-like collection (System.Collections.ArrayList) - even if only one error is collected.

  • Note: Terminating errors, by contrast - which cmdlets rarely emit - abort the entire command, so that requests to collect the command's own stream output with common parameters such as -ErrorVariable and -OutVariable are not honored. To handle such errors, you need a try ... catch ... finally statement. See this answer for details, and this GitHub docs issue for a comprehensive overview of PowerShell's surprisingly complex error handling.

These error records wrap .NET exceptions by supplementing them with additional, PowerShell-relevant metadata, such as the location of the error in a script file (*.ps1).

There are two separate fields that may contain the message (string) that characterizes the error at hand best:

  • .Exception.Message

  • optionally, .ErrorDetails.Message, which can be used to override .Exception.Message in the default display format of the error in the console.

The .ToString() method wraps this logic, so it is the simplest way to get the error message.


Sample code:

Note: Typically, .ErrorDetails is $null. Setting it requires an extra step when constructing an error record.
Here's an example in PowerShell (though note that it's more common to construct error records in compiled cmdlets):

# Create an error record.
$err = [System.Management.Automation.ErrorRecord]::new(
  [InvalidOperationException]::new('foo'),  # the exception being wrapped
  'errId',             # error ID
  'InvalidOperation',  # category 
  $null                # the target object
)
# Then assign an ErrorDetails instance with a custom message.
$err.ErrorDetails = [System.Management.Automation.ErrorDetails] 'bar'

Now, $err.Exception.Message reports 'foo', and $err.ErrorDetails.Message 'bar'. When you call .ToString(), the .ErrorDetails.Message value takes precedence; if .ErrorDetails were $null, 'foo' would be reported:

PS> $err.ToString()
bar

Upvotes: 9

Related Questions