Searching for matches in a non-cmdlet's output

I'm evidently misunderstanding something about PowerShell's piping (I'm quite new to the language).

I'm trying to "grep" for a certain match in the help menu of ssh-keygen. For a simple example, I'm trying to find every line that contains a "C" (I don't care about case at the moment). I tried:

ssh-keygen /? | Select-String "C"

The problem is, ssh-keygen appears to be attempting to consume the entire rest of the command, since I get this output:

PS C:\Users\user\tests> ssh-keygen /? | Select-String "C"
Too many arguments.
usage: ssh-keygen [-q] [-b bits] [-C comment] [-f output_keyfile] [-m format]
. . .

If, however, I try to do a similar operation on a (python script) file that I read in, it works as I'd expect:

PS C:\Users\user\tests> Get-ChildItem .\produce_image.py | Select-String "def"

produce_image.py:12:def draw_mandelbrot_with(canvas_dimensions: Tuple[int, int],
produce_image.py:38:def par_iterate_mandelbrot_with(canvas_dimensions: Tuple[int, int],
. . .

I'm guessing this has something to do with the fact that ssh-keygen is a standalone executable, whereas Get-ChildItem is a cmdlet, and they're writing to different streams? Or something like that?

I'd just like to know how to search through the output of non-cmdlets using PowerShell. Any help here would be appreciated. I'm using PowerShell 7 in case that's at all relevant.


Solution 1:

The command ssh-keygen /? issues its output to stderr (stream 2), while the pipe (|) is passing through only stdout (stream 1).

You should rather use:

ssh-keygen.exe /? 2>&1 | Select-String "C"

The 2>&1 will redirect stderr to stdout so it can be passed on to the following command.