Enable PowerShell "Second-Hop" Functionality with CredSSP

Enable PowerShell "Second-Hop" Functionality with CredSSP

  • Comments 11
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about the dreaded "second-hop" problem with Windows PowerShell and how to overcome it with CredSSP.

 Microsoft Scripting Guy, Ed Wilson, is here.

First, a description of the problem

In yesterday’s article, I talked about using the Windows Update module to update drivers, patches, etc. on my local computer. This worked really great.

Note   For more information about the Windows Update module and using it to update a local system, see yesterday’s blog post: Use a PowerShell Module to Run Windows Update.

By storing the module in a centralized shed location, I should be able to maintain a single location for the module—and, therefore, simplify my maintenance problem of updating dozens of servers every time the module receives an upgrade. In fact, it should be a simple matter to run the module and to update the remote system. I only need to create a remote session, import the module into the session, and run the Get-WUInstall cmdlet (advanced function).

Unfortunately, when I try to run the Invoke-Command cmdlet, I receive a “ResourceUnavailable” error and a “not recognized as the name of a cmdlet” error. These errors are shown here.

Image of command output

When I use Invoke-Command to test the path, I receive an “Access is denied” error. This appears strange because I am running with administrator rights, and I know that I have access through the share and through the NTFS file system permissions. I can test the path from my local computer (as I did yesterday) and it works perfectly. Hmm … I wonder what is going on?

I decide to use Remote Desktop Protocol (RDP) to access my SQL1 server and run the test path from there. (By the way, with Windows PowerShell, all I need to do is type MSTSC to open the Remote Desktop Connection screen).

I open Windows PowerShell from the RDP session on my SQL1 server, and type Test-Path. It resolves and returns True. This is shown here.

PS C:\> Test-Path \\dc1\Share\PSWindowsUpdate

True

I can also import the module from the DC1 share. This command is shown here.

Import-Module -Name \\dc1\Share\PSWindowsUpdate

In addition to importing the module, I can also test out the cmdlets (advanced functions), and I see that they work as well. This is shown in the following image.

Image of command output

So, it is not a name resolution issue because the SQL1 server is definitely able to see the DC1 server. Also, from the SQL1 server I am able to see the share, import the module, and even run commands exposed from the module. I am just not able to do these from my computer, to the SQL1 server, TO the DC1 server—it is the notorious “second hop” problem.

This situation is shown in the figure that follows. Client A enters a remote PS Session onto Server A. Inside the session, the Get-Process cmdlet runs, everything works perfectly, and Client A sees a listing of all the running processes on Server A. Now, from within this remote Windows PowerShell session, Test-Path is used to check the path to a share on Server B. This fails with an Access Denied error. This is due to the second hop, in which the credentials from Client A that were used to enter the remote PS Session are attempted to be carried over to Server B to check the path.

Diagram 1 - second hop

Using CredSSP to solve the second-hop problem

Back in the Windows Vista days, we introduced a new security delegation module called Credential Security Service Provider (CredSSP). This was originally designed to work with Terminal Services because everything in Terminal Services is basically a second hop. What is going on with the second hop? Well, I can remote into my SQL1 server and do things locally—no problem. I use the credentials I specify when I make my connection to the remote server. But when I want my SQL1 server to go off and talk to the DC1 server—that is a second hop. Now where do the credentials for that hop come from? Well, it wants to use the credentials I specified when I connected to SQL1, but that COULD be a problem is SQL1 is a compromised machine because I could take my credentials and go off and do a lot of stuff.

Think of it this way. My dad loans his credit card to me so I can use it to make specifically authorized purchases (perhaps to purchase petrol so I can come home for the holidays). Now my dad trusts me, and he trusts that I will use the credit card for only those specific petrol purchases. This is the first hop, and is permitted in all of our management scenarios. Now, suppose I decide to loan my dad’s credit card to some of my friends. This is not permitted by my dad because he does not know who my friends are or what they are going to do with his credit card.

However, suppose he did know one of my friends. And he wanted to help my friend out and permit him to go home for the holidays as well. Then, in that case, he would specifically permit a second hop for a particular person and for a particular situation—this is where CredSSP comes into play.

Note   For more information about CredSSP, read this excellent article on MSDN.

I need to make two changes. On my client workstation, I need to use the Enable-WSManCredSSP cmdlet to enable the client role and then specify the computer to which I want to delegate my credentials. This command is shown here.

Enable-WSManCredSSP -Role Client -DelegateComputer *.iammred.net -Force

Now, I also need to make a change on the remote server to permit it to use delegated credentials. This command is shown here.

Enable-WSMaCredSSP -Role Server –Force

The use of these two commands is shown in the image that follows.

Diagram 2 - second hop

Making the second hop

I can now use CredSSP to make the second hop, and therefore, to use the centralized module. There are, however, two very important things to keep in mind when making the connections.

  1. When making the PS Session, ensure that I use –Authentication CredSSP.
  2. When making the PS Session, ensure that I use the FQDN of the remote server. (This is true because I specified the delegate computer as *.mydomain.net. If I had specified the delegate computer as Sql1.mydomain.net, I would not need the FQDN.)

My use CredSSP script is shown here.

$credential = Get-Credential -Credential iammred\administrator

$session = New-PSSession -cn SQL1.Iammred.Net -Credential $credential -Authentication Credssp

Invoke-Command -Session $session -ScriptBlock {Test-Path \\dc1\share\PSWindowsUpdate}

Invoke-Command -Session $session -ScriptBlock {

  Import-Module -Name \\dc1\Share\PSWindowsUpdate }

Invoke-Command -Session $session -ScriptBlock {Get-WUHistory }

Join me tomorrow when I will have a guest blog article written by Microsoft MVP Don Jones as he excerpts his new “Learn Windows PowerShell 3 in a Month of Lunches” book. The blog post is called “Digging into PowerShell Remote Authentication.” A very good post indeed—you will NOT want to miss it.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Are there any other ways to do second-hop work?  Sometimes I need to make mass changes on my user workstations that require use of network files:

    invoke-command -computername $listofworkstations -scriptblock{

     copy-item -source \\namespace\share\file.txt -destination C:\utilities\file.txt

     #do stuff with file.txt

    }

    Having all my workstations be CredSSP servers seems unfeasible not to mention a potential security risk.

  • Unless MS has fixed this in 2012 even with CredSSP you can't actually install updates through remoting. You will get an access denied. If you have a solution I'd love to know as we struggled with this for some time and ended up resorting to using psexec which did not suffer the limitation. Alternatively you can create a scheduled task and invoke it, but not run the actual installation method.

  • @Neil, you can use Constrained Delegation instead of CredSSP to enable the second-hop to work. I've blogged about how I achieved this:

    blog.codeassassin.com/.../powershell-remoting-user-profiles-delegation-and-dpapi

  • @Neil, @Jason one thing to keep in mind, is I can remotely enable CredSSP, do the second hop, then in the same script turn it off. It does not even require a reboot. Obviously, there are other ways to do all of this, I just wanted to document some procedures for getting CredSSP to work.

    @Sean - unfortunately, even using the Windows Update module, I cannot remotely install a hotfix. I can detect, but not install. The solution for this is to prop up a WSUS server, or to use System Center.

  • Hey, when you said to enable on the remote machine you typed this:

    Enable-WSMaCredSSP -Role Server –Force

    Thats a typo...  Should be Enable-WSManCredSSP -Role Server –Force

    Thanks!

  • I can't tell you how many times I have unsuccessfully tried to get that to work!  Thanks a ton for the article, I was forgetting the -authentication parameter.

  • 3rd hop possible? (im not sure if that technically correct) For example, I need to run a bat file remotely. So far this article has helped me run that bat files as the desired user with the -Authentication CredSSP option but the bat file then calls another powershell script like this >> powershell.exe myscript.ps1 %arg%. That powershell script then connects to a database via Integrated security. It seems my session creds aren't being respected from this point on. Any advice?

  • What's the point if you have to type in your credentials? CredSSP is not very "automation friendly". Storing credentials in a file is just a bad idea, and I'm certain a security risk, especially for accounts that have admin level access. Am I missing something?

  • Hi, Thanks for the excellent post. In My case Server A is windows 2012, Server B is windows 2008 R2 and file share is non windows server. I have followed the approach outlined above. it is not working.

    The below case is working fine.
    Server A is windows 2012 R2, Server B is windows 2012 R2 and file share is non windows server

    Can you please help?

  • I've got Access Denied while Import-Module ...ConfigurationManager.psd1 in -ScriptBlock section. Can't figure out why. Any idea?