Search code examples
powershellstdinexit

Start program with PowerShell without waiting for input


I was wondering if this Bash command could be converted to PowerShell:

openssl s_client -showcerts -connect host:port </dev/null 2>/dev/null | openssl x509 -noout -dates

The current script (not working):

.\openssl s_client -showcerts -connect host:port 2>$null | .\openssl x509 -noout -dates

The missing </dev/null makes it wait infinitely for input. Is there a PowerShell alternative for that syntax?

<$null doesn't work since < is reserved for future use.



Any suggestions?


Solution

  • The equivalent of </dev/null is @() | ..., as the following simplified example shows:

    # Equivalent of `cat -n </dev/null` in Bash, for instance.
    @() | cat -n
    
    • PowerShell doesn't support the < operator at all, as of PowerShell 7.2;[1] to send data that an external program sees via its stdin stream, it must be piped (|) to it, as shown above.

    • Piping an empty array (@()) effectively provides no stdin input,[2] as </dev/null does in POSIX-compatible shells.

    Note that piping '' or "`0" / [char] 0 does not work, because PowerShell invariably appends a newline to the data, which it invariably sends as text.

    However, there may be an additional problem:

    Your specific command joins two external programs with a PowerShell pipeline, which runs the risk of inadvertent modification of the data being streamed, because this invariably involves decoding as text of the first process' output and re-encoding as text before sending it to the second process - see this answer for more information.

    The workaround is to call the platform-native shell's CLI, whose | operator streams data unmodified; the platform-native shell also allow use of <:

    On Windows, use cmd /c and NUL in lieu of /dev/null:

    cmd /c 'openssl s_client -showcerts -connect host:port <NUL 2>NUL | openssl x509 -noout -dates'
    

    On Unix-like platforms, use sh -c (/dev/null can be used as-is):

    sh -c 'openssl s_client -showcerts -connect host:port </dev/null 2>/dev/null | openssl x509 -noout -dates'
    

    [1] The error message when trying to use < mentions "reserved for future use", but there is no telling if this operator will ever be implemented, and given that the pipeline covers its functionality I'd say that chances are slim.

    [2] The reason is that PowerShell enumerates collections (such as arrays) in the pipeline, i.e. it sends the elements one by one. An empty collection by definition has no elements, so there is nothing to send.