0

Sometimes, the answer is "no". This turns out not to be a question, but more of a cri de coeur (OK, just complaining).

The Team Foundation Server 2010 PowerShell snap-in exports a cmdlet called Get-TfsPendingChange, which does what it sounds like.

If there are no pending changes, Get-TfsPendingChange echoes "There are no pending changes." on standard output. I never asked it to. The following attempts at suppressing that output all fail:

$pcs = $(Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r ) | out-null;

$($pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r ) | out-null;

$pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r | out-null;

I'm not getting errors, but the text output is not redirected. What IS redirected, is the normal successful output of the cmdlet, in the case where there are pending changes for it to return. The ONLY output you can suppress is the useful output. If there are zero pending changes, you get text garbage via stdout. If there are any actual pending changes, that stream (of objects, not text) can be redirected to the null device, but that's worse than useless.

So it appears that text on stdout is a side effect from this cmdlet, not the cmdlet's output, and it cannot be redirected in PowerShell. The PowerShell redirect operators > and |, without the fileno specifiers (2 in PS2, 2, 3, 4, 5, and * in PS3/PS4), work on the object stream, which is not stdout. This would be fine if stdout had been replaced by this new object stream concept (or if some genius on the TFS team hadn't decided that cmdlets should spew random text noise in all directions as a side effect).

The garbage output definitely is on stdout, not stderr. I can redirect the standard output of the whole script to nul when I run it from cmd.exe, and that works as expected, because duh:

c:\>powershell .\tfstest.ps1 > nul

However, I do not want to suppress all the output from the entire script. Just the output from one snapin cmdlet. It's not the end of the world, but it's irritating to have random stuff that I call echoing garbage I have no control over. The script otherwise works correctly (see UPDATE).

One workaround would be to prefix everything I want to echo on stdout with some arbitrary string (say "KLUDGEPREFIX"), and run the whole mess from a batch file which pipes the PowerShell script's output through find /v KLUDGEPREFIX and then through a PowerShell fragment that strips off the prefix from each line.

Instead, I'm going to write the rest of the script around the problem so it looks like what they get is what I intended, because, in fact, I was going to tell them they didn't have any pending changes anyhow. It's been a valuable exercise, however, in terms of getting my head inside PowerShell.

UPDATE: This script turned out to be fragile, unreliable, glacially slow, and impossible to run on any computer but the one where I originally wrote it.

I replaced it with a Perl script that took 1/10 the time to write, executed 10 times as fast, and does the same task better without any foolishness. PS and the TFS PS snap-in are great ideas but they both need a lot of work before they'll be ready for release.

2 Answers2

1

I'm not familiar with Team Foundation Server, but most likely the cmdlet writes to the host rather than one of the output streams. Output to the host cannot be redirected in PowerShell, but if you run a PowerShell script in CMD the host output goes to STDOUT (as does the success output stream) and can be redirected there.

Demonstration:

PS C:\> cat .\test.ps1
Write-Host 'foo'
PS C:\> .\test.ps1 | Out-Null
foo
PS C:\> .\test.ps1 >$null
foo
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1
foo
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1 `>nul
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1 >$null
PS C:\> _
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
-1

if you add 2 in front of the > it will only redirect error. likewise with 1 for non errors (stdout). So if you want all stdout, but not stderr to go away you can type

$pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r 1> $null

$null can be used as an equivalent to /dev/null. your code probably creates the file "nul" on disk.

Snorre
  • 955
  • 1
  • 5
  • 18
  • 3
    Output redirection is documented in [about_redirection](http://technet.microsoft.com/en-us/library/hh847746.aspx). – vonPryz Dec 17 '13 at 17:42
  • `Get-TfsPendingChange : A positional parameter cannot be found that accepts argument '1>'.` – 15ee8f99-57ff-4f92-890c-b56153 Dec 17 '13 at 18:14
  • In batch files, `nul` with one "L" [is the null device that you redirect to](http://stackoverflow.com/questions/4507312/how-to-redirect-stderr-to-null-in-cmd-exe). – 15ee8f99-57ff-4f92-890c-b56153 Dec 17 '13 at 18:18
  • The `stderr` part is irrelevant. Everything else in your answer is at least partly wrong. `1>` is an error. `nul` is well-known. Correct redirect to `$null` with `>` at least doesn't throw an exception, but it unfortunately discards the useful output of the cmdlet while having no effect on `stdout`. $pcs will always be empty in the example you give, and the garbage output will not be suppressed. – 15ee8f99-57ff-4f92-890c-b56153 Dec 17 '13 at 18:55
  • @EdPlunkett: I believe you are confused: the question and this answer are both (primarily) discussing *PowerShell* scripts, not Cmd scripts. In PowerShell, (as per the link vonPryz posted), `2>` and redirecting to `$null` are both perfectly correct. However, I suspect there may be an issue with missing brackets in the line that Snorre posted that causes the error you first reported. – Dan Puzey Dec 18 '13 at 14:39
  • @DanPuzey I stated clearly in the OP that the error stream is irrelevant. In PowerShell 2.0, `1>` is an error. Try it for yourself. In the OP, it is very clear that the redirect to `nul` was done in a cmd script. In my first comment above, I stated the same again. Perhaps I expressed myself poorly, but batch files and cmd scripts are in fact the same thing. Again, try it. Don't take my word for it. I very clearly stated that the problem with `1> $null` was the `1`, not the `$null`. And you can "suspect" all you like about his code, but I actually ran it. Are you trolling me? – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 14:50
  • @DanPuzey In short, re-read everything I wrote. Everything you mention, you misunderstood. There may be other stuff I got wrong (or I wouldn't be here!), but thank you, I do know what `nul` means in a batch file. And I know what I was asking about in the OP, too. – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 14:51
  • @EdPlunkett: you're adding "Powershell 2" as a (fairly vital!) restriction on your question added far too late for either this answer or my comments to take it into consideration. Edit your question to include that restriction! The OP is clear that redirection to `nul` was in a cmd script; equally this answer is clearly giving a *PowerShell* line in which `$null` is valid. "Am I trolling you?" No; I'm trying to help someone who's criticising what is a reasonable attempt at solving the problem, but if you'd rather be hostile then I'm happy to help elsewhere. – Dan Puzey Dec 18 '13 at 15:06
  • @DanPuzey I've not tested `1>` in other versions of PS, [but it is not documented for 3 or 4](http://technet.microsoft.com/en-us/library/hh847746.aspx) either. Test it. Nobody said `$null` or `2>` wasn't valid. `2>` is irrelevant because the problematic output wasn't the error stream. He said that what I did would create a file called `nul`. That was wrong. It is OK to correct wrong information on SO. He wanted me to redirect the object stream to `$null`. No. The question was how to *keep* the object stream. "Wanna keep it? Redirect it to null!" Sigh... – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 15:52
  • @DanPuzey The issue here is that when you redirect cmdlet output in PowerShell, the redirects do not operate on the old `stdout` and `stderr` text streams. They operate on new-fangled object streams, which are a big part of PS. *However, the text streams still exist, separately.* This is the OP's issue. Snorre didn't address it. I completely failed to grasp it, until well after I posted the question. I'm guessing it's not common for cmdlets to print anything on `stdout` as a side effect. Go "help" somebody else, you've done enough here. – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 16:00
  • `1>` works fine here in PS4, though it doesn't solve your problem. Incidentally, I've tested this with the TFS 2012 powershell snapin and don't see the junk output - so perhaps you can further clarify your question with the exact versions you're using? – Dan Puzey Dec 18 '13 at 16:01
  • @DanPuzey TFS 2010. Note that Get-TfsPendingChange (2010) only echoes this stuff if it finds no pending changes to return. – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 16:14
  • I read that part. 2012 does not have this problem: can you upgrade? I believe the power tools are backward compatible. – Dan Puzey Dec 18 '13 at 16:30
  • @DanPuzey Yep, I just might install the 2012 powertools, and document that in the script for others using it. – 15ee8f99-57ff-4f92-890c-b56153 Dec 18 '13 at 17:08