37

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?

6 Answers 6

51

If you want to suppress only standard error, use:

svn info $url 2>$null
Sign up to request clarification or add additional context in comments.

Comments

36

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.

6 Comments

Also, if you have a larger command you can wrap it in $() | out-null to get the same effect. For example: $( svn info $url 2>&) | out-null`. I do this when the command is very long, or I need to break it over a few lines in a script.
@Nick: Ah, thanks. However, wouldn't it have to be $( svn info $url ) 2>&1 | out-null? (Note the placement of the 2>&1.)
Oh wow, I completely misread your post. Yes, it should be $(svn info $url) | out-null. It depends on where you want the error checking to happen for the 2>&1. I can't say without testing it, but I don't think it should matter if it is inside the ) or outside. You might actually be able to just leave the 2>&1 off completely, like I said, without testing I can't be sure.
it works, but if you use it in a script, it will cause the error to stop the script. This might not be an intended side effect.
I cam across this because I had a git commit that I couldn't get to stfu when being ran via PowerShell... I'm very close to having PS instead invoke 'git bash' t handle the git stuff. At least I can trust bash to silence stuff.
|
10

One can also do this:

svn info $url *> $null

See Suppress console output in PowerShell

about_Redirection

1 Comment

Or svn info $url 2> $null for stderr only.
5

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

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

3 Comments

Redirecting stderr to stdout will still generate an error and stop script execution if you have $ErrorActionPreference = 'Stop'. But the error will not happen if you do not redirect stderr to stdout. Weird!
@RafałKłys: Weird, indeed; it is a bug: see github.com/PowerShell/PowerShell/issues/4002
For anybody tracking this, that was duped to github.com/PowerShell/PowerShell/issues/3996 and there will be a fix in version v7.1.0 (still in preview), maybe hidden behind the flag PSNotApplyErrorActionToStderr
5

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, i.e. 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.

1 Comment

"Redirections such as 2>&1 act on individual commands in a pipeline, not the pipeline as a whole." - This is what solved the problem I was having.
0

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 (e.g. 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.

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.