Set-KCD; configuring Kerberos Constrained Delegation (KCD)


In June I posted an article called Configuring Kerberos Constrained Delegation for Hyper-V Management. I covered the concept of Kerberos delegation and evolution into constrained delegation. Obviously, the article was mainly focused on configuring constrained delegation for Hyper-V management in order to be able to manage Hyper-V in a remote fashion. I ended the article with a PowerShell script called Set-KCD.ps1 and Active Directory cmdlet to configure KCD and verify successful delegation.

I primarily use PowerShell for management and therefore use my own scripts. Using Set-KCD worked well but it lacked certain capabilities which resulted in performing additional steps from the PowerShell command line. Like I mentioned in the article, it was nothing fancy or advanced but it worked in its limited way.

My environment is being reinstalled from time to time. This time it was because of the availability of the release of Windows Server 2012. Sometimes, if possible, I use upgrades. But upgrade was not possible so I reinstalled the environment. I could have upgraded Active Directory but a reinstallation and reconfiguration was actually even faster in my simple environment.

So I needed to configure KCD for my hosts and noticed this script could be improved. I rewrote the script such that it would be much easier to use. For example using a distinguished name for the Active Directory computer object is not intuitive and also requires additional Active Directory cmdlets to find the object path. The computer object can be located anywhere in Active Directory and will usually not exist in the Computers container.

The parameter names for the computers where also not intuitive. The computer you configure to be trusted for delegation was called ‘AdDN’ (the Active Directory Distinguished Name) and the computer you specify to trusted delegation to was called HostFQDN. So I changed this into TrustedComputer and TrustingComputer respectively. The thought was this: you configure the computer object in Active Directory to be trusted for delegation of your credentials to a specific computer for a specific service type. So TrustedComputer is self explanatory here. The computer you specify to allow delegation to for a specific service type is basically the computer that trusts the TrustedComputer for delegation. Although the graphical tools in Active Directory don’t use these terms, I think it is the easiest to understand using these terms when configuring KCD. A small change has been made to the service parameter which is now called ServiceType since this is what it really refers to.

I removed the requirement for fully qualified names. You must be logged on as domain administrator so I get the domain name from the logon session. The result is that the command has become much simpler and easier to understand. Referring to the picture in the previous post, when configuring KCD for vmhost1 to be trusted for CIFS to vmhost2, the command looks like this:


./Set-KCD –TrustedComputer vmhost1 –TrustingComputer vmhost2 –ServiceType CIFS –Add


or just type:

./Set-KCD vmhost1 vmhost2 CIFS


This is much simpler compared to the old command syntax:

./Set-KCD –AdDN “cn=vmhost1,cn=computers,dc=contoso,dc=com” –HostFQDN –Service CIFS –Add


Finally, I also wanted to be able to configure delegation records for multiple computer objects in one step and to be able to verify the settings so I added the option to import the settings from a file.

The following switches are available:

  • -Add
  • -Clear
  • -Import
  • -List
  • -ListFromFile
  • -Remove
  • -Replace

I will not go into the details of each. Because of the built-in help of the script you can get the syntax, examples or full description using ‘help ./Set-KCD’, ‘help ./Set-KCD' –examples’ or ‘help ./Set-KCD –full’.



There are four new switches; –Clear, –Import, –List, –ListIFromFile.

Clear will simply clear all delegation records of the TrustedComputer.

List displays the delegation records currently configured for the TrustedComputer.

ListFromFile displays the delegation records for all TrustedComputer entries in the File.

Import enables you to configure delegation records for multiple trusted computers at once. This is one I use for my environment to configure KCD using a configuration file. The –File property lets you specify a path to a CSV file containing the records for the TrustedComputer, TrustingComputer and ServiceType. The format of the file is documented in the help and a sample file is included in the Set-KCD zip file.

Below is the updated script. It also contains some basic error handling but it won’t check your privileges.

Code Snippet

  1. #######################################################
  2. ##
  3. ## Set-KCD.ps1, v1.2, 2012
  4. ##
  5. ## Created by Matthijs ten Seldam, Microsoft
  6. ##
  7. #######################################################
  9. <#
  11. Configures Kerberos Constrained Delegation (KCD) on a single computer object or multiple computer objects in Active Directory.
  14. Set-KCD supports adding, replacing, removing, clearing and listing of delegation records for a specified computer object or multiple computer objects in Active Directory.
  16. .PARAMETER TrustedComputer
  17. The name of the computer object in Active Directory trusted for delegation to a specific service type.
  19. .PARAMETER TrustingComputer
  20. The name of the computer to delegate authentication to. This is the computer that will accept your credentials on behalf of the TrustedComputer.
  22. .PARAMETER ServiceType
  23. The name of the ServiceType to delegate.
  25. .PARAMETER Add
  26. Switch to specify to add delegation records.
  28. .PARAMETER Clear
  29. Switch to specify to clear delegation records.
  31. .PARAMETER File
  32. The name of a CSV file containing entries for the Trusted and Trusting computers and the ServiceType.
  34. .PARAMETER Import
  35. Switch to specify to import delegation records.
  37. .PARAMETER List
  38. Switch to list current delegation settings for the specified TrustedComputer.
  41. Switch to list current delegation settings for the TrustedComputer entries spcified in the File.
  43. .PARAMETER Remove
  44. Switch to specify to remove delegation records.
  46. .PARAMETER Replace
  47. Switch to specify to replace delegation records.
  49. .EXAMPLE
  50. Set-KCD -TrustedComputer vmhost1 -TrustingComputer vmhost2 -ServiceType cifs -Add
  52. This command adds the CIFS ServiceType type to the computer object vmhost1 for computer vmhost2 to trust vmhost1 for delegation to vmhost2 for this ServiceType.
  54. .EXAMPLE
  55. Set-KCD.ps1 -TrustedComputer vmhost2 -TrustingComputer vmhost3 -ServiceType "Microsoft Virtual System Migration ServiceType" -Add
  57. This command adds the "Microsoft Virtual System Migration ServiceType" type to the computer object vmhost2 for computer vmhost3 to trust vmhost2 for delegation to vmhost3 for this ServiceType.
  59. .EXAMPLE
  60. Set-KCD -TrustedComputer vmhost1 -TrustingComputer vmhost2 -ServiceType cifs -Replace
  62. This command replaces ALL delegation properties with the specified property set (vmhost2/cifs). Any existing properties will be removed.
  64. .EXAMPLE
  65. Set-KCD -TrustedComputer vmhost1 -TrustingComputer vmhost2 -ServiceType cifs -Remove
  67. This command removes the specified delegation properties for vmhost2 and cifs.
  69. .EXAMPLE
  70. Set-KCD -TrustedComputer vmhost3 -Clear
  72. This command clears ALL property sets currently specified for delegation.
  74. .EXAMPLE
  75. Set-KCD -TrustedComputer vmhost1 -List
  77. This command lists the available property sets (service type | computer name) on the object of computer vmhost1 (if anything has been configured).
  79. .EXAMPLE
  80. Set-KCD -File .\ConfigFile.csv -ListFromFile
  82. This command uses the TrustedComputer entries in the File to list the currently configured delegation records.
  84. .EXAMPLE
  85. Set-KCD -File .\ConfigFile.csv -Import
  87. This command uses the contents in the CSV File to configure the TrustedComputer with delegation records for the TrustingComputer and ServiceType.
  88. See below example for a correctly formatted file:
  90. TrustedComputer,TrustingComputer,ServiceType
  91. vmhost1,fhost1,CIFS
  92. vmhost1,vmhost2,Microsoft Virtual System Migration Service
  93. vmhost1,vmhost2,CIFS
  94. vmhost2,vmhost1,Microsoft Virtual System Migration Service
  95. vmhost2,vmhost1,CIFS
  97. .INPUTS
  98. None
  100. .OUTPUTS
  101. None
  103. .NOTES
  104. This script must be run using domain administrator credentials.
  105. The script adds both entries for the target computer; unqualified and fully qualified computer names.
  106. The script uses the UserDnsDomain environment variable to construct the fully qualified domain name of the TrustingComputer name.
  108. .LINK
  110. #>
  112. [CmdletBinding(DefaultParameterSetName="Add")]
  113. param(
  114.     [Parameter(Mandatory=$true, Position=0, ParameterSetName="Add")]
  115.     [Parameter(Mandatory=$true, Position=0, ParameterSetName="Clear")]
  116.     [Parameter(Mandatory=$true, Position=0, ParameterSetName="List")]
  117.     [Parameter(Mandatory=$true, Position=0, ParameterSetName="Remove")]
  118.     [Parameter(Mandatory=$true, Position=0, ParameterSetName="Replace")]
  119.     [string] $TrustedComputer,
  120.     [Parameter(Mandatory=$true, Position=1, ParameterSetName="Add")]
  121.     [Parameter(Mandatory=$true, Position=1, ParameterSetName="Replace")]
  122.     [Parameter(Mandatory=$true, Position=1, ParameterSetName="Remove")]
  123.     [string] $TrustingComputer,
  124.     [Parameter(Mandatory=$true, Position=2, ParameterSetName="Add")]
  125.     [Parameter(Mandatory=$true, Position=2, ParameterSetName="Replace")]
  126.     [Parameter(Mandatory=$true, Position=2, ParameterSetName="Remove")]
  127.     [string]$ServiceType,
  128.     [Parameter(Mandatory=$false, ParameterSetName="Add")]
  129.     [switch]$Add,
  130.     [Parameter(Mandatory=$true, ParameterSetName="Clear")]
  131.     [switch]$Clear,
  132.     [Parameter (Mandatory=$true, ParameterSetName="Import")]
  133.     [Parameter (Mandatory=$true, ParameterSetName="ListFromFile")]
  134.     [string]$File,
  135.     [Parameter (Mandatory=$true, ParameterSetName="Import")]
  136.     [switch]$Import,
  137.     [Parameter(Mandatory=$true, ParameterSetName="List")]
  138.     [switch] $List,
  139.     [Parameter(Mandatory=$true, ParameterSetName="ListFromFile")]
  140.     [switch] $ListFromFile,
  141.     [Parameter(Mandatory=$true, ParameterSetName="Remove")]
  142.     [switch] $Remove,
  143.     [Parameter(Mandatory=$true, ParameterSetName="Replace")]
  144.     [switch] $Replace
  145.     )
  147. Set-StrictMode -Version Latest
  149. If ($PSCmdlet.ParameterSetName -ne "Import")
  150. {
  151.     If ($TrustedComputer.Contains("."))
  152.     {
  153.         $TrustedComputer=$TrustedComputer.Remove($TrustedComputer.IndexOf("."))
  154.     }
  155. }
  158. Function Get-Delegation()
  159. {
  160.     try
  161.     {
  162.         $AdObject = Get-AdComputer $TrustedComputer -Properties msDS-AllowedToDelegateTo | Select-Object -ExpandProperty msDS-AllowedToDelegateTo
  163.         If ($AdObject -ne $null)
  164.         {
  165.             Write-Host `n"Computer name $TrustedComputer is trusted for delegation for the following service(s) to computer(s):"
  166.             Write-Host "--------------------------------------------------------------------------------------------"`n
  167.             $AdObject | Sort-Object
  168.             Write-Host `n"--------------------------------------------------------------------------------------------"`n
  169.         }
  170.         else
  171.         {
  172.             Write-Host `n"No delegation has been configured for computer $TrustedComputer."`n
  173.         }
  174.     }
  175.     Catch
  176.     {
  177.         Write-Host `n"An error occurred searching for Computer name $TrustedComputer in Active Directory!"`n
  178.     }
  179. }
  182. switch($PSCmdlet.ParameterSetName)
  183. {
  184.     {($_ -eq "Add") -or ($_ -eq "Replace") -or ($_ -eq "Remove")}
  185.     {
  186.         If ($TrustingComputer.Contains("."))
  187.         {
  188.             $TrustingComputer=$TrustingComputer.Remove($TrustingComputer.IndexOf("."))
  189.         }
  190.         try
  191.         {
  192.             $ParamHash=@{$PSCmdlet.ParameterSetName=@{"msDS-AllowedToDelegateTo"="$ServiceType/$TrustingComputer","$ServiceType/$TrustingComputer.$env:UserDnsDomain"}}
  193.             Get-ADComputer $TrustedComputer | Set-ADObject @ParamHash
  194.             Get-Delegation
  195.         }
  196.         Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
  197.         {
  198.             Write-Host "`nThe Object for computer $TrustedComputer could not be found in Active Directory.`n"
  199.         }
  200.     }
  202.     "Clear"
  203.     {
  204.         Get-ADComputer $TrustedComputer | Set-ADObject -Clear msDS-AllowedToDelegateTo
  205.         Get-Delegation
  206.     }
  208.     "Import"
  209.     {
  210.         If ($File -ne $null)
  211.         {
  212.             try
  213.             {
  214.                 $Records=Import-Csv $File
  215.             }
  216.             Catch
  217.             {
  218.                 Write-Host `n"$File file not found!`n"
  219.                 exit
  220.             }
  222.             foreach($Item in $Records)
  223.             {
  224.                 $TrustedComputer=$Item.TrustedComputer
  225.                 $TrustingComputer=$Item.TrustingComputer
  226.                 $ServiceType=$Item.ServiceType
  228.                 Get-ADComputer $TrustedComputer | Set-ADObject -Add @{"msDS-AllowedToDelegateTo"="$ServiceType/$TrustingComputer","$ServiceType/$TrustingComputer.$env:UserDnsDomain"}
  229.                 Write-Host "--------------------------------------------------------------------------------------------"`n
  230.                 Write-Host "Added $ServiceType/$TrustingComputer,$ServiceType/$TrustingComputer.$env:UserDnsDomain to $TrustedComputer."`n
  231.             }
  232.         }
  233.     }
  235.     "List"
  236.     {
  237.         Get-Delegation
  238.     }
  240.     "ListFromFile"
  241.     {
  242.         If ($File -ne $null)
  243.         {
  244.             try
  245.             {
  246.                 $Records=Import-Csv $File | Select-Object -Property TrustedComputer -Unique
  247.             }
  248.             Catch
  249.             {
  250.                 Write-Host `n"$File file not found!`n"
  251.                 exit
  252.             }
  254.             foreach($Item in $Records)
  255.             {
  256.                 $TrustedComputer=$Item.TrustedComputer
  257.                 Get-Delegation
  258.             }
  259.         }
  261.         else
  262.         {
  263.             Get-Delegation
  264.         }
  265.     }
  266. }


This is for reference only. You can download the script and sample configuration file here.