1

I'm running a vagrant winrm command, and am noticing that a command that fails doesn't print out the entire error output... I thought | might be used to expand output from such commands... but after some internet searching, and trying a few options, such as:

  • | fl
  • | Format-Table -Wrap -Au

I still get a ... in the final output of my error message, i.e. in the part where the command is echo'd.

NewItemIOError
At line:1 char:1
+ New-Item -path C:\var\lib\kubelet\etc\kubernetes\pki\ -type SymbolicL ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The above failure is happening for a clear and obvious reason, so I don't need help debugging the issue, but rather, am generally wondering what is the right option to use with New-Item to make sure powershell shows me the entire output of its failed execution in automated environments with 10000s of lines of logs.

What's the simplest way to output verbose error messages from new-item, and similar powershell commands?

jayunit100
  • 17,388
  • 22
  • 92
  • 167
  • 1
    Isn't the `...` just for the console output? (That is, don't the error objects contain the entire message?) – Bill_Stewart Jun 07 '21 at 18:37
  • @Bill_Stewart it does, as I described below :) – Karolina Ochlik Jun 07 '21 at 18:44
  • 1
    Correct. It is helpful to remember that, In PowerShell, the _display_ of object _x_ is not necessarily equivalent to the _content_ of object _x_. (Another way to say this is that the displayed output of an object is a formatted representation of that object.) – Bill_Stewart Jun 07 '21 at 18:50

1 Answers1

7

Simply put - dots in exception message in console are only for display purposes - to not give you wall of text. If you want to display the FULL exception you can use something like this:

try {
    New-Item NONEXISTING:\asd.txt -ErrorAction Stop #This will throw error
    Write-Host "If it shows error was not caught"
}
catch {
    $_.Exception | Format-List -Force
}

This displays info like below and gives you full info about Exception object :)

ErrorRecord                 : Cannot find drive. A drive with the name 'NONEXISTING' does not exist.
ItemName                    : NONEXISTING
SessionStateCategory        : Drive
WasThrownFromThrowStatement : False
Message                     : Cannot find drive. A drive with the name 'NONEXISTING' does not exist.
Data                        : {}
InnerException              :
TargetSite                  : System.Management.Automation.PSDriveInfo GetDrive(System.String, Boolean)
StackTrace                  :    at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
                                 at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
                                 at System.Management.Automation.LocationGlobber.GetDriveRootRelativePathFromPSPath(String path, CmdletProviderContext context, Boolean escapeCurrentLocation, PSDriveInfo& workingDriveForPath, CmdletProvider& providerInstance)
                                 at System.Management.Automation.LocationGlobber.GetProviderPath(String path, CmdletProviderContext context, Boolean isTrusted, ProviderInfo& provider, PSDriveInfo& drive)
                                 at System.Management.Automation.SessionStateInternal.NewItem(String[] paths, String name, String type, Object content, CmdletProviderContext context)
                                 at Microsoft.PowerShell.Commands.NewItemCommand.ProcessRecord()
HelpLink                    :
Source                      : System.Management.Automation
HResult                     : -2146233087

For full message or stack trace, just go with $_.Exception.Message or $_.Exception.StackTrace:

try {
    New-Item NONEXISTING:\asd.txt -ErrorAction Stop; #This will throw error
    Write-Host "If it shows error was not caught"
}
catch {
    Write-Host "MESSAGE`n$($_.Exception.Message)"
    Write-Host "STACK TRACE`n$($_.Exception.StackTrace)"
}

and it gives info:

MESSAGE
Cannot find drive. A drive with the name 'NONEXISTING' does not exist.
STACK TRACE
   at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
   at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
   at System.Management.Automation.LocationGlobber.GetDriveRootRelativePathFromPSPath(String path, CmdletProviderContext context, Boolean escapeCurrentLocation, PSDriveInfo& workingDriveForPath, CmdletProvider& providerInstance)
   at System.Management.Automation.LocationGlobber.GetProviderPath(String path, CmdletProviderContext context, Boolean isTrusted, ProviderInfo& provider, PSDriveInfo& drive)
   at System.Management.Automation.SessionStateInternal.NewItem(String[] paths, String name, String type, Object content, CmdletProviderContext context)
   at Microsoft.PowerShell.Commands.NewItemCommand.ProcessRecord()

PS. If you want even more info:

try {
    New-Item NONEXISTING:\asd.txt -ErrorAction Stop
    Write-Host "If it shows error was not caught"
}
catch {
    $_ | Format-List -Force
}

This will display all the info including ScriptStackTrace (at which line the exception occurred):

Exception             : System.Management.Automation.DriveNotFoundException: Cannot find drive. A drive with the name 'NONEXISTING' does not exist.
                           at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
                           at System.Management.Automation.SessionStateInternal.GetDrive(String name, Boolean automount)
                           at System.Management.Automation.LocationGlobber.GetDriveRootRelativePathFromPSPath(String path, CmdletProviderContext context, Boolean escapeCurrentLocation, PSDriveInfo& workingDriveForPath, CmdletProvider& providerInstance)
                           at System.Management.Automation.LocationGlobber.GetProviderPath(String path, CmdletProviderContext context, Boolean isTrusted, ProviderInfo& provider, PSDriveInfo& drive)
                           at System.Management.Automation.SessionStateInternal.NewItem(String[] paths, String name, String type, Object content, CmdletProviderContext context)
                           at Microsoft.PowerShell.Commands.NewItemCommand.ProcessRecord()
TargetObject          : NONEXISTING
CategoryInfo          : ObjectNotFound: (NONEXISTING:String) [New-Item], DriveNotFoundException
FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.NewItemCommand
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 2
PipelineIterationInfo : {}
PSMessageDetails      :
mklement0
  • 382,024
  • 64
  • 607
  • 775
Karolina Ochlik
  • 908
  • 6
  • 8
  • 1
    I would suggest using `$Error[0]` instead of `$_`. – Abraham Zinala Jun 07 '21 at 19:29
  • 1
    @AbrahamZinala, in a `catch` block, `$_` is designed to contain the offending error; you only need the more verbose equivalent `$Error[0]` _outside_ such a block, to refer to the most recent error. – mklement0 Jun 07 '21 at 21:26
  • Wait, I was just quoting you from another post so, does one have the edge on the other? – Abraham Zinala Jun 07 '21 at 21:41
  • 1
    @AbrahamZinala :) Inside a `catch` block, `$_` and `$Error[0]` are equivalent, so while you may use the latter too, it's both more verbose and less obvious. If I recommended use of `$Error[0]` in a `catch` block in an answer of mine, do tell me - it should be revised. – mklement0 Jun 07 '21 at 21:52
  • 1
    It was a comment lol can't remember which one it was but, they posted an answer using `$_` as the error. Will keep that in mind now. Thanks!(: – Abraham Zinala Jun 07 '21 at 21:57
  • 1
    Good answer. I usually use `| Select-Object *` instead of `| Format-List -Force` – Daniel Jun 07 '21 at 22:45