3

I have to execute some PowerShell commands on a remote machine from code. For that, I use .net ssh client. Everything works except pipe command interpretation. This code below returns me an error:

DEBUG: 'Stop-Process' is not recognized as an internal or external command, operable program or batch file.

using System.IO;

using Or1WinAppDriverTests.Properties;

using Renci.SshNet;

using Xunit;
using Xunit.Abstractions;

namespace Or1WinAppDriverTests.aidaTests {

    public class AidaMachineSshAccessTests
    {
        public AidaMachineSshAccessTests(ITestOutputHelper output)
        {
            this._output = output;
        }

        private readonly ITestOutputHelper _output;

        [Fact]
        public void SshTest3()
        {
            var host = Resources.HOST;
            var username = Resources.USERNAME;
            var password = Resources.PASSWORD;

            using (var client = new SshClient(host, username, password))
            {
                #region Example SshCommand CreateCommand Execute ExtendedOutputStream

                client.Connect();

                var cmd2 = client.CreateCommand(
                    $"powershell.exe -executionPolicy bypass ;" +
                    $"Get-Process notepad | Stop-Process ;" +
                    $"exit ;");

                var result = cmd2.Execute();

                _output.WriteLine(result);

                var reader = new StreamReader(cmd2.ExtendedOutputStream);
                _output.WriteLine("DEBUG:");
                _output.WriteLine(reader.ReadToEnd());

                client.Disconnect();

                #endregion Example SshCommand CreateCommand Execute ExtendedOutputStream
            }
        }
    }
}
Tatiana
  • 381
  • 4
  • 18
  • 1
    The problem isn't the pipe character. You're trying to start a CMD script over SSH that starts the Windows Powershell executable with a *raw* Powershell script that makes no sense to `CMD` – Panagiotis Kanavos Mar 09 '20 at 16:29
  • 1
    If you want to execute Powershell remotely, use [Powershell remoting](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7). ON Windows this works over WinRM, not SSH (which isn't available to begin with). On Linux and Powershell Core, it works [over SSH](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7). – Panagiotis Kanavos Mar 09 '20 at 16:30
  • If you use Windows 10 or Windows Server 2019, Remoting over SSH is also available. That's transparent to the client though. You don't need SshClient, nor can use use this through the *Windows* executable. – Panagiotis Kanavos Mar 09 '20 at 16:34
  • @PanagiotisKanavos You should probably make an answer out of these comments. I upvoted OP's answer since it works and thus is useful, but the one(s) you are suggesting is way much cleaner. – Pac0 Mar 09 '20 at 16:55
  • @PanagiotisKanavos could you kindly give me the code sample to test? – Tatiana Mar 09 '20 at 17:11
  • [This particular answer](https://stackoverflow.com/a/45638464/134204) shows how to connect and run an entire script on the remote computer. The other answers in that question show how to pass the `ComputerName` attribute to `Invoke-Command. By default, the connection is made using the current user's credentials. [WinRM security](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/winrmsecurity?view=powershell-7) explains the permissions needed (by default only admins can connect), firewall rules, encryption – Panagiotis Kanavos Mar 09 '20 at 17:20
  • @PanagiotisKanavos thanks a lot for the link – Tatiana Mar 09 '20 at 17:23
  • What are you trying to do? In a domain, you don't need SSH, unless you try to run the code from a Mac or Linux machine. Perhaps, if you need to work remotely and run code on Windows Server. Powershell will work just fine over a VPN connection. – Panagiotis Kanavos Mar 09 '20 at 17:25
  • @PanagiotisKanavos I have to run and kill some processes on the remote machine in the local network, both from my local host and from CI runner. – Tatiana Mar 10 '20 at 13:08

1 Answers1

0

It works if I add additional quotes:

var cmd2 = client.CreateCommand(
                    "powershell.exe -executionPolicy bypass; " +
                    "\"Get-Process notepad | Stop-Process\"; " +
                    "exit ;");
Tatiana
  • 381
  • 4
  • 18
  • It doesn't really. There's no need to use `powershell.exe` like this, it *already* offers **secure** remoting. Windows Powershell is getting replaced by Powershell Core already, so `powershell.exe` may or may not work at some point. It will definitely not work with Linux. – Panagiotis Kanavos Mar 09 '20 at 16:55
  • On the other hand, with remoting you could just write `Get-Process -ComputerName thatComputer notepad` – Panagiotis Kanavos Mar 09 '20 at 16:58