99

I have a PowerShell script that uses du.exe (Disk Usage originally from Sysinternals) to calculate the size of directories.

If I run du c:\Backup in the console, it works as expected, but the same line of code run in ISE or PowerGui gives the expected result plus the error

+ du <<<<  c:\backup
+ CategoryInfo          : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Why is that? How do I avoid this error? I tried invoke-expression, using &, but no go.

Thanks for the help.

5
  • 5
    Note that if you have $ErrorActionPreference set to Stop this will actually stop your script's execution. My solution was to set it to Continue, invoke the command, and set it back to Stop. Commented Aug 4, 2016 at 12:01
  • Possible duplicate of Ignoring an errorlevel != 0 in Windows PowerShell Commented Feb 6, 2019 at 17:10
  • 1
    @OhadSchneider Thanks, you've saved me days of pain! I just couldn't fathom why my script results were different when running in my Docker container and $ErrorActionPreference = 'Continue' fixed the problem Commented Oct 2, 2019 at 15:58
  • 16
    But why is there an error? No-one seems to be explaining that bit. What is this NativeCommandError complaining about exactly? Commented Jun 19, 2021 at 21:39
  • 4
    @codeulike Some PowerShell hosts complain about the fact that a native command (basically an executable, as opposed to a PowerShell cmdlet) wrote to stderr. Some native commands use stderr as a verbose output stream, which can be redirected to /dev/null or nul by the user if they are not interested in the verbose output. A PowerShell host should check the exit code of the native command to decide if output on stderr should be interpreted as a NativeCommandError or not. But regardless, in PowerShell, stderr output will be wrapped in an ErrorRecord, that's just how it is. Commented Jul 25, 2023 at 8:35

7 Answers 7

73

Another way to suppress the NativeCommandError output is to convert the objects in the pipeline to strings as outlined at the bottom of this answer:

du c:\Backup 2>&1 | %{ "$_" }
Sign up to request clarification or add additional context in comments.

7 Comments

I hate you, PowerShell. Despite the profundity of this loathing, I applaud the insanity embedded within the above one-liner. Yes, it's unreadable. But what isn't? This is the definitive solution. Whereas the accepted answer discards all stderr (blatantly harmful!) and the next answer defers to CMD.exe (even less readable than this solution when passing options!), this answer both redirects stderr to stdout and preserves the standard option passing syntax.
Note that when you want to redirect the stdout as well (for example, to a file), you need to do that after converting the objects to strings: du c:\backup 2>&1 | %{ "$_" } >outputfile.txt
Second your sentiments @Cecil Curry. Please note that while I like this answer for how clean it is, it unfortunately does not work with $ErrorActionPreference="Stop". So the cmd /c wrapping is what I've had to resort to. Sigh.
If you are using $ErrorActionPreference="Stop", you can set it to "SilentlyContinue", run this line, and then set it back to "Stop".
This does work, but it is slow, its one of the reasons I created github.com/Luiz-Monad/PowershellProcess . So I can capture stdout/stderr as string arrays and pass then in batch over the pipeline so my functions can consume output from cmake (don't ask why).
|
58

I've recently been facing the same issues, but I would like to get the stderr output directed to stdout. You would think that the following would work:

    & du 2>&1

But PowerShell will interpret the redirection and process it after 'du' is completed. The work-around I found is to invoke it using cmd.exe /c:

    & cmd /c 'du 2>&1'

6 Comments

This one worked for me where I couldn't use the answer from KeithHill. Thanks SimonEjsing!
This worked for me, without executing in the cmd context I still got the error.
This worked for me. I was also needing to pass in options, so the full syntax for me was & cmd /c 'foo.exe 2>&1' option1 option2. (Note that only the executable name and the 2>&1 go inside the single quotes.)
Actually you can put the redirection at the end, and can have paths with spaces (surrounded by quotes), etc. Example: cmd /c ('"' + $ezfuscator + '" ' + $obfuscatedFolder + $targetName + '.exe' + ' -k ..\strongkey.snk' + ' 2>&1')
If you're doing redirection, or have $ErrorActionPreference="Stop", this is currently the only answer that works.
|
53

To avoid this you can redirect stderr to null e.g.:

du 2> $null

Essentially the console host and ISE (as well as remoting) treat the stderr stream differently. On the console host it was important for PowerShell to support applications like edit.com to work along with other applications that write colored output and errors to the screen. If the I/O stream is not redirected on console host, PowerShell gives the native EXE a console handle to write to directly. This bypasses PowerShell so PowerShell can't see that there are errors written so it can't report the error via $error or by writing to PowerShell's stderr stream.

ISE and remoting don't need to support this scenario so they do see the errors on stderr and subsequently write the error and update $error.

3 Comments

In general case it's a bad idea to hide stderr, better to redirect it to stdout.
But, the value of $? is still False? Or maybe this is only in my specific scenario (running docker-compose commands remotely).
This answer discards stderr and is therefore fundamentally insane. See sschuberth's answer for a one-liner redirecting stderr to stdout and preserving the standard option passing syntax – unlike the next answer, which syntactically breaks down when passing options.
8

After pulling a load of hair out, I realised that actually, these errors only occur when running the .ps1 file from "Windows PowerShell ISE".

When I ran the same .ps1 script from a Command Line, the errors didn't happen.

powershell.exe .\MikesScript.ps1

2 Comments

doesn't work for me
Running in PowerShell ISE was my issue as well. Running the script from a normal PowerShell window worked for me.
2

Previous FIX will redirect errors but you could lose a real error if by example your user name or password is not good or if using integrated authentication, you do not have access.

So here is a way to implement the error handling and bypass the specific error (that is not one) raised by psexec.

try {
    whoami # powershell commands
}
catch [System.Management.Automation.RemoteException] {
    if ($_.TargetObject -like "Connecting to *" -and $_.CategoryInfo.Category -eq "NotSpecified" -and $_.FullyQualifiedErrorId -eq "NativeCommandError" -and $_.InvocationInfo.MyCommand.Name -like "psexec*.exe") {
        $error.Remove[$Error[0]]
    }
    else {
        Throw
    }
}        
catch {
    throw
}

2 Comments

If you can fill the rest of the code to make it compilable, as it currently it the code is not valid.
NOTE: $ErrorActionPreference="stop" is needed for the catch block to actually be entered
0

Write this script at the top of your PowerShell script it will solve this issue and even it will not affect the whole behavior of all error commands

#prepare powershell for docker-compose commands
        if((select-string -Path $profile -Pattern "Set-Alias docker-compose 'docker-compose.cmd'") -eq $null ){
           Add-Content -Path $profile -Value "Set-Alias docker-compose 'docker-compose.cmd'"}
$str = "@echo off
        docker-compose.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 2>&1"
        if ((Get-Content "C:\Windows\System32\docker-compose.cmd" -ErrorAction Ignore) -ne $str){
            $str.Trim() | Out-File "C:\Windows\System32\docker-compose.cmd" -Encoding ascii}

Comments

0

I'm calling Pandoc from a PowerShell Azure Function, and I was having issues getting what I needed from the solutions here:

  • Detect whether or not an error occurred
  • Get the error message from said error
  • Don't abrubtly terminate the script

What finally worked was a solution based on this ServerFault post and which incorporates a lot of ideas on this page.

While not shown below, I do have ErrorActionPreference = 'Stop' set in my Function, though I don't know if this is required for the below to work as intended.

$Output = $null
$InputText | pandoc -f $InputFormat -t $OutputFormat 2>&1 | ForEach-Object { if ($_.GetType().Name -eq "ErrorRecord") { $Output += $_.Exception.Message + "`n" } else { $Output += $_ + "`n" } }
$Output = $Output.Trim()

if ($LASTEXITCODE -eq 0) {
    # Do something appropriate for a success.
}
else {
    # Do something appropriate for a failure.
}

And, yes, the above only works for input and output formats which work with stdin and stdout. This is just an example, not a full solution :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.