1

I have this simple powershell script which simply reads the arguments from stdin. Nothing else. The problem I have is that this also prints what it reads. How can I stop that? The end goal I have with this is writing a program that takes a file (input via stdin), transforms it, then outputs to stdout. But if it's going to output the input first, the whole thing won't work, so I am already blocked at the first step.

$lines=while($x=read-host){$x}

$lines

Called like this:

echo hello | powershell .\myScript.ps1

Expected output:

hello

Actual output:

hello
hello

What can I do to avoid this problem? My expectation would have been that it doesn't output the result of the assignment.

Of course I can workaround by simply taking the file name as parameter instead, but I would like to learn how this use case can be made to work.

kutschkem
  • 7,826
  • 3
  • 21
  • 56

2 Answers2

1

You can bypass your problem by using a better solution for collecting all stdin input: the automatic $input variable:

# Collect all lines from stdin.
$lines = @($input)

$lines

Note that $input is an enumerator for the lines of text provided via stdin, and enclosing it in @(…), the array-subexpression operator, forces its enumeration, so that $lines ends up containing an array of lines (an [object[]] array containing [string]s) representing all stdin input.

Then, be sure to invoke your script via the -File parameter of powershell.exe, the Windows PowerShell CLI:

# Note the use of -File
echo hello | powershell -File .\myScript.ps1

Note:

  • When using neither -File nor -Command, -Command is implied in powershell.exe (Windows PowerShell) (whereas it is now -File in pwsh, the PowerShell (Core) CLI).

  • Thus, your original command implicitly uses -Command, which would require use of $input as part of the command too:

    # Less efficient equivalent of the above.
    echo hello | powershell -Command "$input | .\myScript.ps1"
    
  • However, when invoking script files (.ps1), use of -File is generally preferable, not least because -Command subjects the script path and any pass-through arguments to an extra round of interpretation - see this answer for guidance.


As for what you tried:

Read-Host echoes to the console what the user types / what is provided via stdin, in addition to returning it as data.

You cannot suppress this echoing from inside PowerShell, and to the outside caller the echoed Read-Host response is indistinguishable from intentional data output.

Use of $input avoids this problem, and is the preferable and more efficient solution to begin with.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

You're outputting content twice, so you get it twice. Just remove $lines and you're good to go :)

$lines=while(
    $x=read-host
    ){
        $x
    }

echo hello | pwsh .\myscript.ps1

I've added a pause to validate, just after the function. enter image description here

Also - if you ever have an .exe that would output some sort of text you can try a few things.

Redirect it to null

$null = & $someExe

Void it

[void] (& $someExe)

Redirect all output to null

& $someExe *>$null

enter image description here

  • That's not helping, what I am actually trying to avoid is outputting the result of the assignment. Can you show how to do that? Can I somehow redirect the output of the assignment? Is an assignment just syntactic sugar for Set-Variable? – kutschkem Mar 24 '23 at 12:14
  • 1
    The undesired output is the uncontrollable side effect of collecting stdin input via repeated `Read-Host` calls: `Read-Host` prints what was "entered" directly to the console, outside PowerShell's system of output streams. As such, you cannot silence this output from _inside_ PowerShell, and PowerShell redirections don't help (to the outside caller, this output is stdout output, just like _intentional_ output from the script). As an aside: it doesn't make sense to use `>>` with `$null` (though it does no harm), and you probably meant `$null = ...` or `[void] (...)`, not `$void = ...` – mklement0 Mar 24 '23 at 14:34
  • Correct, haven't used it as of late so my mistake – Sebastian Wiszowaty Mar 24 '23 at 15:18