Reputation: 63
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
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.'
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.
-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