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