In PowerShell remoting, what is the difference between Enter-PSSession and Invoke-Command, and when would you use each?
answer
- one host or many
- who types the commands
- prompt prefix versus pipeline output
- script block ships, results return
basics
~20 sEnter-PSSession opens an interactive prompt on one remote machine, so you type commands there and see results immediately. Invoke-Command sends a script block to one or many machines, runs it there, and returns the results into your local session.
solid answer
~40 sBoth use PowerShell remoting, but they serve different modes of work. `Enter-PSSession` is the interactive one: it attaches your console to a runspace on a single remote host, your prompt changes to show that host, and you work as if you were logged on there until you type `exit` or `Exit-PSSession`. `Invoke-Command` is the non-interactive one: you hand it a script block (or a local script file with `-FilePath`) and a list of computers, it runs that code remotely, and the output flows back into your local pipeline where you can sort, filter or export it. `Invoke-Command` accepts an array of computer names and fans out in parallel; `Enter-PSSession` targets exactly one host. In practice you explore with `Enter-PSSession` and automate with `Invoke-Command`.
go deeper
Know that Enter-PSSession puts you at a prompt on one remote machine and Invoke-Command runs a script block on one or many and hands the output back to you. Recognise the [Server01]: prompt prefix.
Be ready to explain that the script block is shipped to a remote runspace, so local variables need $using: or -ArgumentList, and that -FilePath is read locally. Mention the parallel fan-out and the added PSComputerName property.
Show the operational instinct: automate with Invoke-Command so results are objects you can aggregate and audit, and treat Enter-PSSession as a diagnostic tool where a mistyped command lands on production. Know that both can ride a reusable session.
Frame the choice as interactive troubleshooting versus repeatable, reviewable automation. Argue for script blocks under version control and against habitual interactive sessions on production hosts, and set the expectation that remote work produces collectable evidence.
## What remoting actually sets up PowerShell remoting works by starting a *runspace* — a live PowerShell engine — on the remote machine and exchanging serialized objects with it over a transport (WS-Man/WinRM by default, or SSH). Every remoting cmdlet is a different way of driving that remote runspace. The two you meet first are `Enter-PSSession` and `Invoke-Command`, and the difference between them is simply **who types the commands**: you, at a prompt, or a script block you wrote in advance. ## Enter-PSSession: the interactive prompt ```powershell Enter-PSSession -ComputerName Server01 # prompt becomes: [Server01]: PS C:\Users\me\Documents> Get-Service -Name Spooler exit ``` While you are inside, everything you type is executed on the remote host and the rendered output is sent back for display. The prompt prefix `[Server01]:` is the visible cue that you are no longer local — forgetting that is how people run a destructive command on the wrong box. You leave with `exit` or `Exit-PSSession`. `Enter-PSSession` targets **one** machine. Its `-ComputerName` parameter takes a single string, not an array, because an interactive console cannot sensibly be attached to fifty hosts at once. It is the tool for exploration, poking at a misbehaving server, or checking something you cannot yet express as a script. ## Invoke-Command: the scripted one ```powershell Invoke-Command -ComputerName Server01, Server02, Server03 -ScriptBlock { Get-Service -Name Spooler } | Sort-Object PSComputerName ``` Here the code is fixed up front. Each host runs the script block and returns its output; the results arrive in your **local** session as ordinary pipeline input, so you can `Where-Object`, `Sort-Object`, `Export-Csv` them locally. PowerShell tags each returned object with a `PSComputerName` property so you can tell whose result is whose — essential once you target more than one machine. `Invoke-Command` fans out in parallel across the computers you give it, so contacting many hosts is roughly as fast as contacting the slowest one, not the sum of all of them. ## The variable trap The script block is *shipped* to the remote host, so it does not close over your local variables: ```powershell $svc = 'Spooler' Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Service -Name $svc } # $svc is empty remotely Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Service -Name $using:svc } # correct ``` The `$using:` scope modifier tells PowerShell to capture the local value and send it along. The alternative is `-ArgumentList` together with a `param()` block inside the script block. Both are fine; `$using:` is shorter. ## -FilePath is read locally ```powershell Invoke-Command -ComputerName Server01 -FilePath .\Collect-Inventory.ps1 ``` This reads the file **on your machine** and sends its contents to run remotely. The script does not need to exist on the target, and does not need to be copied there first — a point people frequently get backwards. ## Both can ride on an explicit session Neither cmdlet is tied to `-ComputerName`. If you have created a session with `New-PSSession`, both accept it via `-Session`, which lets you reuse one connection and keep state between calls: ```powershell $s = New-PSSession -ComputerName Server01 Invoke-Command -Session $s -ScriptBlock { $x = 42 } Enter-PSSession -Session $s # $x is still there ``` ## Choosing between them Use `Enter-PSSession` when you do not yet know what you want to run, on a single host, and a human is watching. Use `Invoke-Command` for anything repeatable, anything touching more than one machine, and anything whose output you want to process — because its results come back as objects in your own session rather than as text on a remote screen. An interviewer asking this is checking that you understand remoting returns *data to you*, rather than merely giving you a remote terminal.
- Why does a local variable referenced inside an Invoke-Command script block come back empty on the remote host?The script block is serialized and executed in a remote runspace that knows nothing about your local scope, so the name resolves to nothing there. Use the `$using:` scope modifier — `$using:path` — to capture the local value and send it with the block, or pass values through `-ArgumentList` and receive them in a `param()` block inside the script block.
- If you pass Invoke-Command a script with -FilePath, does that file have to exist on the remote machine?No. `-FilePath` reads the script from your local filesystem, and its contents are transmitted and executed in the remote runspace. Nothing is copied to the target's disk and no share or pre-staging is required, which makes it convenient for running an ad-hoc script against machines you have not prepared.
- How do you tell which of several machines produced a given object returned by Invoke-Command?Remoting adds a `PSComputerName` property (plus `RunspaceId`) to every object returned from a remote runspace, so you can group, sort or filter on it — `... | Sort-Object PSComputerName` or `... | Group-Object PSComputerName`. It is added automatically for the `-ComputerName` fan-out case, which is why you should never rely on output ordering to identify hosts.
saying these in an interview costs you the question
- Claims Enter-PSSession can target a list of computers at once
- Thinks Invoke-Command gives you an interactive remote shell
- Assumes local variables are automatically visible inside the script block
- Believes -FilePath requires the script to exist on the target
- Says results are plain text rather than objects in the local pipeline