简体   繁体   中英

How do I suppress standard error output in PowerShell?

In a PowerShell script automating some SVN tasks I have the following function:

function SvnUrlExists($url)
{
  svn info $url | out-null 2>&1
  return $?
}

Since this explicitly tests whether some SVN repository URL exists, I am not interested at all in any error output. However, despite everything I found about redirecting stderr in PowerShell suggesting 2>&1 to redirect it to stdout , this still outputs an error message :

svn: warning: W170000: URL 'blahblah' non-existent in revision 26762
svn: E200009: Could not display info for all targets because some targets don't exist

Unfortunately, this severely messes up the output of my script.

What am I doing wrong, and how should I suppress this error output?

Just in case someone else googles for similar terms as I did:

After I have been banging my forehead against this for hours, of course I found the solution within minutes after posting the question here:

svn info $url 2>&1 | out-null

This works like a charm.

如果要抑制的唯一标准错误,使用:

svn info $url 2>$null

One can also do this:

svn info $url *> $null

See Suppress console output in PowerShell

about_Redirection

The voted answer generates an error for me. The solution ended up being the following:

cmd /c "MyProgram MyArguments 2>&1" | Out-Null

tl;dr

function SvnUrlExists($url)
{

  # Suppress all output streams (external stdout and stderr in this case)
  # To suppress stderr output only, use 2>$null
  svn info $url *>$null 

  # For predictable results with external programs, 
  # infer success from the *process exit code*, not from the automatic $? variable.
  # See https://github.com/PowerShell/PowerShell/issues/10512
  $LASTEXITCODE -eq 0
}

Your own answer effectively addresses the redirection issue .

Steven Penny's answer proposes *>$null , ie suppressing all output streams as a convenient alternative - it obviates the need for Out-Null , which I generally suggest replacing with $null = ... - see this answer .

However, there's another problem with the code in your question:

While it may work with your particular command, $? , unfortunately, is not a robust indicator of whether an external program succeeded or not - use $LASTEXITCODE -eq 0 instead, because - due to a bug as of PowerShell Core 7.0.0-preview.3, reported on GitHub here - $? can end up reflecting $false even when $LASTEXITCODE is 0 (unequivocally signaling success).

  • Update : If and when the pre-v7.2 experimental feature named PSNotApplyErrorActionToStderr becomes an official feature, this problem will go away - see this answer for more information.

As for what you tried in your question:

svn info $url | out-null 2>&1  # WRONG
  • Only success output is sent through to the pipeline ( stdout output from external programs is sent to PowerShell's success output stream ).

  • Redirections such as 2>&1 act on individual commands in a pipeline, not the pipeline as a whole .

  • Therefore, if svn info $url produces stderr output, it prints straight to the host (console) - Out-Null never sees it.

Important to note is that some Powershell cmdlets do not behave correctly with these methods. Such an example is Get-ADUser which will output the error in case of failure no matter what trick you use:

PS C:\Temp\2022-09-05T08-28-46_oexvijzd.tfq> Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" 2>&1 | Out-Null
Get-ADUser : Directory object not found
At line:1 char:1
+ Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" 2>&1 | Ou ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (CN=administrator,DC=acme,DC=internal:ADUser) [Get-ADUser], ADIdentityNotFoundException
    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
PS C:\Temp\2022-09-05T08-28-46_oexvijzd.tfq> Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" *>$null
Get-ADUser : Directory object not found
At line:1 char:1
+ Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" *>$null
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (CN=administrator,DC=acme,DC=internal:ADUser) [Get-ADUser], ADIdentityNotFoundException
    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
PS C:\Temp\2022-09-05T08-28-46_oexvijzd.tfq> Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" *>$null | Out-Null *>$null
Get-ADUser : Directory object not found
At line:1 char:1
+ Get-ADUser -Identity "CN=administrator,DC=acme,DC=internal" *>$null | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (CN=administrator,DC=acme,DC=internal:ADUser) [Get-ADUser], ADIdentityNotFoundException
    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser

In these cases, you will have to make try / catch blocks, or find other alternatives (eg Checking for the existence of an AD object; how do I avoid an ugly error message? ).

Hope this will save someone some unproductive head scratching.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM