PowerShell Remoting Over SSH Without WinRM Configuration

WinRM is blocked or unavailable in a growing number of environments — zero-trust architectures restrict WS-Man ports, Linux targets never supported it, and many security teams simply refuse to open port 5985. PowerShell 7 introduced SSH-based remoting as a fully supported alternative. It reuses the OpenSSH infrastructure that is already present on Windows 10/Server 2019 and all modern Linux distributions, requires no new firewall rules beyond port 22, and supports key-based authentication that fits neatly into existing PKI workflows.
Quick Answer
Install OpenSSH Server on the target, add a Subsystem powershell entry to sshd_config pointing at the PowerShell 7 executable, then connect with New-PSSession -HostName <target> -UserName <user> from PowerShell 7 on the management host.
Installing and Configuring OpenSSH Server on Windows
Windows 10 1809+ and Windows Server 2019+ include OpenSSH as an optional feature. Install and start the service with two commands, then verify it is listening before editing any configuration.
# Install the OpenSSH Server optional feature (requires elevation)
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# Start the service and set it to start automatically
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
# Verify the service is running and port 22 is listening
Get-Service sshd
Test-NetConnection -ComputerName localhost -Port 22
If Test-NetConnection returns TcpTestSucceeded : True, the OpenSSH server is ready for the next step.
Adding the PowerShell SSH Subsystem to sshd_config
The SSH subsystem line tells sshd which executable to invoke when a client requests the powershell subsystem. The path must point to the PowerShell 7 binary — not Windows PowerShell 5.1. Edit C:\ProgramData\ssh\sshd_config and add the subsystem entry, then restart the service.
# Add the subsystem line to sshd_config
$sshdConfig = "C:\ProgramData\ssh\sshd_config"
$subsystemLine = "Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -nologo"
# Check it is not already present before appending
if (-not (Select-String -Path $sshdConfig -Pattern "Subsystem powershell" -Quiet)) {
Add-Content -Path $sshdConfig -Value $subsystemLine
}
Restart-Service sshd
Using the 8.3 short path (progra~1) avoids the space in Program Files which can confuse the sshd_config parser. Alternatively, enclose the full path in double quotes.
Connecting with New-PSSession -HostName and -UserName
Once the subsystem is configured, connecting from any PowerShell 7 client uses the same New-PSSession and Enter-PSSession commands you already know — just swap -ComputerName for -HostName.
# Interactive session
Enter-PSSession -HostName srv-linux01.corp.local -UserName adminuser
# Non-interactive session for scripting
$session = New-PSSession -HostName srv-win02 -UserName adminuser
Invoke-Command -Session $session -ScriptBlock {
$PSVersionTable.PSVersion
Get-Service -Name W32Time | Select-Object Name, Status
}
Remove-PSSession -Session $session
The first connection will prompt to accept the host key fingerprint, identical to a standard SSH workflow.
Key-Based Authentication Setup and Agent Forwarding
Password prompts in automation scripts are a reliability problem. Set up SSH key authentication by generating an ed25519 key pair, copying the public key to the target’s authorized_keys file, and optionally adding the private key to ssh-agent for agent forwarding.
# Generate a key pair (no passphrase for automation; use passphrase for interactive admin)
ssh-keygen -t ed25519 -f "$env:USERPROFILE\.ssh\id_ed25519_ps7" -C "ps7-automation"
# Copy the public key to a Windows target (PowerShell equivalent of ssh-copy-id)
$pubKey = Get-Content "$env:USERPROFILE\.ssh\id_ed25519_ps7.pub"
Invoke-Command -HostName srv-win02 -UserName adminuser -ScriptBlock {
param($key)
$authPath = "$env:USERPROFILE\.ssh\authorized_keys"
if (-not (Test-Path (Split-Path $authPath))) {
New-Item -ItemType Directory -Path (Split-Path $authPath) | Out-Null
}
Add-Content -Path $authPath -Value $key
} -ArgumentList $pubKey
# Connect without a password prompt
New-PSSession -HostName srv-win02 -UserName adminuser `
-KeyFilePath "$env:USERPROFILE\.ssh\id_ed25519_ps7"
SSH Remoting to Linux Targets from Windows
Linux targets need PowerShell 7 installed and the same Subsystem powershell line added to /etc/ssh/sshd_config, then sudo systemctl restart sshd. The connection syntax from the Windows management host is identical — -HostName accepts any hostname or IP that resolves from the client.
Performance Comparison: WinRM vs SSH Remoting
SSH remoting has slightly higher latency than WinRM for small payloads due to the cryptographic handshake overhead, but for typical sysadmin tasks the difference is imperceptible. For bulk data transfer (Copy-Item over a session) SSH is competitive. The operational advantage — no WS-Man configuration, no trusted host lists, no HTTP/HTTPS port exceptions — outweighs the minor latency difference in most environments.
Common Errors
- sshd fails to start after subsystem config change: An indentation error, a tab character instead of spaces, or a missing executable path in
sshd_configwill silently prevent sshd from loading the config and cause the service to fail. Check the Windows Event Log under Application and Services Logs > OpenSSH > Operational for the exact parse error. - New-PSSession hangs when port 22 is blocked: The Windows Firewall may not automatically open port 22 during OpenSSH Server installation. Run
Get-NetFirewallRule -Name *OpenSSH*and ensure the inbound rule is Enabled. If the rule is missing, add it withNew-NetFirewallRule -Name sshd -DisplayName "OpenSSH Server" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22.
Related Cmdlets / See Also
Wrapping Up
SSH-based remoting in PowerShell 7 removes the WinRM dependency without changing the cmdlets you already know. A one-time subsystem entry in sshd_config is all the server-side configuration required. Once configured, key-based auth makes it fully suitable for unattended automation across both Windows and Linux targets.


