Tome's Land of IT

IT Notes from the Powertoe – Tome Tanasovski

Category Archives: Remoting

Receiving a Disconnected PowerShell Session Asjob

I was down in Washington DC delivering a presentation about Windows Server 2012 for a roadshow that Microsoft put on. This was one stop in a few that I was lucky enough to be a part of (actually it’s not over yet – Boston is coming up on Wednesday). During that presentation I was showing off how you can disconnect a PowerShell session and then receive that session from another computer. This is a great new feature in PowerShell remoting that is integral to the new movement in Server to use PowerShell or tools that leverage PowerShell like the new server manager as the management tool of choice.

The demo goes like this:

Setup

3 computers

Server1 – The computer I am starting on. Windows Server 2012 RC1 (with PowerShell v3)
Server2 – The computer I am connecting to. Windows Server 2012 RC1 (with PowerShell v3)
Server3 – The computer I will use to connect to Server2 after Server1 is disconnected. Winows Server 2012 RC1 (with PowerShell v3)

The following script gets run on Server1 to start it off:

# Create a remote session
$s = New-PSSession -ComputerName server2
$s
# Start a long running command as a job on the session
$job = Invoke-Command $s {1..10000 | % {sleep 1; "Output $_"}} -AsJob
$job

After the job runs for a few seconds, you run the following on Server1 to disconnect the session:

Disconnect-PSSession $s

You can then close PowerShell on Server1 and open it on Server3. The following command will show you what sessions are available on Server2:

Get-PSSession -Computername Server2

The demo is finalized by performing the following to get into the session that was disconnected on Server1:

Get-PSSession -Computername Server2 |Receive-Session

This is a great demo that shows one of the best new features in the new version of the management framework. The only downside with the above is that the command started as a job, but when you call receive-pssession you are placed in the middle of the session as if you typed enter-pssesion. The problem with this is that ctrl-c will now break your running process. The natural question that was posed during the demonstration was, “How do you run receive-pssession, but keep it as a job?” My first inclination was to see if receive-pssession had an -asjob parameter. The answer is no. The solution is rather simple, but it did throw me for a loop. So much so that I thought I would share.

Solution

If you want to call receive-pssession asjob, simply run start-job with receive-pssession:

$job = Start-Job -ScriptBlock {Get-PSSession -ComputerName Server2|Receive-PSSession}

I told you it was simple, and I’m sure plenty of you who are reading this had figured this out without having to read the article. However, I thought it was worth discussing. If nothing else, this article at least highlights one of the great new features in PowerShell v3 Remoting.

Updated Solution – 6/26/2012

Thanks to Steve and Andreas in the comments (they require approval so I read them at the same time before they were visible on the page), there is a parameter in Receive-PSSession called OutTarget.  You can specify the following to force a Receive-PSSession to return a job:

$job = Get-PSSession -Computername Server2 |Receive-PSSession -OutTarget Job

I don’t like this.  I don’t like this so much that I have filed a connect suggestion to make Receive-PSSession use the more familiar -ASJob parameter.  Feel free to vote it up, if you agree.  Now, with that distraction, I hope no one noticed that I absolutely did not read the full Get-Help before making this post.  <ahem> wait…. I’ll come up with an excuse eventually.  All kidding aside, thanks for reading!  And thank you for helping make the site accurate!

Enable CredSSP from a Windows 7 Home Client

While I do have a Win 7 Pro license, pure laziness has kept me from installing it on my Alienware laptop. This is fine for most things, but I ran into a bit of a problem while writing the Active Directory chapter for the PowerShell Bible. In order to use the ActiveDirectory module via remoting on my 2k8r2 server I needed to use CredSSP as my authentication type. Step one was easy. Launch PowerShell as an admin and run:

Enable-WSManCredSSP -Role client -DelegateComputer server1.home.toenuff.com

Now, if you’ve ever run this before you are probably familiar with the next error message that will return if you try and run Enter-PSSession or Invoke-Command with -Authentication CredSSP:

Enter-PSSession : Connecting to remote server failed with the following error message : The 
WinRM client cannot process the request. A computer policy does not allow the delegation of 
the user credentials to the target computer. Use gpedit.msc and look at the following policy
: Computer Configuration -> Administrative Templates -> System -> Credentials Delegation -> 
Allow Delegating Fresh Credentials. Verify that it is enabled and configured with an SPN ap
propriate for the target computer. For example, for a target computer name "myserver.domain.
com", the SPN can be one of the following: WSMAN/myserver.domain.com or WSMAN/*.domain.com. 
For more information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:16
+ Enter-PSSession <<<< -Credential $cred server1 -Authentication credssp
 + CategoryInfo : InvalidArgument: (server1:String) [Enter-PSSession], PSRemoti 
 ngTransportException
 + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

In most versions of Windows you can then follow the instructions in the error message which tell you explicitly how to handle this, but with a home version of Windows this is a bit of a problem because there is no gpedit.msc snapin or local policy to modify. Fortunately, we know that every policy is really just a registry setting. I was able to track it down specifically:

  • Create a Dword key called AllowFreshCredentials with a value of 1 in hklm:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation
  • Create a separate String entry for each computer in hklm:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentials
  • Each entry within the AllowFreshCredentials key should be named an integer, and the first entry should be 1
Strangely, the above fix used to work for me, however, recently a new error started appearing that talked about another local policy.  I thought this was related to SP1, but I’ve been told by others that this has existed for some time.   This additional local policy has to be set in order to allow CredSSP to use NTLM authentication instead of Kerberos.  The fix is the exact same as the above except that the AllowFreshCredentials name also has AllowFreshCredentialsWhenNTLMOnly.
The following script will do both of these registry changes for you.  Mind you, it doesn’t handle entries already in the AllowFreshCredentials or AllowFreshCredentialsWhenNTLMOnly key, but you could easily handle that if it was a concern you had:
$allowed = @('WSMAN/*.home.toenuff.com','WSMAN/server1')            

$key = 'hklm:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation'
if (!(Test-Path $key)) {
    md $key
}
New-ItemProperty -Path $key -Name AllowFreshCredentials -Value 1 -PropertyType Dword -Force            

$key = Join-Path $key 'AllowFreshCredentials'
if (!(Test-Path $key)) {
    md $key
}
$i = 1
$allowed |% {
    # Script does not take into account existing entries in this key
    New-ItemProperty -Path $key -Name $i -Value $_ -PropertyType String -Force
    $i++
}