PowerShell Remoting has been around since the early days of the PowerShell language and allows for running commands and receiving output between remote systems. Traditionally, PowerShell Remoting has been built on WinRM, but with newer PowerShell versions, the SSH protocol is now available to facilitate remoting between Linux systems as well. In this article, you’ll learn how to get started with PowerShell remoting, concentrating on PowerShell versions 5.1 and greater.
In this article we concentrate on Windows Server 2016 as prior versions have been deemed end-of-life by Microsoft.
Take note that by default, Windows PowerShell will create a microsoft.powershell session endpoint. Enter-PSSession and New-PSSession will use this endpoint when no other session endpoint is specified. Since newer versions of PowerShell do not create or override this endpoint, the endpoint name must be specified to connect to the right remote instance, if not connecting to Windows PowerShell. An example of the default Windows PowerShell configuration is below (Figure 1).
After running Enable-PSRemoting, the correct version-specific endpoints are registered, in this case 6.2.5 (figure 3).
The reason that the -SkipNetworkProfileCheck parameter is specified is that any Public network will end the Enable-PSRemoting command early. As long as you are aware of the ramifications and proper control of this, then it is safe to run this command.
The endpoint names that are then registered to allow for remoting are specific to the latest PowerShell version, in this case 7.0.1. (see figure 5).
Run the following commands to install the required capabilities (OpenSSH.Client may already be installed), service configuration, and firewall rules.
# Install the OpenSSH Client and Server Add-WindowsCapability -Online -Name 'OpenSSH.Client~~~~0.0.1.0' Add-WindowsCapability -Online -Name 'OpenSSH.Server~~~~0.0.1.0' # Initial Configuration of SSH Server Start-Service -Name 'sshd' Set-Service -Name 'sshd' -StartupType 'Automatic' # Confirm the Firewall rule is configured. It should be created automatically by setup. Get-NetFirewallRule -Name '*ssh*' | Format-Table -AutoSize # There should be a firewall rule named "OpenSSH-Server-In-TCP", which should be enabled New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
Finally, to enable the SSH server to work with PowerShell remoting, the subsystem must be correctly set.
notepad $Env:ProgramData\ssh\sshd_config
# Make sure that the subsystem line goes after the existing SFTP subsystem line Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -NoLogo -NoProfile # Change c:/progra~1/powershell/7/pwsh.exe to c:/progra~1/powershell/6/pwsh.exe for PowerShell Core PasswordAuthentication yes # Below is optional but recommended to allow use of public/private keys PubkeyAuthentication yes
Finally, restart the SSH server:
Restart-Service -Name 'sshd'
There is a bug in the OpenSSH server version included with Windows. It requires that 8.3 short names be used for any file paths, hence c:/progra~1. To verify that you are using the correct 8.3 short name, you can use the following command to retrieve this for Program Files (where PowerShell 6 or 7 is installed):
Get-CimInstance Win32_Directory -Filter 'Name="C:\\Program Files"' | Select-Object EightDotThreeFileName
$Params = @{ "ComputerName" = 'Host1' "ConfigurationName" = 'PowerShell.7' "ScriptBlock" = { Get-Service | Where-Object Status -EQ 'Running' | Format-Table -AutoSize } } Invoke-Command @Params
$Params = @{ "ComputerName" = 'Host1' "ConfigurationName" = 'PowerShell.7' "ScriptBlock" = { Get-Service -Name 'Spooler' | Restart-Service } } Invoke-Command @Params