88

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.

darthbith
  • 18,484
  • 9
  • 60
  • 76
Lucas
  • 883
  • 1
  • 6
  • 4
  • 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`. – Ohad Schneider Aug 04 '16 at 12:01
  • Possible duplicate of [Ignoring an errorlevel != 0 in Windows PowerShell](https://stackoverflow.com/questions/1394084/ignoring-an-errorlevel-0-in-windows-powershell) – Ohad Schneider Feb 06 '19 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 – Oly Dungey Oct 02 '19 at 15:58
  • 10
    But why is there an error? No-one seems to be explaining that bit. What is this NativeCommandError complaining about exactly? – codeulike Jun 19 '21 at 21:39
  • 1
    @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. – Michiel van Oosterhout Jul 25 '23 at 08:35

6 Answers6

64

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 | %{ "$_" }
Community
  • 1
  • 1
sschuberth
  • 28,386
  • 6
  • 101
  • 146
  • 32
    **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](https://stackoverflow.com/a/2095623/2809027) discards all stderr (*blatantly harmful!*) and the [next answer](https://stackoverflow.com/a/16334189/2809027) 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. – Cecil Curry Jun 07 '19 at 07:15
  • 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` – Ignitor Jul 01 '19 at 07:28
  • 2
    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. – aggieNick02 Oct 18 '19 at 16:08
  • 1
    If you are using $ErrorActionPreference="Stop", you can set it to "SilentlyContinue", run this line, and then set it back to "Stop". – Marco van Hilst Feb 04 '21 at 10:55
55

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.

Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • Worked fine with PSEXEC! Thanks! – Akira Yamamoto Dec 05 '13 at 16:56
  • 5
    In general case it's a bad idea to hide stderr, better to redirect it to stdout. – Ivan Oct 20 '16 at 08:55
  • But, the value of `$?` is still `False`? Or maybe this is only in my specific scenario (running `docker-compose` commands remotely). – Anthony Mastrean Dec 06 '17 at 15:44
  • 6
    This answer discards stderr and **is therefore fundamentally insane.** See [sschuberth](https://stackoverflow.com/users/1127485/sschuberth)'s answer for a [one-liner redirecting stderr to stdout *and* preserving the standard option passing syntax](https://stackoverflow.com/a/20950421/2809027) – unlike the [next answer](https://stackoverflow.com/a/16334189/2809027), which syntactically breaks down when passing options. – Cecil Curry Jun 07 '19 at 06:52
54

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'
Aage
  • 5,932
  • 2
  • 32
  • 57
Simon Ejsing
  • 1,455
  • 11
  • 16
  • This one worked for me where I couldn't use the answer from KeithHill. Thanks SimonEjsing! – mbourgon Oct 03 '13 at 14:41
  • This worked for me, without executing in the cmd context I still got the error. – Jon H Jan 07 '16 at 15:59
  • 6
    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.) – user2441511 Oct 05 '16 at 18:25
  • 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')` – drizin Aug 03 '19 at 04:26
  • If you're doing redirection, or have $ErrorActionPreference="Stop", this is currently the only answer that works. – aggieNick02 Oct 18 '19 at 16:09
  • @user2441511, I saw your comment late so i put arguments before the redirect which seemed to work too. Anyways good answer. Was searching for an hour already. – The Fool Jan 08 '21 at 13:41
3

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
Mike Gledhill
  • 27,846
  • 7
  • 149
  • 159
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
}
Barry MSIH
  • 3,525
  • 5
  • 32
  • 53
  • 1
    If you can fill the rest of the code to make it compilable, as it currently it the code is not valid. – sean Feb 17 '17 at 20:40
  • NOTE: `$ErrorActionPreference="stop"` is needed for the catch block to actually be entered – recvfrom Jun 03 '21 at 17:12
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}
mohamed saeed
  • 147
  • 1
  • 6