Reputation: 38941
Why is Powershell 7 (pwsh.exe) NOT outputting the full error when we have a $null
passed to a non-null parameter? And how can I configure my Powershell 7 on my Windows 10 box to fully report it?
Given this script:
param(
[Parameter()]
$Adventurer = "Bilbo"
)
$ErrorActionPreference = 'Stop'
#Requires -Version 7
function Get-SpyResult($FileName) {
$profile = Get-Item $FileName
# ...
}
$x = Get-SpyResult $Adventurer
# ...
Write-Host "If this worked, we would get here."
We can observe the following:
PS C:\temp> $PSVersionTable.PSVersion.ToString()
7.4.1
PS C:\temp> .\here_be_dragons.ps1 "Someone"
Get-Item: C:\temp\here_be_dragons.ps1:10
Line |
10 | $profile = Get-Item $FileName
| ~~~~~~~~~~~~~~~~~~
| Cannot find path 'C:\temp\Someone' because it does not exist.
PS C:\temp>
PS C:\temp> .\here_be_dragons.ps1 $Null
here_be_dragons.ps1: Cannot bind argument to parameter 'Path' because it is null.
PS C:\temp> # Why ??
PS C:\temp>
PS C:\temp> $Error[0]
Get-Item: C:\temp\here_be_dragons.ps1:10
Line |
10 | $profile = Get-Item $FileName
| ~~~~~~~~~
| Cannot bind argument to parameter 'Path' because it is null.
PS C:\temp>
As you can see, Cannot find path
is reported with a stack trace.
But Cannot bind argument to parameter
is not properly reported, you have to resolve the error object manually.
Now, by inspecting the error objects, we can get a clue:
When it works, we have this:
_> $Error[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ActionPreferenceStopException System.Management.Automation.RuntimeException
For the $null
mess we have:
_> $Error[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ErrorRecord System.Object
The actual error objects seem to be generated differently. But that still doesn't explain what this is all about and how I can get my scripts to always report a stack trace.
Upvotes: 1
Views: 52
Reputation: 7501
Part of the issue might be you're executing a script from inside a script, and not dot sourcing it.
You don't have to deal with that extra layer if your script defines functions.
Sometimes it's better to error on Parameter Binding.
Other times it's better to validate after you bind. here I use Get-Item -ErrorAction Stop
to ensure the file exists.
function Get-SpyOnParamBind {
[cmdletBinding()]
param(
[ValidateNotNullOrEmpty()]
[Parameter()] $Filename = 'default.json'
)
"Config: ${Filename}"
}
function Get-SpyOnFileMissing {
[CmdletBinding()]
param(
[Parameter()] $Filename = 'default.json'
)
$config = Get-Item -ea 'stop' $Filename
"Config: ${Filename}"
}
What could be happening is there's more than one error record being created. Check out $error.count
to confirm it.
$error | Join-String -sep "`n`n#####`n`n" -P { $_.Exception }
## or
$error | fl * -force
Upvotes: 0
Reputation: 38941
The problem is that - at least for 7.4.1 - the error display is basically broken/buggy in that it is completely inconsistent. (Both for the COnciseView as well as the NormalView, see below.)
If you run the case above
PS C:\temp> .\here_be_dragons.ps1 $Null
here_be_dragons.ps1: Cannot bind argument to parameter 'Path' because it is null.
PS C:\temp> # Why ??
with ErrorActionPreference = Continue
, then it will even print the stack trace! As opposed to ErrorActionPreference=Stop
.
A current solution / workaround lies in the $ErrorView
variable and in the Get-Error
commandlet of pwsh 7:
Get-Error
to get a (waaay too verbose!) complete view on the last error$ErrorView = 'DetailedView'
to get the same dump of info as with Get-Error
$Error[0]
From what you get back from Get-Error
, you are looking for the InvocationInfo
and the ScriptStackTrace
to identify the location in your script where the error occured.
Upvotes: 0