PowerShell 7.x supports SSH for cross-platform remoting. Learn how to configure and test PowerShell remoting between Windows, Linux, and macOS systems.
Latest posts by Timothy Warner (see all)

Imagine the server fleet you manage comprises both Windows Server- and Ubuntu Linux-based systems. Historically, you used Windows Remote Management (WinRM) PowerShell remoting to administer the Windows nodes and Secure Shell (SSH) to manage the Linux nodes.

However, now that .NET Core and PowerShell 7.x are rapidly maturing, you decide to standardize on PowerShell to remotely administer all your server nodes. To accomplish this, you want to use SSH as your transport protocol instead of WinRM (which you'll remember is Microsoft's implementation of the vendor-neutral WS-Man protocol).

In my lab environment, I have a Windows 10 VM named (imaginatively enough) windowsvm and an Ubuntu 16.04 VM named linuxvm. These machines reside on the same virtual network, and I've configured firewall allowances to support bi-directional SSH traffic between the machines. Recall that SSH uses Transmission Control Protocol (TCP) port 22 by default.

I have PowerShell 7.1.0 installed on both VMs. Please note that the SSH remoting configuration steps I teach here for Windows 10 apply equally to Windows Server 2019.

Prepare the Windows 10 system for SSH-based PowerShell remoting

We need to install OpenSSH on our Windows 10 workstation. If you're running Windows 10 build 1809 or later, the client and server tools are included. Run the following commands from an elevated console session:

Add-WindowsCapability -Online -Name OpenSSH.Client~~~~
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~

Next, set the SSH server service to start automatically, and then start up the service:

Set-Service -Name sshd -StartupType 'Automatic'
Start-Service -Name sshd

I suggest you use the Microsoft PowerShell team's wonderful RemotingTools module to simplify configuring SSH-based remoting. You can install the module directly from the PowerShell Gallery:

Install-Module -Name Microsoft.PowerShell.RemotingTools	
Import-Module -Name Microsoft.PowerShell.RemotingTools

The RemotingTools module contains a single cmdlet, called Enable-SSHRemoting, that performs the following actions:

  • Detects the operating system (Windows, macOS, Linux)
  • Detects the SSH client and server
  • Creates an SSH-based remoting endpoint
  • Updates the SSHD configuration file

Go ahead and run the cmdlet and follow the prompts. I show you a screenshot of the process in the following figure. Oh, make sure you restart the sshd service after the command completes.

Enable-SSHRemoting -Verbose
Restart-Service -Name sshd
Enable SSH based PowerShell remoting in Windows Server

Enable SSH based PowerShell remoting in Windows Server

Prepare Ubuntu 16.04 system for SSH-based PowerShell remoting

Open a terminal session on the server and begin by installing OpenSSH client and server:

sudo apt install openssh-client
sudo apt install openssh-server

Next, start an elevated pwsh session, install the RemotingTools module from the PowerShell Gallery, and run the Enable-SSHRemoting command. Again, be sure to start the SSH server daemon after the command finishes.

Install-Module -Name Microsoft.PowerShell.RemotingTools
Enable-SSHRemoting -Verbose
sudo service ssh restart

Test Windows-to-Linux and Linux-to-Windows PowerShell remoting over SSH

What's beautiful about PowerShell 7.x and SSH remoting is that we finally have a single, unified automation language that works between Windows, macOS, and Linux. Thus, creating a PSSession object works regardless of the underlying operating system.

$session = New-PSSession -HostName windowsvm -UserName tim
Enter-PSSession -Session $session

Notice that we use the -HostName parameter for SSH remoting. Recall that we use the -ComputerName parameter for WinRM remoting. The HostName value can be either a Domain Name System (DNS) name or an IP address.

Moreover, you can send PowerShell script blocks to a remote system using Invoke-Command as usual:

Invoke-Command $session -ScriptBlock { Get-Process -Name pwsh }

In the absence of a dedicated PSSession, you can use Invoke-Command on its own by using the -HostName parameter:

Invoke-Command -HostName linuxvm -UserName tim -ScriptBlock { Get-Process -Name pwsh }

I show you an example Windows-to-Linux PowerShell remoting session in the next figure.

Windows to Linux PowerShell remoting over SSH

Windows to Linux PowerShell remoting over SSH

Tradeoffs and takeaways

Although I used password authentication in this tutorial, Michael wrote a great article on public key authentication with SSH-based PowerShell remoting. In their docs, Microsoft mentions that multifactor authentication (MFA) is handled externally to PowerShell. This means you can optionally include Azure MFA services to your PowerShell remoting sessions, but the configuration happens in the context of the MFA service and/or SSH itself. For instance, you could perform Azure AD sign-in to Linux VMs in Azure that include Azure MFA.

In my opinion, SSH transport in PowerShell remoting is still in its "early days." Specifically, as of December 2020, we are faced with the following limitations:

Subscribe to 4sysops newsletter!

  • sudo doesn't work in remote sessions to Linux hosts
  • PS remoting doesn't support PowerShell profile scripts

The sudo limitation is a pretty big problem, in my opinion. That said, I am optimistic that the PowerShell development team will sort it out eventually, given Microsoft's current focus on cross-platform management. After all, we have what could effectively be called a Microsoft Linux distribution, right?

  1. Ferdinando Simonetti 2 years ago

    Hi there.

    I believe (but I can't be sure before I test it) that the sudo problem could be overridden by an appropriate /etc/sudoers configuration on "remote side" *or* a tweaking on /etc/ssh/ssh_config "local side", as explained, for example, here

    This breaks down to two options, basically:

    Defaults !requiretty

    inside /etc/sudoers on remote Linux machine, or

    RequestTTY auto


    RequestTTY force

    inside your own .ssh/config either globally, or for specific destination hosts



  2. bc1 1 year ago

    Hi! Thanks for this post, very useful.

    When I try to connect (Windows 10 -> Linux (synology nas)), using this command:
    $s = New-PSSession -ComputerName myComputer -UserName userName -Port sshPort

    It ask me the password and then I have the following error message:
    OpenError: [] The background process reported an error with the following message: The SSH client session has ended with error message: subsystem request failed on channel 0.

    Any idea why? (I didn’t install anything on my Synology NAS, but activated ssh in the settings and I’m able to ssh using the standard command ‘ssh username@ipaddress -p sshPort’)

    • bc1 1 year ago

      sorry, I’m not using -ComputerName, but -HostName 😉

Leave a reply

Your email address will not be published.


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account