Search code examples
powershellsshsed

Can't use sed when using ssh with ms powershell to linux host


This is working in linux

sed "s/#\?\(PasswordAuthentication\s*\).*$/\1 no/" /etc/ssh/sshd_config;

But in MS Powershell in windows when I using

pwsh -c ssh [email protected] -p 22 sed "s/#\?\(PasswordAuthentication\s*\).*$/\1 no/" /etc/ssh/sshd_config;

I get following error

sed: -e expression #1, char 35: unterminated `s' command

Before I fix encoding issue in powershell so \1 look right. So for now I can't solve this.

$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding

BodyName : utf-8
EncodingName : Unicode (UTF-8)
HeaderName : utf-8
WebName : utf-8
WindowsCodePage : 1200
IsBrowserDisplay : True
IsBrowserSave : True
IsMailNewsDisplay : True
IsMailNewsSave : True
IsSingleByte : False
EncoderFallback : System.Text.EncoderReplacementFallback
DecoderFallback : System.Text.DecoderReplacementFallback
IsReadOnly : True
CodePage : 65001

Edit more info

enter image description here

Is ssh in powershell th issue?

I see the command is changed in debug info

enter image description here


Solution

    • It seems that ssh isn't capable of relaying arbitrary commands with separate arguments that contain \ characters to the remote shell, and simply escaping \ as \\ also does not work.

    • The solution is to pass the entire sed command line as a single argument to ssh:

    # From PowerShell:
    # Note the use of '...''...''...'
    ssh [email protected] -p 22 'sed ''s/#\?\(UsePAM\s*\).*$/\1 no/'' /etc/ssh/sshd_config'
    

    Note:

    • Because PowerShell itself interpolates $-prefixed tokens inside "..." (expandable strings), it is better to use '...' (verbatim strings).

      • Unlike in POSIX-compatible shells such as Bash, you can directly embed ' characters inside '...' by escaping them as '', as shown above.
    • In cases where you do need up-front string interpolation by PowerShell, be sure to escape any pass-through $ characters as `$, i.e. using the so-called backtick, PowerShell's escape character.

      • Note that \ has no special meaning in PowerShell, whereas it functions as the escape character in POSIX-compatible shells, for instance.

      • As an aside: $ chars. that aren't followed by an identifier (e.g., $foo) or start a subexpression (e.g., $(1 + 2)) are left untouched, so there is no strict need to `-escape them, though it's probably better to do so for conceptual reasons; e.g., "5$/" is treated the same as "5`$/" by PowerShell and yields verbatim 5$/ ($ sign retained).
        The same applies analogously to POSIX-compatible shells (except that escaping $ requires \$ there).

    • Your question shows an attempt to call ssh via pwsh -c, i.e. via pwsh, the PowerShell (Core) 7 CLI, which isn't necessary: just invoke ssh directly, as shown above.

      • If you were to call directly from cmd.exe, you'd use "..." for enclosing the sed command line as a whole (cmd.exe only recognizes double-quoting, and doesn't interpret $), and just '...' for the embedded sed script.