Disconnected Sessions: Phenotype and Genotype (Part 1)

Summary: Learn about a revolutionary feature in Windows PowerShell 3.0 that lets you disconnect from and reconnect to PSSessions.

Scripting Guy, Ed Wilson here. We have an exciting guest blog series that is written by Paul Higinbotham, a software design engineer for Windows PowerShell and June Blender, a senior programming writer for Windows Azure Active Directory. Today, June is going to start us off…

In Windows PowerShell 2.0, when you closed a session, such as your Windows PowerShell console window, or you lost your network connection, you lost all remote sessions (PSSessions) that you started in that session. And if a command just happened to be running in one of those remote sessions, the command stopped, and its results were forever lost.

All of that changed in Windows PowerShell 3.0. And, for those of us who multitask (frequently switching machines and coming and going between our home and office), it was a dream come true. I'm always surprised that I don't hear more people raving about this change. But maybe you just don't know the whole story.

To help me tell this story, I've recruited Paul Higinbotham, the Windows PowerShell developer who coded this feature. I'll explain how you use it (the "phenotype") and then, in a few follow-up posts, Paul will explain why it works (the "genotype"). I'm always pleased to get a chance to work with Paul, who's a great writer as well as a great coder. When you hear from him, you'll want to get to know him, too.

Need to go home? No problem!

So, here's the scenario:

An IT pro is hard at work diagnosing a failure on Server01, which is a remote machine with a tricky problem. She creates a PSSession to Server01 and then runs a few commands and a diagnostic script that takes a while to complete. In the meantime, she closes the session, closes the computer, and starts another task on a different machine. At the end of a long day, she heads home.

After dinner, she opens her home laptop, connects to her corporate network, starts Windows PowerShell, connects to the PSSession on Server01 and reviews the results. She runs a few more commands before calling it a day.

Next morning, she goes to work, reconnects to the session on Server01, and continues her investigation.

This scenario works in Windows PowerShell 3.0 because the PSSession is saved on the remote computer when the session is disconnected, either intentionally or unintentionally (such as when the network connection is interrupted). The PSSession becomes independent of the session in which it was created. Let's run through the commands that she uses.

First, she creates a PSSession named Diag on Server01, runs some commands and a script.

PS C:> $s = New-PSSession -Name Diag -ComputerName Server01

PS C:> $s

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

2 Diag localhost Opened Microsoft.PowerShell Available

Notice that the State of the PSSession is Opened and the Availability is Available, which means that she can run commands in the PSSession.

Among the commands that she runs is a command to save the current date and time in a $Start variable in PSSession. She'll use this value to track the time spent on this machine.

PS C:> Invoke-Command -Session $s {$start = get-date}

PS C:> Invoke-Command -Session $s {$start}

Wednesday, September 18, 2013 2:51:20 PM

PS C:> Invoke-Command -Session $s -FilePath Get-Diagnostics.ps1

PS C:> Invoke-Command -Session $s { <more_commands>}

Before she moves to a different computer, she disconnects the PSSession. There are several ways to do this, including simply closing her laptop, but she uses the Disconnect-PSSession cmdlet.

Notice that the State is Disconnected and the Availability is None, which means that no one is using the session.

In Windows PowerShell 2.0, if a session is disconnected, all is lost. But in Windows PowerShell 3.0, the commands continue to run uninterrupted in the disconnected session. It's…well…revolutionary!

Meanwhile, at home…

Our IT pro finally finishes her tasks and goes home. After whipping up a gourmet dinner and enjoying an evening bicycle ride, she grabs her Surface Pro, connects to her corporate network, starts Windows PowerShell, and reconnects to the Diag PSSession on Server01. To find the disconnected PSSession, she uses the ComputerName parameter of the Get-PSSession cmdlet.

PS C:> $s = Get-PSSession -ComputerName Server01 -Name Diag

PS C:> $s

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

1 Diag Server01 Disconnected Microsoft.PowerShell None

The ComputerName parameter of Get-PSSession works differently in Windows PowerShell 2.0 and Windows PowerShell 3.0. In Windows PowerShell 3.0, the ComputerName parameter is an implicit remoting command.

Windows PowerShell 2.0: Gets all PSSessions in the current session, and selects the ones that connect to Server01.

Windows PowerShell 3.0: Connects to the Server01 computer, and gets the PSSessions that this user started.

She's glad that she remembered to name the PSSession, because she has several PSSessions to the Server01 computer, and the ID property is not persistent; it can change with each connection.

Next, she uses the Connect-PSSession cmdlet to reconnect to the disconnected PSSession.

PS C:> Connect-PSSession $s

PS C:> $s

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

9 Diag Server01 Opened Microsoft.PowerShell Available

Now, the PSSession state is Opened, indicating that she's connected to it, and the Availability is Available, so she can run commands in the PSSession.

If, at this point, she peeks at the Diag PSSession from another computer (or another session on the same computer), it looks a bit different. From the perspective of another session, the Diag PSSession is Disconnected, that is, not connected to the current session. It is also Busy, meaning that it is connected to another session.

PS C:> Get-PSSession -ComputerName Server01 -name Diag

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

1 Diag Server01 Disconnected Microsoft.PowerShell Busy

Now, back in the reconnected PSSession, our IT pro can review the output, and run more commands.

And that $Start variable from the afternoon? It's still there:

PS C:> Invoke-Command -Session $s {$start}

Wednesday, September 18, 2013 2:51:20 PM

Back to work

When our roving IT pro gets to work bright and early in the morning, she opens her main computer and reconnects to the PSSession. This time, she uses Receive-PSSession, which gets the results of her commands and automatically reconnects to the PSSession.

PS C:> $s = Get-PSSession -ComputerName Server01 -name Diag

PS C:> $s

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

1 Diag Server01 Disconnected Microsoft.PowerShell None

PS C:> $results = Receive-PSSession $s

PS C:> $s

Id Name ComputerName State ConfigurationName Availability

-- ---- ------------ ----- ----------------- ------------

7 Diag localhost Opened Microsoft.PowerShell Available

And that session-specific $Start variable is still in the PSSession:

PS C:> Invoke-Command -Session $s {$start}

Wednesday, September 18, 2013 2:51:20 PM

Pretty remarkable? In the next post in this series (watch for it on Saturday, October 12), I'll show you how to use the InDisconnectedSessions parameter of Invoke-Command and share a few "gotchas" to keep you out of trouble. In the meantime, try it, and use the following Leave a comment section to send questions to me and Paul.

This is all part of the implicate order of things. PowerShell is just now expressing its pedigree. As it evolves we should see an even better selection of traits expressed. Yes, in software, pedigree is absolute.