Remoting and PSSessions

Reviewed & published by Brayan K

By the end of this lesson you'll run commands on remote machines with Invoke-Command, drop into an interactive remote prompt with Enter-PSSession, reuse persistent connections via New-PSSession, fan a command out across many servers at once, and pass local data into remote blocks with $using: — the foundation of real infrastructure automation.

Part of the free PowerShell course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

Remoting is like having remote control of other computers. Enter-PSSession is a video call — you're "in the room" on one machine, typing live. Invoke-Command is sending a task by courier — you hand over a sealed instruction (the script block), it's carried out on the far end, and the results are couriered back to you. New-PSSession is keeping the phone line open so you don't redial for every message, and $using: is writing your local notes into the instruction so the remote worker has the details they need.

1. Running Commands Remotely with Invoke-Command

Invoke-Command is the workhorse of remoting. You give it -ComputerName (where to run) and a -ScriptBlock (what to run); the block executes on the remote machine and the results come back to you as objects, each tagged with a PSComputerName property. Read this worked example, then run it against a host you control.

# PowerShell Remoting runs commands on OTHER machines from your session.

# Invoke-Command runs a script block remotely and brings the RESULTS back
# as objects. -ComputerName says where; -ScriptBlock says what.
Invoke-Command -ComputerName 'Server01' -ScriptBlock {
    # This code runs ON Server01, not locally:
    Get-Process | Sort-Object WS -Descending | Select-Object -First 2 Name, Id
}

# The output gains a PSComputerName property so you know which host it came from.

2. Interactive Sessions with Enter-PSSession

When you want to "go there and look around" one machine, Enter-PSSession drops you into an interactive remote prompt. Your prompt changes to show the remote host, every command you type runs there, and Exit-PSSession brings you home. Supply credentials with -Credential (Get-Credential). This is ideal for single-machine troubleshooting; for automation across many hosts, reach for Invoke-Command instead.

# Enter-PSSession gives you an INTERACTIVE prompt ON the remote machine.
# Everything you type now runs there until you Exit-PSSession.

Enter-PSSession -ComputerName 'Server01' -Credential (Get-Credential)

# Notice the prompt changes to show the remote host:
# [Server01]: PS C:\> hostname
# Server01
# [Server01]: PS C:\> Exit-PSSession      # back to your local prompt

# Enter-PSSession is great for ad-hoc, one-machine troubleshooting.
# For automation across MANY machines, use Invoke-Command instead.

Now you try. Fill in the one blank using the hint in the comment, then run it.

# 🎯 YOUR TURN — replace each ___ then run it.
# Goal: get the OS version from a remote machine called 'Web01'.

___ -ComputerName 'Web01' -ScriptBlock {   # 👉 the cmdlet is: Invoke-Command
    # This runs on Web01:
    [System.Environment]::OSVersion.Version
}

# ✅ Expected (example):
# Major  Minor  Build  PSComputerName
# -----  -----  -----  --------------
# 10     0      19045  Web01

3. Persistent Connections with New-PSSession

Passing -ComputerName opens a throwaway connection per call. For repeated work, create a persistent session with New-PSSession and pass it to Invoke-Command -Session. Reuse is faster and keeps state between calls — a variable set in one call is still there in the next. Always Remove-PSSession when you finish to free resources on both ends.

# A PSSession is a PERSISTENT connection you can reuse for many commands.
# Create once, run several Invoke-Commands, then clean up.

# 1) Open reusable sessions to two servers:
$sessions = New-PSSession -ComputerName 'Web01', 'Web02' -Credential (Get-Credential)

# 2) Reuse them — state persists between calls on the same session:
Invoke-Command -Session $sessions -ScriptBlock { $svc = (Get-Service).Count }
Invoke-Command -Session $sessions -ScriptBlock { "$env:COMPUTERNAME has $svc services" }

# 3) ALWAYS clean up when finished:
Remove-PSSession -Session $sessions

Pro Tip

On Windows, remoting rides on WinRM (enable it once with Enable-PSRemoting). In PowerShell 7 you can also remote over SSH with -HostName instead of -ComputerName, which works cross-platform to Linux and macOS. Pick WinRM inside a Windows domain; pick SSH when you need to cross operating systems.

Putting It Together: fan-out + $using:

The two features that make remoting scale: give -ComputerName a list and the block runs on every machine in parallel; and use the $using: scope modifier to push a local variable into the remote block (a remote session can't see your local variables otherwise).

# Two power features: running on MANY machines, and passing LOCAL data in.

$targets   = 'Web01', 'Web02', 'Web03'
$logFolder = 'C:\Logs'           # a LOCAL variable

# Invoke-Command fans out to all three machines IN PARALLEL.
# To use the local $logFolder inside the remote block, prefix it $using:
Invoke-Command -ComputerName $targets -ScriptBlock {
    $files = Get-ChildItem $using:logFolder -ErrorAction SilentlyContinue
    [pscustomobject]@{
        Host  = $env:COMPUTERNAME
        Logs  = $files.Count
    }
}

Each returned object carries PSComputerName, so even though all three ran at once you always know which host produced which row.

Common Errors (and the fix)

📋 Quick Reference — Remoting

CmdletPurposeExample
Invoke-CommandRun a block remotelyInvoke-Command -ComputerName S1 -ScriptBlock {...}
Enter-PSSessionInteractive remote promptEnter-PSSession -ComputerName S1
New-PSSessionPersistent connection$s = New-PSSession -ComputerName S1
Remove-PSSessionClose a sessionRemove-PSSession $s
-CredentialAuthenticate-Credential (Get-Credential)
$using:Pass a local variable in$using:path

Mini-Challenge: multi-server uptime report

No blanks this time — just a brief and an outline to keep you on track. Build it, run it (against lab hosts), and check your output against the example in the comments. Fanning a check out across servers is everyday infrastructure work.

# 🎯 MINI-CHALLENGE: a multi-server uptime report
# No code is filled in — just an outline. Build it and check the output.
#
# 1. Put three computer names in a $servers array.
# 2. Define a LOCAL variable $threshold = 7  (days).
# 3. Use Invoke-Command -ComputerName $servers -ScriptBlock { ... } to,
#    on EACH server:
#       - compute uptime from (Get-Date) minus the last boot time
#         ( (Get-CimInstance Win32_OperatingSystem).LastBootUpTime )
#       - compare uptime in days against $using:threshold
#       - output a [pscustomobject] with Host, UptimeDays, NeedsReboot.
# 4. Sort the combined results by UptimeDays descending.
#
# ✅ Example output:
#    Host   UptimeDays NeedsReboot  PSComputerName
#    ----   ---------- -----------  --------------
#    Web03          31 True         Web03
#    Web01           4 False        Web01

# your code here

🎉 Lesson Complete

Practice quiz

What does PowerShell Remoting let you do?

  • Run commands on remote computers
  • Compress archives
  • Format strings
  • Edit local files faster

Answer: Run commands on remote computers. Remoting runs PowerShell commands and scripts on one or many remote machines from your local session.

Which cmdlet runs a script block on a remote computer?

  • Get-Process
  • Enter-Session
  • Invoke-Command
  • Start-Process

Answer: Invoke-Command. Invoke-Command -ComputerName <name> -ScriptBlock { ... } runs the block remotely and returns the results.

Which cmdlet opens an interactive one-to-one remote session?

  • Invoke-Command
  • Enter-PSSession
  • Connect-Host
  • New-PSSession

Answer: Enter-PSSession. Enter-PSSession starts an interactive session so your prompt operates on the remote machine until you Exit-PSSession.

What does New-PSSession create?

  • A new local window
  • A scheduled task
  • A log file
  • A persistent reusable connection to a remote host

Answer: A persistent reusable connection to a remote host. New-PSSession creates a persistent PSSession you can reuse across multiple Invoke-Command calls.

Which cmdlet closes and cleans up a PSSession?

  • Remove-PSSession
  • Stop-Session
  • Close-PSSession
  • Exit-Session

Answer: Remove-PSSession. Remove-PSSession disconnects and removes a session, freeing resources on both ends.

On Windows, which protocol is the traditional remoting transport?

  • FTP
  • WinRM
  • SMTP
  • Telnet

Answer: WinRM. WinRM (Windows Remote Management) is the default transport for PowerShell remoting on Windows.

Which transport enables cross-platform PowerShell remoting?

  • HTTP only
  • RDP
  • SMB
  • SSH

Answer: SSH. PowerShell 7 supports SSH-based remoting, letting you connect across Windows, Linux, and macOS.

How do you supply alternate credentials to a remote command?

  • -Login
  • -User
  • -Credential
  • -Password

Answer: -Credential. The -Credential parameter accepts a PSCredential so you can authenticate as a different user.

What does Invoke-Command do when given many computer names?

  • Errors out
  • Runs the command on all of them in parallel
  • Runs them one at a time slowly
  • Picks one at random

Answer: Runs the command on all of them in parallel. Invoke-Command fans out and runs the script block on all listed computers concurrently.

Inside a remote script block, how do you use a LOCAL variable?

  • Prefix it with $using:
  • Use $remote:
  • It is impossible
  • Just type $var

Answer: Prefix it with $using:. The $using: scope modifier passes a local variable into the remote script block, e.g. $using:path.

Continue this course

Frequently asked questions

What is the difference between Invoke-Command and Enter-PSSession?

Enter-PSSession is INTERACTIVE: it drops you into a live prompt on one remote machine, so every command you type runs there until you Exit-PSSession. It's perfect for ad-hoc troubleshooting on a single host. Invoke-Command is for AUTOMATION: it runs a script block (or script file) on one or many machines, returns the results as objects, and finishes. Use Enter-PSSession to 'go there and look around'; use Invoke-Command to 'run this everywhere and bring back the answers'.

When should I use New-PSSession instead of just -ComputerName?

Passing -ComputerName to Invoke-Command opens a fresh, temporary connection for that single call and tears it down afterward. New-PSSession creates a PERSISTENT PSSession you can reuse across many Invoke-Command calls. Reuse matters for two reasons: it's faster (no repeated connection setup), and STATE persists between calls on the same session, so a variable you set in one Invoke-Command is still there in the next. Always Remove-PSSession when you're done to free resources.

What is the difference between WinRM and SSH remoting?

WinRM (Windows Remote Management) is the traditional Windows transport for PowerShell remoting; it's enabled with Enable-PSRemoting and uses the WS-Management protocol. SSH-based remoting, added in PowerShell 7, lets you remote across platforms — Windows to Linux, Linux to Windows, macOS — using the same SSH you'd use for a normal shell, specified with -HostName and -SSHTransport (or -UserName). Choose WinRM inside a Windows/Active Directory environment; choose SSH for cross-platform or where SSH is already the standard.

Why do I need the $using: scope modifier?

A remote script block runs in a separate session on the remote machine, so it can't see your LOCAL variables by default. The $using: modifier captures a local variable's value and ships it into the remote block: $using:path becomes the local $path's value on the remote side. Without it, $path inside the block would be empty (or the remote machine's own $path). Use $using: whenever a remote block needs data computed locally.

How does Invoke-Command run on many machines at once?

Give -ComputerName a comma-separated list (or an array), and Invoke-Command fans the script block out to all of them IN PARALLEL, then collects every machine's results into one stream. Each result object carries a PSComputerName property so you can tell which host produced it. There's a built-in throttle limit (default 32 concurrent connections) you can tune with -ThrottleLimit. This fan-out is what makes remoting scale from one server to hundreds.