When it comes to PowerShell Remoting, we can distinguish between synchronous and asynchronous processing. In the latter case, you work with disconnected remote sessions.

If you create an interactive remote PowerShell session with the Enter-PSSession cmdlet, you do synchronous PowerShell Remoting. Whenever you enter a command, you have to wait for PowerShell to process the command and produce the results

Likewise, if you execute a PowerShell command remotely with the help of the Invoke-Command cmdlet, you are also working in synchronous mode because your console is blocked while you wait for the results.

In contrast, if you do asynchronous Remoting, you run a command or execute a script in the background on a remote machine and collect the output later.

Creating a disconnected session with Invoke-Command ^

The easiest way to execute a command asynchronously on a remote machine is to use the ‑InDisconnectedSession parameter:

Invoke-command -ComputerName $RemoteComputer -ScriptBlock {Get-Process} -InDisconnectedSession

Invoke-Command with the -InDisconnectedSession parameter

Invoke-Command with the -InDisconnectedSession parameter

Your PowerShell prompt will return instantly. Instead of receiving the output of the remotely executed command, you will receive information about the session. Before we dive deeper into the different ways of using Invoke-Command asynchronously, we have to take a closer look at the concept of user-managed PowerShell sessions (so-called PSSessions). Without a fundamental understanding of PSSessions, your remotely executed commands might disappear in the nirvana of PowerShell sessions.

In my previous post, I mentioned that PowerShell Remoting creates a user-managed PowerShell session when you execute commands on a remote computer. This PSSession is connected to your local session, but it terminates at the remote computer where it is maintained.

Viewing PowerShell sessions ^

To view all the sessions that are connected to your local session, you can use the Get-PSSession cmdlet:


Viewing connected PSSessions with Get-PSSession

Viewing connected PSSessions with Get-PSSession

The ID can differ when you connect from a different machine, but the session name will always be identical. If you don’t specify a name when you create the session, PowerShell will choose one for you. ComputerName tells you where the session is maintained.

The State property is set to Disconnected if your current session is not connected to the PSSession. However, this doesn’t mean that another session, say on another machine, isn’t connected to the PSSession. After you connect to the session, the State property changes to Opened.

If the Availability property is set to Busy, someone else might be connected to the session and you cannot connect it. It can also mean that the session has some unfinished business (for instance, if data waits in the session to be collected). In this case, you can connect to a busy session (in contrast to what the official documentation claims).

If Availability is set to None, it doesn’t mean that you can’t connect to the session. It just means that your current session is not connected to the PSSession. Once you are connected, the Availability property will change to Available.

You can also view this session when you log onto the remote computer via RDP or Enter-PSSession. However, if you then just run Get-PSSession without parameters, you won’t see the session. Why? If you launch a PowerShell host on the remote machine, you create a new PowerShell session; this session is not connected to the PSSession that you created remotely. To view the PSSession on a console on the remote computer, you have to pass the computer name. In this case, you can use localhost.

Viewing PowerShell sessions on a remote computer

Viewing PowerShell sessions on a remote computer

As you can see in the above screenshot, there are now two PSSessions on the remote computer: the one I created with Invoke-Command on my local computer and the one I created with Enter-PSSession.

Connecting and disconnecting sessions ^

You face a similar problem when you close the PowerShell host on the local computer where you executed Invoke-Command. If you want to reconnect to a disconnected PSSession, you need the Connect-PSSession cmdlet:

Connect-PSSession $RemoteComputer

Reconnecting to a remote PowerShell session

Reconnecting to a remote PowerShell session

If multiple sessions are running on the remote computer, the above command will connect them all to your current session. Once you are connected to a session, you can list it with Get-PSSession without specifying the remote computer’s name. However, the session will still be in the list after you manually disconnect a session with the Disconnect-PSSession cmdlet.

Disconnect-PSSession -id 1

Why would you want to disconnect a session? As mentioned above, a PSSession can only be connected to one session at a time. Thus, if you want to connect to a session from another computer, you have to ensure that the session’s state is disconnected. Note that closing (disconnecting) a session does not terminate it. To destroy a PSSession, you can run the Remove-PSSession cmdlet.

If you run Invoke-Command in synchronous mode (for instance, if you didn’t pass the ‑InDisconnectedSession switch), the corresponding session will automatically be removed after your command completes.

In contrast, if you work with disconnected sessions in asynchronous mode, you should remove the session after your task completes. By default, PowerShell removes idle sessions—that is, sessions that receive no communication—after two hours. However, you can change the default idle timeout when disconnecting from the session with the cmdlet’s - IdleTimeoutSec parameter:

Disconnect-PSSession -Name mySession -IdleTimeoutSec 43200

This sets the timeout to 43200 seconds (12 hours) which is the default maximum idle timeout. (You can change the maximum idle timeout with the MaxIdleTimeoutMs property of the session configuration as described below.) Another option is to set the timeout when you create the session:

$TimeOut = New-PSSessionOption -IdleTimeoutMSec (New-TimeSpan -Days 7).TotalMilliSeconds
Invoke-Command -ComputerName $RemoteComputer -ScriptBlock {Get-Process} -InDisconnectedSession -SessionName mySession -SessionOption $TimeOut

In this case, you can use larger values for the timeout than 12 hours. To view how the idle timeout of a session is configured, you can use this command:

(Get-PSSession -Name mySession).IdleTimeout

Or, if you are too lazy to convert milliseconds to days, you can do this:

(New-TimeSpan -Seconds (((Get-PSSession -Name mySession).IdleTimeout)/1000)).Days

And to view when a session expires, you can run this:

(Get-PSSession -Name mySession).ExpiresOn

If the default idle time setting is not to your liking, you can change the $PSSessionOption preference variable:

$PSSessionOption = New-PSSessionOption -IdleTimeoutMSec (New-TimeSpan -Days 7).TotalMilliSeconds

Entering a disconnected session to receive results ^

I think you should now have a feel for how disconnected PSSessions behave, which guarantees that you will be able to collect the data that your remote command or script generates. The first idea that comes to mind is to simply start an interactive session with Enter-PSSession and read the variables living in the session. This does indeed work. However, you first have to connect to the session with Connect-PSSession. Otherwise, you will receive this error message:

Enter-PSSession : Cannot enter session Session1 because it is not in the disconnected state or is not available for connection. Reconnect using Connect-PSSession or Receive-PSSession.

You might also see a warning that the session is busy; nevertheless, you can then read the variables of the session.

Connecting to a disconnected session with Enter-PSSession

Connecting to a disconnected session with Enter-PSSession

However, this only works after the job completed. If the job is still running, you will be connected to the session as soon as it is available.

I think the example also illustrates the difference between connecting to a session and entering a session. Connecting to a remote session just means that the session is exclusively linked to your local session. At this point, you can’t access the remote session from another session, say on another computer. It is important to note that if you exit your current session, say by closing your PowerShell console, all connected sessions on remote machines will be destroyed.

Entering a session with Enter-PSSession means establishing an interactive PowerShell session to the remote computer. You can run all cmdlets that are available on the remote machine, including those provided by modules that are installed on the remote computer. Before you can enter an existing PSSession, you have to connect to the session with Connect-PSSession.

Receiving results from a remote session ^

But entering a session to access output data generated by commands that you executed with Invoke-Command in a One-to-Many Remoting scenario is not really what you want to do. You don’t want to manually connect to all your remote sessions to read the job results. The common way is to use the Receive-PSSession cmdlet in your local session:

Invoke-Command -ComputerName $RemoteComputer -ScriptBlock {Get-Process} -InDisconnectedSession -SessionName mySession
Receive-PSSession -Name mySession
Remove-PSSession -Name mySession

In contrast to Connect-PSSession, you must specify the session from which you want to get the results. Receive-PSSession automatically connects to the session if it is disconnected from your current session. It then reads the output that the commands in the session generated while the session was disconnected. The remote session will stay connected to your current session and it won’t terminate. You can destroy a session with the Remove-PSSession cmdlet as demonstrated in the above example.

To remove all your sessions, you can pipe the result of Get-PSSession to Remove-PSSession:

Get-PSSession | Remove-PSSession

In my next post, I will discuss the three different types of remote jobs in One-to-Many Remoting scenarios with Invoke-Command.

  1. sai kumar 5 years ago

    how to force remove-pssession to print the output.

    • Author
      Michael Pietroforte 5 years ago

      Remove-Pssession doesn’t have a parameter for that. You can do it like this:

       Receive-PSSession -Name $mySession; Remove-PSSession -Name $mySession

Leave a reply

Your email address will not be published.


© 4sysops 2006 - 2022


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account