PowerShell Remoting: Run Commands on Remote Computers

Running one script across 100 servers simultaneously is the ops dream — and PowerShell remoting Invoke-Command makes it real. Instead of opening RDP sessions one by one, you send a script block over WinRM and get structured objects back. Whether you need to collect disk space from every server, deploy a configuration change fleet-wide, or query event logs remotely, Invoke-Command handles it all with proper parallelism and session management built in.
Enable PowerShell Remoting
Remoting is disabled by default on workstations. Run this once on each target machine — or push it via GPO or a management tool. The command must run as administrator.
# On the REMOTE target machine — run as admin
Enable-PSRemoting -Force
This configures WinRM, sets the service to automatic, and creates the appropriate firewall rules. On domain-joined machines, remoting between machines in the same domain usually works immediately after this step.
Run a Single Command Remotely
Pass a script block to -ScriptBlock and specify the target with -ComputerName. The command runs on the remote machine and the result comes back as a deserialized object.
# Run a command on one remote computer
Invoke-Command -ComputerName "server01" -ScriptBlock {
Get-Service -Name "wuauserv" | Select-Object Name, Status
}
Name Status
---- ------
wuauserv Running
# With explicit credentials
$cred = Get-Credential
Invoke-Command -ComputerName "server01" -Credential $cred -ScriptBlock {
hostname
}
Run a Script Block on Multiple Computers
Pass an array of computer names to -ComputerName and Invoke-Command fans out the execution automatically — by default up to 32 concurrent connections. Results include a PSComputerName property so you know which server each object came from.
$servers = @("server01", "server02", "server03", "server04")
$diskReport = Invoke-Command -ComputerName $servers -ScriptBlock {
Get-PSDrive -Name C | Select-Object Name,
@{N="FreeGB"; E={[math]::Round($_.Free / 1GB, 1)}},
@{N="UsedGB"; E={[math]::Round($_.Used / 1GB, 1)}}
}
$diskReport | Sort-Object PSComputerName | Format-Table PSComputerName, FreeGB, UsedGB
Persistent Sessions with New-PSSession
For repeated operations on the same servers, create persistent sessions with New-PSSession. Sessions avoid the overhead of re-authenticating on every call and allow you to import remote modules into your local session.
# Create sessions once
$sessions = New-PSSession -ComputerName "server01", "server02"
# Run multiple commands against the same sessions
Invoke-Command -Session $sessions -ScriptBlock { Get-Date }
Invoke-Command -Session $sessions -ScriptBlock { Get-Process | Measure-Object | Select-Object -Expand Count }
# Always clean up sessions when done
Remove-PSSession -Session $sessions
Passing Local Variables to Remote Session
Variables defined locally are not automatically available inside the remote script block. Use the $Using: scope modifier (PowerShell 3.0+) to inject local variable values into the remote execution context.
$serviceName = "Spooler"
$servers = @("server01", "server02")
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-Service -Name $Using:serviceName | Select-Object Name, Status, StartType
}
Without $Using:, $serviceName would be undefined inside the remote block and the command would fail silently or throw an error.
Remoting Without Domain (Workgroup)
Remoting across workgroup (non-domain) machines requires extra configuration because there’s no Kerberos authentication. You need to add the remote machine to the TrustedHosts list and authenticate with explicit credentials.
# On the SOURCE machine — run as admin
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.50" -Force
# Then connect with credentials
$cred = Get-Credential
Invoke-Command -ComputerName "192.168.1.50" -Credential $cred -ScriptBlock {
"Connected as: $env:USERNAME on $env:COMPUTERNAME"
}
Set TrustedHosts to * only in isolated lab environments — in production, list specific IPs or hostnames.
Common Errors and Fixes
- WinRM not enabled on target: The most common error is “WinRM cannot complete the operation” or “Connection refused”. The fix is to run
Enable-PSRemoting -Forceon the target machine as administrator. If you can’t access the target interactively, push the configuration via GPO using the “Allow remote server management through WinRM” policy setting. - Double-hop authentication problem: When your remote script tries to access a third resource (network share, another server), credentials don’t automatically pass through — this is the classic Kerberos double-hop problem. Solutions include using CredSSP (configure with
Enable-WSManCredSSPon both sides), using a-RunAsaccount, or using$Using:to pass explicit credentials into the second hop.
Related Cmdlets / See Also
- PowerShell Enter-PSSession: Interactive Remote Shell
- PowerShell SSH: Connect to Linux Servers from Windows
Wrapping Up
Invoke-Command with an array of computer names is one of the highest-leverage commands in PowerShell — what takes an hour manually completes in seconds across your entire fleet. As a next step, combine it with Get-ADComputer to dynamically build the target list from Active Directory rather than hardcoding server names.


