PowerShell Remoting Kerberos Double Hop Solved Securely


The struggle is real.

Are you facing issues with PowerShell remoting and credentials? You remote into your jump box, but then any remoting beyond there gets a big red ACCESS DENIED. Maybe you’ve tried CredSSP, but people say that isn’t safe. Read today’s post for a completely legit, secure, safe, and easy way to enable Kerberos double hop for PowerShell remoting.

The Problem

image

It’s a tale as old as time:

  • ServerA talks to ServerB
  • ServerB talks to ServerC
  • Access denied!

You would have better luck asking a cheerleader to the prom. We call this the kerberos double hop. Yeah, it’s like a dance.

The struggle is real. Just check out this forum post on PowerShell.org from last month. After many years of PowerShell remoting we are still searching for a secure method of passing credentials to that elusive ServerC.

Neo vs. the Architect

Many have come before you. Let’s look at some of the popular solutions for Kerberos double hop in PowerShell remoting:

Method Pros Cons Links
Grant access to the ServerC resource for the ServerB computer object. n/a It works for some other double hop use cases, but not PowerShell remoting.
CredSSP It works! It’s not totally secure.
Requires configuration of the client and server roles.
Accidental Sabotage: Beware of CredSSP
[MS-CSSP]: Credential Security Support Provider (CredSSP) Protocol – 5.1 Security Considerations for Implementers
PSSessionConfiguration using RunAs It works! Requires PSSessionConfiguration and RunAs credential password maintenance on every ServerB. Another solution to multi-hop PowerShell remoting
JEA – Just Enough Administration It works!
When using a virtual account or group managed service account (gMSA) there is no password maintenance.
Requires WMF 5.0 or above.
Requires role capability module and PSSessionConfiguration on every ServerB.
Just Enough Administration
Pass fresh credentials inside the Invoke-Command scriptblock ($using:cred) It works!
No special server configuration.
No Windows Server 2012 requirement.
Awkward code technique.
Easiest using WMF 3.0 or above. Also possible by using the WMF 2.0 syntax for passing arguments to a remote session.
See the very bottom of this article for a code sample.
Kerberos Constrained Delegation It may work if you can figure it out.
No special coding required.
Moves authority from the back-end resource owner to the front-end application owner.
Limited to one domain; cannot cross a trust.
Requires domain administrative rights to update objects and SPNs.
Not documented for PowerShell remoting.
Kerberos Unconstrained Delegation It works!
No special coding required.
It’s not totally secure.
Allows delegation of credentials with no control over where they get used.
Resource-Based Kerberos Constrained Delegation No stored credentials.
Easy to configure.
Works across domains and forests.
No special coding required.
Requires Windows Server 2012 and above for most servers involved.
See KB2665790 for 2008 R2 support.
Support for limited commands running as SYSTEM.
Does not support WinRM.
See links at the bottom of the article.

 

Resource-Based Kerberos Constrained Delegation

Every release of Windows Server packs tons of new features, many that do not make big headlines. In my opinion this solution has been around four years now, and no one has uncovered its use for PowerShell remoting. I have researched this topic thoroughly, and I have not found anyone else online documenting this feature as a solution for PowerShell remoting.

Windows Server 2000 included Kerberos delegation (unconstrained). This allowed ServerB to delegate credentials anywhere else in the domain. Not good.

Windows Server 2003 modified this concept to constrained delegation, limiting delegation from ServerB to only designated service principal names (SPNs) on ServerC. This was much better, and it is common practice today. Many have struggled to get this working for PowerShell remoting, since it is not a documented solution.

Windows Server 2012 simplified the design by instead configuring the delegation on the computer object of ServerC, called resource-based delegation, specifying from whom it will receive delegated credentials. The same attribute can be set for user accounts and service accounts as well.

Resource-based Kerberos constrained delegation requires Windows Server 2012 or above for the servers involved, including at least one 2012 domain controller in each related domain. I am not going to include all of the details in this post, because the technology is well-documented. Read the links at the bottom of the article for all the particulars.

Show me some `Shell

This code for setting up the permissions requires a Windows box with the Windows Server 2012 Active Directory PowerShell RSAT available.

PS C:\> Add-WindowsFeature RSAT-AD-PowerShell

PS C:\> Import-Module ActiveDirectory

PS C:\> Get-Command -ParameterName PrincipalsAllowedToDelegateToAccount

CommandType Name                 ModuleName     
----------- ----                 ----------     
Cmdlet      New-ADComputer       ActiveDirectory
Cmdlet      New-ADServiceAccount ActiveDirectory
Cmdlet      New-ADUser           ActiveDirectory
Cmdlet      Set-ADComputer       ActiveDirectory
Cmdlet      Set-ADServiceAccount ActiveDirectory
Cmdlet      Set-ADUser           ActiveDirectory

Notice that some of the Active Directory cmdlets for Windows Server 2012 and above include a new parameter PrincipalsAllowedToDelegateToAccount. This parameter sets the Active Directory object attribute msDS-AllowedToActOnBehalfOfOtherIdentity. That attribute actually holds an access control list (ACL) determining who has permissions to delegate credentials to ServerC.

# Set up variables for reuse            
$ServerA = $env:COMPUTERNAME            
$ServerB = Get-ADComputer -Identity ServerB            
$ServerC = Get-ADComputer -Identity ServerC            

# Notice the StartName property of the WinRM Service: NT AUTHORITY\NetworkService            
# This looks like the ServerB computer account when accessing other servers over the network.            
Get-WmiObject Win32_Service -Filter 'Name="winrm"' -ComputerName $ServerB.name | fl *

The WinRM service by default runs as the NetworkService account. Therefore, we will allow ServerC to receive the computer object of ServerB for delegation.

# Grant resource-based Kerberos constrained delegation            
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB            
            
# Check the value of the attribute directly            
$x = Get-ADComputer -Identity $ServerC -Properties msDS-AllowedToActOnBehalfOfOtherIdentity            
$x.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access            
            
# Check the value of the attribute indirectly            
Get-ADComputer -Identity $ServerC -Properties PrincipalsAllowedToDelegateToAccount

The output of the ACL Access property shows a simple access control entry (ACE) for ServerB to delegate credentials to ServerC:

ActiveDirectoryRights : GenericAll
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : CONTOSO\ServerB$
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

Here is the one snag. The KDC has a 15 min SPN negative cache. If ServerB has already tried to talk to ServerC, then there is a negative cache entry. You need to clear the cache on ServerB using one of the following techniques:

  1. klist purge -li 0x3e7 (preferred and fastest method)
  2. Wait 15 minutes for the cache to clear automatically.
  3. Reboot ServerB.
Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {            
    klist purge -li 0x3e7            
}

or

Restart-Computer $ServerB.Name -Force -Wait -For WinRM

Once that step is complete we can successfully run code like this from ServerA through ServerB to ServerC:

# Capture a credential            
$cred = Get-Credential Contoso\Alice            
            
# Test kerberos double hop            
Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {            
    Test-Path \\$($using:ServerC.Name)\C$            
    Get-Process lsass -ComputerName $($using:ServerC.Name)            
    Get-EventLog -LogName System -Newest 3 -ComputerName $($using:ServerC.Name)            
}

Note that the $using variable prefix allows ServerB to reference the $ServerC variable that lives in memory on ServerA. This makes the code entirely flexible. Just modify the $ServerB and $ServerC variables above with the computer names you want to use. Read more about $using in about_Remote_Variables.

You may want to allow multiple servers to delegate credentials to ServerC. In that case, set the parameter to an array of computer or user objects like this:

# Set up variables for each server            
$ServerB1 = Get-ADComputer -Identity ServerB1            
$ServerB2 = Get-ADComputer -Identity ServerB2            
$ServerB3 = Get-ADComputer -Identity ServerB3            
$ServerC  = Get-ADComputer -Identity ServerC            
            
# Grant resource-based Kerberos constrained delegation            
Set-ADComputer -Identity $ServerC `
    -PrincipalsAllowedToDelegateToAccount @($ServerB1,$ServerB2,$ServerB3)

According to this whitepaper include the domain controller FQDN in the Server parameter of the Get-ADComputer command to make it work across domains:

# For ServerC in Contoso domain and ServerB in other domain            
$ServerB = Get-ADComputer -Identity ServerB -Server dc1.alpineskihouse.com            
$ServerC = Get-ADComputer -Identity ServerC            
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB

To undo the configuration, simply reset ServerC’s attribute to null.

Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $null

A Practical Example

You have a jump box server that you connect to for daily administration. From that server you access all the other servers in your environment. The jump box server would be ServerB, so all the other servers in your environment (ServerC) would need ServerB allowed. Here is a code sample to query servers from an OU and set them all for resource-based Kerberos constrained delegation:

$ServerB = Get-ADComputer -Identity JumpBox            
$Servers = Get-ADComputer -Filter {Name -ne $ServerB.Name} `
    -SearchBase 'OU=Servers,OU=NA,DC=contoso,DC=com' -SearchScope Subtree            
ForEach ($ServerC in $Servers) {            
    Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB            
}

Summary

Kerberos double hop for PowerShell remoting can now be solved with one simple cmdlet:

$ServerB = Get-ADComputer -Identity ServerB            
$ServerC = Get-ADComputer -Identity ServerC            
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB
# Then on ServerB: KLIST PURGE -LI 0x3e7

The benefits are many:

  • No PowerShell code modification.
  • No more SPNs for constrained delegation!
  • Credentials are not stored on ServerB.
  • Multiple domains and forests supported across trusts.
  • Easier setup and administration.
  • ServerA can now talk to ServerC through ServerB.

Once again the world is a happy place. Now go try it for yourself. Use the comment area below for feedback. Let me know how it goes.

Resource-Based Kerberos Constrained Delegation Links

What’s New in Kerberos Authentication
Resource-based constrained delegation across domains and forest
https://technet.microsoft.com/en-us/library/hh831747.aspx

How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part 1
http://windowsitpro.com/security/how-windows-server-2012-eases-pain-kerberos-constrained-delegation-part-1
“Constrained delegation in Server 2012 introduces the concept of controlling delegation of service tickets using a security descriptor rather than an allow list of SPNs. This change simplifies delegation by enabling the resource to determine which security principals are allowed to request tickets on behalf of another user.”
“Resource-based constrained delegation functions correctly regardless of domain functional level and number of domain controllers (DCs) running a version of Windows Server prior to Server 2012, provided you have at least one Server 2012 DC in the same domain as the front-end server and one Server 2012 DC in the domain hosting the back-end server.”

How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part 2
http://windowsitpro.com/security/how-windows-server-2012-eases-pain-kerberos-constrained-delegation-part-2

Understanding Kerberos Constrained Delegation for Azure Active Directory Application Proxy Deployments with Integrated Windows Authentication
http://aka.ms/kcdpaper

[MS-ADA2]: Active Directory Schema Attributes M
2.210 Attribute msDS-AllowedToActOnBehalfOfOtherIdentity
https://msdn.microsoft.com/en-us/library/hh554126.aspx
“This attribute is used for access checks to determine if a requestor has permission to act on the behalf of other identities to services running as this account.”

[MS-SFU]: Kerberos Protocol Extensions: Service for User and Constrained Delegation Protocol
1.3.2 S4U2proxy
https://msdn.microsoft.com/en-us/library/cc246079.aspx

Resource Based Kerberos Constrained Delegation
https://blog.kloud.com.au/2013/07/11/kerberos-constrained-delegation/

Remote Administration Without Constrained Delegation Using PrincipalsAllowedToDelegateToAccount
https://blogs.msdn.microsoft.com/taylorb/2012/11/06/remote-administration-without-constrained-delegation-using-principalsallowedtodelegatetoaccount/

 

image

When All Else Fails… $using:cred

If you still have no Windows Server 2012 domain controllers in your environment then you can use this technique:

# This works without delegation, passing fresh creds            
# Note $Using:Cred in nested request            
$cred = Get-Credential Contoso\Administrator            
Invoke-Command -ComputerName ServerB -Credential $cred -ScriptBlock {            
    hostname            
    Invoke-Command -ComputerName ServerC -Credential $Using:cred -ScriptBlock {hostname}            
}

This works, because the $using:cred passes a fresh copy of the credential variable into the remoting session without storing it anywhere. You could also swap out the Invoke-Command cmdlets with Enter-PSSession. The only requirement is WMF 3.0 or above on your servers.

Edit 8/31/16: Thanks to fellow PFE Martin Schvartzman for the KLIST PURGE syntax!
Edit 9/26/16: Added a code sample for the $using:cred alternative.
Edit 12/5/16: After much research internally we have concluded that this technique does not support double-hop for WinRM-based commands (Invoke-Command, Enter-PSSession, Get-CimInstance, etc.). I plan to release more details on this later.

Edit 12/13/16: The product group has turned this article into documentation here: https://msdn.microsoft.com/en-us/powershell/scripting/setup/ps-remoting-second-hop. They included some additional links you may want to review.
Edit 4/10/17: Minor tweaks to the JEA and Resource-Based Kerberos Constrained Delegation items in the matrix.

Comments (33)

  1. Wow, great post!
    I’m very happy to have found a new and secure way of resolving this double hop issue!

    Thanks for sharing Ashley!

  2. agressiv says:

    This is great, but the 2012 requirement will limit its practical use at most large shops. 2008R2 is still the common denominator for many. Heck we still have about 50 2008 (R1) servers.

  3. Wes says:

    Hi Ashley,

    Thanks for the very clear step by step article. I did test it with success but it doesn’t seems to work with SharePoint Powershell double hop issue. We are still bound to use CredSSP in this case. Could it be because the credential are passed directly to the MSSQL resource rather than the computer object ?

    Regards.

  4. Wow this is awesome! Thanks for sharing!

  5. suikone says:

    You mentioned that user and service accounts also could be entered for PrincipalsAllowedToDelegateToAccount.
    Unfortunately I couldn’t get it working.
    Computer works just fine, but user does not work.
    I used this command:
    $user2 = Get-ADUser -Identity userA
    Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $user2 -Server DC2012R2

    He sets the value for the Property, but then I get Access Denied again :/

  6. Javier Barrio says:

    That’s incredibly great and I can confirm that it works for ‘standard’ PowerShell cmdlets, but I am finding troubles to invoke SharePoint cmdlets. The Microsoft.SharePoint.PowerShell snapin loads fine inside a ScriptBlock but if I want to execute a basic SharePoint cmdlet like Get-SPFarm it returns error: cannot access local farm.

    Checking SQL Server logs I can see that SQL is receiving a logon request using NT AUTHORITY\ANONYMOUS instead of the real user. It seems that for some reason the snapin is not able to propagate the right user.

    May you be so kind to check this internally to see why it does happen and if there’s a possible solution?

    Cheers.

  7. Hello Javier and Wes,
    Thank you for this feedback. I am not a SharePoint engineer, but I know some. I’ll ask around and let you know what I find out.
    Thanks,
    Ashley
    GoateePFE

    1. Javier Barrio says:

      Hi Ashley,

      Were you able to ping some SP engineer to know why the snapin cannot benefit of this article?

      Cheers.

    2. Javier Barrio says:

      Hi,

      I wouldn’t like to sound like I’m pressing you but couple of weeks without updates on this and it’s a pitty because it looks very promising.

      Where you able to ask SharePoint engineers to get any interesting information?

      Thanks!

      1. Hello Javier,
        Yes, I am asking SharePoint peers for assistance. Still no progress on an answer yet. Thank you for being persistent. The answer may take a while. Thank you for your patience.
        Ashley

        1. Javier Barrio says:

          Hi Ashley,

          Were you and the SP Engineers able to make this work with SharePoint snap-in?

          Cheers!

        2. Wes says:

          Hello,
          Will we have a gift from your SharePoint peers for Christmas regarding this scenario ?
          This issue with SharePoint delegation has been persistent for a while now. My colleagues wants to deny CredSSP functionality because they fear the PTH attack but they didn’t force restricted mode for RDP … (big non sense in my mind but whatever). All in all, this leaves a security hole when deploying SharePoint environments since there is no secured way to connect to it.
          I’d be interested in having MS engineers thoughts.

          Thank you !

          1. Javier Barrio says:

            Still no news from the SharePoint Engineering?

            :__(

  8. Ganapathy says:

    If server b (jump server) & c is in different domain and we will login to server b using one way trust of different domain, in this scenario will this concept work?

  9. Alex says:

    Hi Ashley,
    I have a windows 10 prof Hyper-V with windows server 2012 r2 VMs: Ex1, App1, Dc1. I can ping the host, the 3 VMs and the internet (bing, google). I am getting an error at Invoke-command
    PS C:\> Invoke-Command -ComputerName $ServerB.Name -Credential $cred –ScriptBlock {
    >> Test-Path \\$($using:ServerC.Name)\C$
    >> Get-Process lsass -ComputerName $($using:ServerC.Name)
    >> Get-EventLog -LogName System -Newest 3 -ComputerName $($using:ServerC.Name)
    >> }
    >>
    [DC1] Connecting to remote server DC1 failed with the following error message : WinRM cannot complete the operation.
    Verify that the specified computer name is valid, that the computer is accessible over the network, and that a
    firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM
    firewall exception for public profiles limits access to remote computers within the same local subnet. For more
    information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo : OpenError: (DC1:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken

    1. Anyone knows what type of domain authorization is required to execute the Get-ADComputer and Set-ADComputer? Is it full domain administrator or can it be more granular configured based on the parameter values. For example can a domain be configured that my user is allowed to grant resource-based Kerberos constrained delegation based on the values of -Identity and -PrincipalsAllowedToDelegateToAccount?

      1. Hello Alex,
        Domain Admins is required by default to edit the computer object. However, you can delegate computer account administration to a group at the OU level.
        Thanks,
        Ashley
        GoateePFE

    2. Hello Alex,
      Basic remoting question here. By default remoting should be enabled on 2012 R2. What happens if you run the following command as admin on DC1: enable-psremoting. Does that fix the issue?
      Thanks,
      Ashley
      GoateePFE

      1. AlexA says:

        Same error: WinRMOperationTimeout,PSSessionStateBroken
        PS C:\> get-vm (from Host windows 10)
        Name State CPUUsage(%) MemoryAssigned(M) Uptime Status Version
        —- —– ———– —————– —— —— ——-
        APP1 Running 2 1302 00:28:12.5750000 Operating normally 7.0 (server 2012 R2)
        CLIENT1 Off 0 0 00:00:00 Operating normally 7.0 (windows 10)
        DC1 Running 0 1578 00:29:29.9950000 Operating normally 7.0 (server 2012 R2)
        EX1 Running 0 7616 00:18:46.3740000 Operating normally 7.0 (server 2012 R2)

        (On App1 $serverA):
        $ServerA = $env:COMPUTERNAME
        $ServerB = Get-ADComputer -Identity EX1
        $ServerC = Get-ADComputer -Identity DC1
        Get-WmiObject Win32_Service -Filter ‘Name=”winrm”‘ -ComputerName $ServerB.name | fl *

        (On EX1 $serverB):
        PS C:\> enable-psremoting

        WinRM Quick Configuration
        Running command “Set-WSManQuickConfig” to enable remote management of this computer by using the Windows
        Remote Management (WinRM) service.
        This includes:
        1. Starting or restarting (if already started) the WinRM service
        2. Setting the WinRM service startup type to Automatic
        3. Creating a listener to accept requests on any IP address
        4. Enabling Windows Firewall inbound rule exceptions for WS-Management traffic (for http only).

        Do you want to continue?
        [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”): A
        WinRM is already set up to receive requests on this computer.
        WinRM is already set up for remote management on this computer.

        Confirm
        Are you sure you want to perform this action?
        Performing the operation “Set-PSSessionConfiguration” on target “Name: microsoft.powershell SDDL:
        O:NSG:BAD:P(A;;GA;;;BA)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD). This lets selected users remotely run
        Windows PowerShell commands on this computer.”.
        [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”): A
        PS C:\>
        PS C:\> whoami
        corp\administrator

        (On APP1 $serverA):
        PS C:\> Invoke-Command -ComputerName $ServerB.Name -Credential $cred –ScriptBlock {
        >> Test-Path \\$($using:ServerC.Name)\C$
        >> Get-Process lsass -ComputerName $($using:ServerC.Name)
        >> Get-EventLog -LogName System -Newest 3 -ComputerName $($using:ServerC.Name)
        >> }
        >>
        [EX1] Connecting to remote server EX1 failed with the following error message : WinRM cann
        more information, see the about_Remote_Troubleshooting Help topic.
        + CategoryInfo : OpenError: (EX1:String) [], PSRemotingTransportException
        + FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken
        PS C:\> whoami
        corp\administrator
        PS C:\>

        1. Hello Alex,
          This looks like a VM configuration issue rather than a WinRM issue. The error message you pasted was cut off. Can you paste the entire error message? Make sure the you have basic connectivity, name resolution, and common domain membership between all the VMs first.
          Thanks,
          Ashley

          1. Alex says:

            Hi Ashley,
            What am I missing???
            (On App1 $ServerA)
            PS C:\Users\administrator.CORP> ping -4 DC1
            Pinging DC1.Corp.alexaq8.com [192.168.1.51] with 32 bytes of data:
            Reply from 192.168.1.51: bytes=32 time ping -4 ex1
            Pinging ex1.Corp.alexaq8.com [192.168.1.58] with 32 bytes of data:
            Reply from 192.168.1.58: bytes=32 time ping -4 app1
            Pinging app1.Corp.alexaq8.com [192.168.1.61] with 32 bytes of data:
            Reply from 192.168.1.61: bytes=32 time ping -4 ex1
            Pinging ex1.Corp.alexaq8.com [192.168.1.58] with 32 bytes of data:
            Reply from 192.168.1.58: bytes=32 time=1ms TTL=128

            (On EX1 $ServerC)
            PS C:\Users\administrator.CORP> ping dc1
            Pinging dc1.corp.alexaq8.com [192.168.1.51] with 32 bytes of data:
            Reply from 192.168.1.51: bytes=32 time ping app1 -4
            Pinging app1.Corp.alexaq8.com [192.168.1.61] with 32 bytes of data:
            Reply from 192.168.1.61: bytes=32 time $serverA = $env:ComputerName
            PS C:\Users\administrator.CORP> $ServerB = Get-ADComputer -Identity DC1
            PS C:\Users\administrator.CORP> $ServerC = Get-ADComputer -Identity ex1
            Get-WmiObject Win32_Service -Filter ‘Name=”winrm”‘ -ComputerName $ServerB.name | fl *
            PS C:\Users\administrator.CORP> Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB
            PS C:\Users\administrator.CORP> $x = Get-ADComputer -Identity $ServerC -Properties msDS-AllowedToActOnBehalfOfOtherIdentity
            ….
            PS C:\Users\administrator.CORP> Restart-Computer $ServerB.Name -Force -Wait -For WinRM
            Restart-Computer $ServerB.Name -Force -Wait -For WinRM
            ***above cmdlet hangs after DC1 restarts, with waiting for WinRM to start????

            (On DC1 $ServerB)
            PS C:\Users\Administrator> enable-psremoting
            PS C:\Users\Administrator>
            PS C:\Users\Administrator> winrm quickconfig
            WinRM service is already running on this machine.
            WinRM is already set up for remote management on this computer.

            (On App1 $ServerA)
            Ctrl-C aborted: ‘restart-computer… -For WinRM’

            PS C:\Users\administrator.CORP> Invoke-Command -ComputerName $ServerB.Name -Credential $cred –Script
            Block {
            >> Test-Path \\$($using:ServerC.Name)\C$
            >> Get-Process lsass -ComputerName $($using:ServerC.Name)
            >> Get-EventLog -LogName System -Newest 3 -ComputerName $($using:ServerC.Name)
            >> }
            >>
            [DC1] Connecting to remote server DC1 failed with the following error message : WinRM cannot
            complete the operation. Verify that the specified computer name is valid, that the computer is
            accessible over the network, and that a firewall exception for the WinRM service is enabled and
            allows access from this computer. By default, the WinRM firewall exception for public profiles
            limits access to remote computers within the same local subnet. For more information, see the
            about_Remote_Troubleshooting Help topic.
            + CategoryInfo : OpenError: (DC1:String) [], PSRemotingTransportException
            + FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken

            I really do not understand WinRMOperationTimeout.

            Regards

  10. wasserja says:

    Thanks Ashley for doing the researching and putting this together for the community.

    I attempted to run these commands and received the following error:
    Set-ADComputer : The attribute cannot be modified because it is owned by the system
    At line:1 char:1

    I have a mix of 2008 R2 DC’s and 2012 R2 domain controllers. I then re-ran the commands to get-adcomputer but specified the name of a 2012 R2 domain controller and then it worked.

    Get-ADComputer -identity serverb -server w2k12r2dc

    Thanks again.

  11. a.sarafian says:

    I’m not a domain administrator and through comments here and on twitter you suggested to ask for “delegated authorization”. Also please forgive any wrong terminology used.

    We grouped the ServerB and ServerC under one OU, and we tried to assign “delegated authorization” to my domain account to this specific OU. Then ServerB and ServerC would inherit it. But our IT guys didn’t want to provide access to everything and they tried to restrict the properties I’m allowed to change. The delegated authorization ui wizard offers a per group or per property assignment.

    Since the query “Get-ADComputer -Identity $ServerC -Properties msDS-AllowedToActOnBehalfOfOtherIdentity” targets “msDS-AllowedToActOnBehalfOfOtherIdentity” we tried locating this attribute in the wizard but it was not there. There were many other msDS-* properties though as expected.

    Is my thought correct? Can this work with permission to only one property? If so then what does it mean when it’s not available to select. If not then can you explain the smallest set of properties or group that is required to be assigned in the authorization to my account? Could we actually get a powershell script for this? I believe it would be a nice finishing touch for cases like me that we try to push automation with PowerShell but we are not domain administrators. Since this is an advanced subject even for domain admins, it would help them enable us to further push the agenda.

  12. a.sarafian says:

    Regarding the “When All Else Fails… $using:cred” last section. I’m actually amazed that it works. Its an excellent alternative but the limitation is that it depends on a cmdlet that can be finally driven by a credential. For example like above or first create a session and then use this session as a parameter.

    But my reality and I believe for many others is that we need to solve the “double-hop” issue for code blocks that do an implicit kerberos authentication.

    One example that I had to address with the CredSSP is that when bootstrapping a ServerB from e.g. my ClientA, I need to add a domain user Domain\UserA into the local administrator group of ServerB. With this action, there is an implicit access to the domain controller from ServerB from within a remote session initialized on ClientA with my DOMAIN\myuser account. I do this with cmdlet “Add-GroupMember” from the powershell module “Carbon”.

    Other examples could be when the web requests go through a proxy with windows credential authorization or when trying to access a network path. Both can be circumvented by accessing the remote resource from ClientA and then copying the resource to ServerB.

    Is it possible that there is a similar workaround for the first example?

  13. Emmanuel R says:

    Thanks a lot Ashley for taking the time to write this, it will definitely be helpful!

  14. Dennis B says:

    This does not appear to fix the problem with cross-domain users.

    eg:

    – domainA\user logs into domainA\computerA
    – domainA\user runs $cred = Get-Credential & enters login info for for domainB\user
    – domainA\user runs Set-ADComputer domainA\computerB -PrincipalsAllowedToDelegateToAccount (Get-ADUser -Server domainB -Identity -user)

    Works: Enter-PSSession -computername computerB.domainA
    Does not work: Enter-PSSession -computername computerB.domainA -Credential $cred

  15. Alex Aymonier says:

    Hey Ashley,

    Just setting this up and the example works beautifully using the following:

    Invoke-Command -ComputerName $ps.Name -Credential $cred -ScriptBlock {
    Test-Path \\$($using:dc.Name)\C$
    Get-Process lsass -ComputerName $($using:dc.Name)
    Get-EventLog -LogName System -Newest 3 -ComputerName $($using:dc.Name)
    }

    However if we use:

    Invoke-Command -ComputerName $ps.Name -Credential $cred -ScriptBlock {
    Get-ADUser test.user
    }

    We get the following:

    Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not
    have the Active Directory Web Services running.
    + CategoryInfo : ResourceUnavailable: (test.user:ADUser) [Get-ADUser], ADServerDownException
    + FullyQualifiedErrorId : ActiveDirectoryServer:0,Microsoft.ActiveDirectory.Management.Commands.GetADUser
    + PSComputerName : Server1

    Should this work with ADcmdlets

    Alex

    1. Hello Alex,
      I get the same result. Since releasing this article I have come to learn that the technique does not apply in all cases. You can get it to work without delegation using this alternate method:

      $cred = Get-Credential Contoso\Administrator
      Invoke-Command -ComputerName JumpServer -Credential $cred -ScriptBlock {
      Get-AdUser -Identity danpark -Server DC1 -Credential $using:cred
      }

      Hope this helps,
      Ashley
      GoateePFE

      1. Alex Aymonier says:

        Hi Ashley,

        That works perfectly, thank you.

        Alex

  16. Thankyou says:

    # This works without delegation, passing fresh creds
    # Note $Using:Cred in nested request
    $cred = Get-Credential Contoso\Administrator
    Invoke-Command -ComputerName ServerB -Credential $cred -ScriptBlock {
    hostname
    Invoke-Command -ComputerName ServerC -Credential $Using:cred -ScriptBlock {hostname}
    }

    I love it! Nice and simple!

  17. Robert Smith jr says:

    Hi, we were able to overcome some of the double hop issue when accessing domain based services (AD, SCCM, VMware PowerCli, etc) from a jump host by initializing a new PS-Drive for the service in question and passing the appropriate credential. Example: Admins remote into a stand alone domain joined server and need to use the AD cmdlets (in our case we have a root domain and a child domain with a one way trust, how can we access both from the child domain?). By initializing two separate PsDrives!

    new-psdrive -psprovider ActiveDirectory -Name -root “” -server -cred $cred -scope Global #pass $cred as credential object

    Here’s another example for accessing VMware Powercli:
    Add-PSSnapin VMware.VimAutomation.Core #install PowerCli on Jump Host
    if ($currentuser -eq $null) {$global:currentuser=Get-Credential (whoami)}
    Set-PowerCLIConfiguration -InvalidCertificateAction Ignore
    $viserver=connect-viserver
    write-host “Connected to ” $viserver.Name

  18. Thank you, Ashley, for this helpful post.
    However, I have a question: how many computers can you add to the PrincipalsAllowedToDelegateToAccount attribute?
    I mean, if you have a few hundred or even a few thousand of computers making the second hop to a single central computer, for instance, a deployment server…
    I found this link: https://msdn.microsoft.com/en-us/library/hh554126.aspx
    If I understand well we can add 132 096 entries to this attribute. Is that correct?

    1. Yeah. It can get crazy with thousands of systems. I believe you are reading that correctly for the limit.

Skip to main content