What PowerShell Remoting Is
PowerShell remoting is a mechanism that sends PowerShell commands and scripts from your machine to one or more remote machines, executes them there, and returns results to you.
There are two main transports you will see today:
- Uses Windows Remote Management (WinRM), HTTP/HTTPS on ports 5985/5986.
- Built into Windows PowerShell 2.0+ and supported in PowerShell 7+ on Windows.
- Uses OpenSSH (TCP port 22 by default).
- Cross-platform: Windows, Linux, macOS.
- Supported natively in PowerShell 7+.
Both approaches allow:
- 1 to 1 interactive sessions.
- 1 to many fanout (run once, execute on many machines).
- Session reuse for multiple commands, which is important for performance.
- Port 22 sails through firewalls (unlike WinRM's 5985/5986)
- Perfect for jump boxes and Azure Arc SQL
- No GPO fights over WinRM config
- PowerShell 7+ brings faster module loading and true parallel `Invoke-Command`, but VS Code's learning curve can feel steep coming from SSMS's polished GUI.
Requirements and Versions
- Installed by default on Windows Server and Windows 10.
- Uses WinRM remoting by default.
- Cross-platform and installed separately.
- Supports both WinRM and SSH remoting.
- Has its own remoting endpoints and configuration, independent from Windows PowerShell.
- WinRM must be enabled and configured on the remote computer.
- The firewall must allow WinRM (HTTP/HTTPS) traffic.
- Authentication must be possible (domain trust, certificates, or explicit credentials).
- Name resolution must work (DNS/hosts), or you must use IP plus TrustedHosts.
Enabling WinRM Remoting on Servers (Windows Server)
On Windows Server versions, WinRM is usually installed and often already configured, especially in domain environments. To explicitly configure:
# Run in an elevated PowerShell session on the server
Enable-PSRemoting -Force
What this does:
- Starts and configures the WinRM service.
- Creates the default PowerShell endpoint.
- Configures HTTP listener (port 5985).
- Creates firewall rules for WinRM.
If your organization enforces WinRM policies via Group Policy, those settings may override this configuration. In that case, work with your AD/GPO administrators.
Enabling WinRM Remoting on Clients (Windows 10/11)
On Windows 10/11, WinRM is present but often disabled by default:
# Run as Administrator
Enable-PSRemoting -Force
If this fails or is restricted, you can also check with:
winrm quickconfig
This tool can help configure the WinRM service level, but PowerShell remoting endpoints still require PowerShell configuration.
Quick Test: Ping a Remote Endpoint
Before running real commands, verify that remoting is working on the remote computer:
Test-WsMan -ComputerName SERVER1Basic WinRM Remoting Examples
Example 1: Run a Simple Command
Invoke-Command -ComputerName SERVER1 -ScriptBlock {
Get-Service -Name WinRM
}
-ComputerName can accept a single name or an array of names. -ScriptBlock contains the code that runs on the remote machine.
Example 2: Run on Multiple Servers
$servers = 'SERVER1', 'SERVER2', 'SERVER3'
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-Service -Name Spooler
}
This is one of the biggest wins of remoting: a single command targeting many servers.
Example 3: Use Explicit Credentials
$cred = Get-Credential
Invoke-Command -ComputerName SERVER1 -Credential $cred -ScriptBlock {
Get-Process
}
This prompts for a username and password, which PowerShell uses to authenticate to the remote system.
Using Persistent Sessions
Creating and reusing a PowerShell session (PSSession) is more efficient than setting up a new connection for every command. It is also necessary for some workflows, like copying files or maintaining state.
Example 4: Create and Use a PSSession
$session = New-PSSession -ComputerName SERVER1
Invoke-Command -Session $session -ScriptBlock {
Get-ChildItem C:\Temp
}
# Run another command in the same session
Invoke-Command -Session $session -ScriptBlock {
Get-Date
}
# Always clean up when done
Remove-PSSession $session
A PSSession keeps the remote environment alive across multiple commands.
Example 5: Copy a File to a Remote Server
$session = New-PSSession -ComputerName SERVER1
Copy-Item -Path "C:\Scripts\Deploy.ps1" `
-Destination "C:\Admin\Deploy.ps1" `
-ToSession $session
Remove-PSSession $session
This uses the WinRM channel to transfer the file rather than SMB, which can be useful in locked-down environments.
Example 6: Enter an Interactive Remote Session
Enter-PSSession -ComputerName SERVER1
# Prompt changes to something like:
# [SERVER1]: PS C:\Users\Admin>
# Run commands directly on SERVER1
Get-Process
Get-Service
# Exit the remote session
Exit-PSSession
This is a powerful replacement for RDP in many administrative scenarios.
Example 7: Check Database Backup Status Across SQL Servers
# Shows last full backup date for every database on every SQL Server. $servers = @("SQL01\Instance01", "SQL02\Instance02", "SQL03\Instance03") foreach($server in $servers) { $status = Invoke-Sqlcmd -ServerInstance $server -Database "msdb" -Query @" SELECT database_name AS DatabaseName, MAX(backup_finish_date) AS LastFullBackup FROM msdb.dbo.backupset WHERE type = 'D' GROUP BY database_name "@ $status | Select-Object @{Name="SQLServer";Expression={$server}}, DatabaseName, @{Name="LastFullBackup";Expression={$_.LastFullBackup -f "yyyy-MM-dd HH:mm"}} }
Example 8: Restart Stuck SQL Agent Jobs Remotely
#Finds failed Agent jobs from today, restarts them automatically. $SQLServerInstance = "SQL01\Instance01" $failedJobs = Invoke-Sqlcmd -ServerInstance $SQLServerInstance -Database "msdb" -Query @" SELECT j.name AS JobName FROM msdb.dbo.sysjobs AS j INNER JOIN msdb.dbo.sysjobhistory AS h ON j.job_id = h.job_id WHERE h.run_status = 0 AND h.step_id = 0 AND h.instance_id = (SELECT MAX(instance_id) FROM msdb.dbo.sysjobhistory WHERE job_id = h.job_id) AND h.run_date >= CONVERT(INT, CONVERT(VARCHAR(8), GETDATE() - 1, 112)); "@ foreach($job in $failedJobs) { Write-Output "Starting Job: $($job.JobName)" Invoke-Sqlcmd -ServerInstance $SQLServerInstance -Database "msdb" -Query @" EXEC msdb.dbo.sp_start_job @job_name = '$($job.JobName)' "@ Write-Output "Started Job: $($job.JobName)" }
Common Issues and Troubleshooting
1. Access Denied
Symptoms:
Access is denied.The client cannot connect to the destination specified in the request.
Checks:
- Are you running the console as Administrator?
- Does the account have permissions to connect via WinRM on the remote machine?
- Are there group policies restricting WinRM or PowerShell endpoints?
2. Network or Name Resolution Problems
Symptoms:
WinRM cannot complete the operation.The client cannot connect to the destination specified in the request.
Checks:
- Test basic reachability:
Test-Connection SERVER1 Test-WsMan SERVER1 - Check DNS: does the hostname resolve correctly?
- Inspect firewall rules on both client and server.
3. TrustedHosts and Workgroup Machines
On nondomain machines, or when using IP addresses, you may need to configure TrustedHosts:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "SERVER1,SERVER2" -Force
Use wildcards or ranges only when you understand the security implications.
4. Double-Hop Problem
If a remote session needs to access another network resource (for example, SQL Server or a file share from within the remote script), Kerberos may not delegate credentials by default. Solutions include:
- Using CredSSP (with caution).
- Using Kerberos constrained delegation.
- Using alternate credentials explicitly within the script for downstream access.
- Running the script from a system that has direct access instead of hopping.
Security Considerations
Security is critical when enabling remoting.
Key points:
- Prefer HTTPS for WinRM (port 5986) in untrusted or internetfacing scenarios.
- Use Kerberos authentication within a domain whenever possible; it provides mutual authentication and strong security.
- Limit who can use remoting:
- Use groups instead of individual user accounts.
- Use constrained endpoints or Just Enough Administration (JEA) so users only have the rights they need.
- Be careful with CredSSP: it can solve doublehop issues but introduces credentialdelegation risk. Use it only when necessary and within tightly controlled environments.
If you must use HTTP (5985), keep traffic on internal trusted networks and consider IPsec or VPN protections.
PowerShell Remoting Over SSH
While WinRM is excellent for Windows domain environments, SSH-based remoting is often easier across platforms and through firewalls.
Requirements
- PowerShell 7 or later on both client and server.
- OpenSSH server configured on the remote host.
- PowerShell 7 set as a subsystem or command in SSH configuration.
On Windows, install OpenSSH server and enable it, then configure sshd_config to allow a PowerShell endpoint, for example:
# In sshd_config (simplified example)
Subsystem powershell C:/Program Files/PowerShell/7/pwsh.exe -sshs -NoLogo -NoProfile
On Linux/Unix/macOS, the file is located /etc/ssh/sshd_config.
Restart the SSH service after changes:
sudo systemctl sudo systemctl restart sshdRestart-Service sshdExample 9: SSH Remoting with PowerShell 7
$cred = Get-Credential # user on the SSH server
$session = New-PSSession `
-HostName "linux01.contoso.com" `
-UserName $cred.UserName `
-SSHTransport
Invoke-Command -Session $session -ScriptBlock {
$PSVersionTable
}
Remove-PSSession $session
On Windows-to-Windows over SSH, the pattern is the same—just change the host.
SSH remoting allows you to use the same PowerShell syntax to manage Linux and Windows, which is especially attractive for hybrid SQL/Oracle shops.
Best Practices for Modern Environments
- Standardize on PowerShell 7+ for new automation where possible, especially in mixed OS environments.
- Use HTTPS WinRM listeners and/or SSH for secure remote management.
- Use PSSessions and run multiple commands per session instead of single-use remoting calls.
- Incorporate logging and auditing via transcript (
Start-Transcript) and central logging solutions. - Start small: test remoting on a lab machine, then roll out to production via GPO or configuration management.