- Use Azure Bastion as a jump host for RDP and SSH - Tue, Apr 18 2023
- Azure Virtual Desktop: Getting started - Fri, Apr 14 2023
- Understanding Azure service accounts - Fri, Mar 31 2023
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~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
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
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 Exit-PSSession
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.
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?
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:
inside /etc/sudoers on remote Linux machine, or
or
inside your own .ssh/config either globally, or for specific destination hosts
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: [192.168.0.10] 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’)
sorry, I’m not using -ComputerName, but -HostName 😉