PowerShell Remoting is one of the most powerful features in PowerShell, enabling administrators to execute commands and scripts on remote computers across a network. Whether you’re managing a handful of servers or thousands of endpoints, PowerShell Remoting provides a secure, efficient way to perform administrative tasks without physically accessing each machine.
What is PowerShell Remoting?
PowerShell Remoting uses the WS-Management protocol and Windows Remote Management (WinRM) service to establish connections between computers. It allows you to run PowerShell commands on one or more remote computers as if you were sitting at their consoles. Unlike traditional remote desktop connections, PowerShell Remoting is lightweight, scriptable, and designed specifically for administrative tasks.
Prerequisites for PowerShell Remoting
Before using PowerShell Remoting, ensure the following requirements are met:
- PowerShell 2.0 or later (PowerShell 5.1 or 7+ recommended)
- Administrator privileges on both local and remote computers
- Network connectivity between computers
- WinRM service configured and running
- Appropriate firewall rules configured
- Both computers in the same domain (or proper authentication configured for workgroup scenarios)
Enable-PSRemoting: Setting Up Remote Access
The Enable-PSRemoting cmdlet configures your computer to receive remote PowerShell commands. This is the first step in enabling PowerShell Remoting on a target machine.
Basic Configuration
Run the following command with administrator privileges on the remote computer:
Enable-PSRemoting -Force
Output:
WinRM has been updated to receive requests.
WinRM service type changed successfully.
WinRM service started.
WinRM has been updated for remote management.
Created a WinRM listener on HTTP://* to accept WS-Man requests to any IP on this machine.
WinRM firewall exception enabled.
The -Force parameter suppresses confirmation prompts, making it ideal for scripted deployments.
What Enable-PSRemoting Does
When you run Enable-PSRemoting, PowerShell performs several critical configuration tasks:
- Starts the WinRM service and sets it to start automatically
- Creates a listener to accept requests on any IP address
- Configures firewall exceptions for WS-Management traffic
- Registers default PowerShell session configurations
- Enables remote management
Advanced Configuration Options
For more control over the remoting configuration, use these parameters:
# Skip network profile check (useful for home networks)
Enable-PSRemoting -SkipNetworkProfileCheck -Force
# Specify a specific listener address
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Service\IPv4Filter -Value "192.168.1.100"
Verifying Remoting Configuration
Check if remoting is properly configured:
Test-WSMan -ComputerName localhost
Output:
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 10.0.19045 SP: 0.0 Stack: 3.0
Invoke-Command: Executing Remote Commands
The Invoke-Command cmdlet is the workhorse of PowerShell Remoting. It allows you to run commands on one or multiple remote computers simultaneously.
Basic Remote Command Execution
# Execute a simple command on a remote computer
Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Service -Name W32Time }
Output:
Status Name DisplayName PSComputerName
------ ---- ----------- --------------
Running W32Time Windows Time Server01
Notice the PSComputerName property, which indicates which computer the result came from.
Running Commands on Multiple Computers
One of the most powerful features of Invoke-Command is parallel execution across multiple machines:
# Execute command on multiple computers
$computers = "Server01", "Server02", "Server03"
Invoke-Command -ComputerName $computers -ScriptBlock {
Get-Process | Where-Object { $_.CPU -gt 10 } | Select-Object -First 5
}
Output:
Handles NPM(K) PM(K) WS(K) CPU(s) PSComputerName
------- ------ ----- ----- ------ --------------
450 25 45678 67890 45.23 Server01
380 20 34567 56789 32.15 Server01
520 30 56789 78901 28.45 Server02
410 22 43210 65432 22.30 Server02
490 28 54321 76543 19.87 Server03
Using Credentials for Remote Execution
When connecting to computers outside your domain or using different credentials:
# Create credential object
$cred = Get-Credential
# Execute with credentials
Invoke-Command -ComputerName Server01 -Credential $cred -ScriptBlock {
Get-EventLog -LogName System -Newest 5
}
Passing Parameters to Remote Scripts
Use the -ArgumentList parameter to pass variables to remote script blocks:
$serviceName = "wuauserv"
$logName = "System"
Invoke-Command -ComputerName Server01 -ScriptBlock {
param($Service, $Log)
$svc = Get-Service -Name $Service
$events = Get-EventLog -LogName $Log -Source "Service Control Manager" -Newest 10
[PSCustomObject]@{
ServiceName = $svc.Name
Status = $svc.Status
RecentEvents = $events.Count
}
} -ArgumentList $serviceName, $logName
Output:
ServiceName Status RecentEvents PSComputerName
----------- ------ ------------ --------------
wuauserv Running 10 Server01
Running Local Scripts Remotely
Execute a script file stored on your local computer on remote machines:
Invoke-Command -ComputerName Server01, Server02 -FilePath "C:\Scripts\DiskCheck.ps1"
Background Jobs with Invoke-Command
For long-running tasks, use the -AsJob parameter to run commands as background jobs:
# Start remote job
$job = Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {
Get-ChildItem C:\ -Recurse | Measure-Object -Property Length -Sum
} -AsJob
# Check job status
Get-Job -Id $job.Id
# Retrieve results when complete
Receive-Job -Id $job.Id -Keep
New-PSSession: Persistent Remote Connections
While Invoke-Command creates temporary connections, New-PSSession establishes persistent sessions that can be reused multiple times. This is more efficient when you need to run multiple commands on the same remote computer.
Creating a Basic Session
# Create a new session
$session = New-PSSession -ComputerName Server01
# View session details
$session
Output:
Id Name ComputerName State Availability
-- ---- ------------ ----- ------------
1 Session1 Server01 Opened Available
Using Sessions with Invoke-Command
Once a session is created, reuse it for multiple commands:
$session = New-PSSession -ComputerName Server01
# First command
Invoke-Command -Session $session -ScriptBlock { $env:COMPUTERNAME }
# Second command - reuses the same session
Invoke-Command -Session $session -ScriptBlock { Get-Date }
# Third command
Invoke-Command -Session $session -ScriptBlock {
Get-Service | Where-Object Status -eq 'Running' | Measure-Object
}
Output:
SERVER01
Wednesday, October 22, 2025 2:36:00 PM
Count : 145
Average :
Sum :
Maximum :
Minimum :
Property :
Creating Multiple Sessions
# Create sessions to multiple computers
$servers = "Server01", "Server02", "Server03"
$sessions = New-PSSession -ComputerName $servers
# Use all sessions at once
Invoke-Command -Session $sessions -ScriptBlock {
[PSCustomObject]@{
Computer = $env:COMPUTERNAME
Uptime = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
FreeMemoryGB = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)
}
}
Session Configuration Options
Customize session behavior with additional parameters:
# Create session with credentials and custom configuration
$cred = Get-Credential
$sessionOption = New-PSSessionOption -IdleTimeout 7200000 -OpenTimeout 30000
$session = New-PSSession -ComputerName Server01 `
-Credential $cred `
-SessionOption $sessionOption `
-Name "MyCustomSession"
Interactive Sessions with Enter-PSSession
For interactive work, enter a remote session directly:
# Create and enter an interactive session
$session = New-PSSession -ComputerName Server01
Enter-PSSession -Session $session
Your prompt will change to indicate you’re in a remote session:
[Server01]: PS C:\Users\Administrator> Get-Location
Path
----
C:\Users\Administrator
[Server01]: PS C:\Users\Administrator> Exit-PSSession
Managing Sessions
PowerShell provides several cmdlets for session management:
# List all sessions
Get-PSSession
# Get specific session
Get-PSSession -ComputerName Server01
# Disconnect session (keeps it running)
Disconnect-PSSession -Session $session
# Reconnect to disconnected session
Connect-PSSession -Session $session
# Remove session when done
Remove-PSSession -Session $session
Session State and Variables
Variables and state persist within a session:
$session = New-PSSession -ComputerName Server01
# Set a variable in the remote session
Invoke-Command -Session $session -ScriptBlock { $myVar = "Hello from Server01" }
# Access the same variable in subsequent commands
Invoke-Command -Session $session -ScriptBlock { $myVar }
# The variable persists across multiple Invoke-Command calls
Invoke-Command -Session $session -ScriptBlock { $myVar += " - Updated" }
Invoke-Command -Session $session -ScriptBlock { $myVar }
Output:
Hello from Server01
Hello from Server01 - Updated
Security Considerations
PowerShell Remoting includes several security features to protect your infrastructure:
Authentication Methods
- Kerberos: Default for domain environments, provides mutual authentication
- NTLM: Used when Kerberos is unavailable
- Basic: Requires HTTPS, username/password authentication
- Certificate: Certificate-based authentication
TrustedHosts Configuration
For workgroup scenarios or non-domain computers, configure TrustedHosts:
# View current TrustedHosts
Get-Item WSMan:\localhost\Client\TrustedHosts
# Add a specific computer
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "Server01" -Force
# Add multiple computers
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "Server01,Server02,192.168.1.100" -Force
# Add all computers (use with caution)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
Using HTTPS for Remoting
Configure HTTPS listeners for encrypted communication:
# Create HTTPS listener (requires certificate)
New-WSManInstance -ResourceURI winrm/config/Listener `
-SelectorSet @{Address="*";Transport="HTTPS"} `
-ValueSet @{CertificateThumbprint="YOUR_CERT_THUMBPRINT"}
# Connect using HTTPS
Invoke-Command -ComputerName Server01 -UseSSL -ScriptBlock { Get-Process }
Just Enough Administration (JEA)
JEA restricts what users can do in remote sessions by creating constrained endpoints:
# Register a constrained session configuration
Register-PSSessionConfiguration -Name "LimitedAdmin" `
-RunAsVirtualAccount `
-SessionType RestrictedRemoteServer
# Connect to the constrained endpoint
$session = New-PSSession -ComputerName Server01 -ConfigurationName "LimitedAdmin"
Troubleshooting Common Issues
WinRM Service Not Running
# Check WinRM service status
Get-Service WinRM
# Start the service if stopped
Start-Service WinRM
Set-Service WinRM -StartupType Automatic
Firewall Blocking Connections
# Check firewall rules
Get-NetFirewallRule -DisplayName "Windows Remote Management*"
# Enable firewall rule
Enable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)"
Testing Remote Connectivity
# Test WinRM connectivity
Test-WSMan -ComputerName Server01
# Test with credentials
Test-WSMan -ComputerName Server01 -Credential (Get-Credential)
# Detailed connection test
Test-NetConnection -ComputerName Server01 -Port 5985
Checking Session Configuration
# List available session configurations
Get-PSSessionConfiguration
# View detailed configuration
Get-PSSessionConfiguration -Name Microsoft.PowerShell | Format-List *
Best Practices for PowerShell Remoting
- Use sessions for multiple commands: Create persistent sessions with
New-PSSessionwhen running multiple commands on the same computer - Clean up sessions: Always remove sessions when done with
Remove-PSSessionto free resources - Limit TrustedHosts: Be specific about which computers are trusted rather than using wildcards
- Use HTTPS in production: Configure SSL/TLS certificates for encrypted communication
- Implement JEA: Use constrained endpoints to follow the principle of least privilege
- Monitor session limits: Be aware of the default limit of 5 concurrent sessions per user
- Use parallel execution wisely:
Invoke-Commanddefaults to 32 concurrent computers; adjust with-ThrottleLimitif needed - Handle errors properly: Use
-ErrorActionand-ErrorVariableto manage errors in remote commands
Real-World Examples
Gathering System Information from Multiple Servers
$servers = "Server01", "Server02", "Server03"
Invoke-Command -ComputerName $servers -ScriptBlock {
$os = Get-CimInstance Win32_OperatingSystem
$disk = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='C:'"
[PSCustomObject]@{
Computer = $env:COMPUTERNAME
OS = $os.Caption
OSVersion = $os.Version
LastBoot = $os.LastBootUpTime
TotalMemoryGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
FreeMemoryGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
CDriveFreeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
CDriveSizeGB = [math]::Round($disk.Size / 1GB, 2)
}
} | Format-Table -AutoSize
Deploying Software to Multiple Computers
$computers = "Server01", "Server02", "Server03"
$installerPath = "\\FileServer\Software\Application.msi"
Invoke-Command -ComputerName $computers -ScriptBlock {
param($Path)
$result = Start-Process msiexec.exe -ArgumentList "/i `"$Path`" /qn" -Wait -PassThru
[PSCustomObject]@{
Computer = $env:COMPUTERNAME
ExitCode = $result.ExitCode
Success = ($result.ExitCode -eq 0)
}
} -ArgumentList $installerPath
Bulk Service Management
$servers = "Server01", "Server02", "Server03"
$serviceName = "Spooler"
# Check service status
$status = Invoke-Command -ComputerName $servers -ScriptBlock {
param($Name)
Get-Service -Name $Name | Select-Object Name, Status, StartType
} -ArgumentList $serviceName
$status | Format-Table -AutoSize
# Restart service on all servers
Invoke-Command -ComputerName $servers -ScriptBlock {
param($Name)
Restart-Service -Name $Name -Force
} -ArgumentList $serviceName
Centralized Log Collection
$servers = "Server01", "Server02", "Server03"
$logs = Invoke-Command -ComputerName $servers -ScriptBlock {
Get-EventLog -LogName System -EntryType Error -Newest 10 |
Select-Object TimeGenerated, Source, EventID, Message
}
$logs | Sort-Object TimeGenerated -Descending |
Select-Object PSComputerName, TimeGenerated, Source, EventID |
Format-Table -AutoSize
Performance Optimization
Controlling Parallel Execution
# Default throttle limit is 32
Invoke-Command -ComputerName $largeServerList -ScriptBlock { Get-Process } -ThrottleLimit 50
# For better control with large datasets
$sessions = New-PSSession -ComputerName $largeServerList -ThrottleLimit 100
Invoke-Command -Session $sessions -ScriptBlock { Get-Process }
Remove-PSSession -Session $sessions
Minimizing Data Transfer
# Filter on remote computer before returning data
Invoke-Command -ComputerName Server01 -ScriptBlock {
Get-Process | Where-Object { $_.WorkingSet -gt 100MB } |
Select-Object Name, Id, @{N='WorkingSetMB';E={[math]::Round($_.WorkingSet/1MB,2)}}
}
Conclusion
PowerShell Remoting is an essential tool for modern Windows administration, enabling efficient management of distributed systems. By mastering Enable-PSRemoting, Invoke-Command, and New-PSSession, you can automate tasks across entire infrastructures, reduce administrative overhead, and improve consistency in your environment.
Whether you’re managing a small network of servers or a large enterprise environment, PowerShell Remoting provides the flexibility and power needed to scale your administrative efforts effectively. Start with basic remote command execution, progress to persistent sessions for complex workflows, and implement security best practices to ensure your remote management infrastructure remains secure and efficient.








