PowerShell Remoting: Run Commands on Remote Computers

PowerShell Remoting: Run Commands on Remote Computers

PowerShell Tips Editor 4 min read
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 -Force on 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-WSManCredSSP on both sides), using a -RunAs account, or using $Using: to pass explicit credentials into the second hop.

Related Cmdlets / See Also

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.

Send-Item -To