Public/Test-KdsRootKeyPrerequisite.ps1
function Test-KdsRootKeyPrerequisite { <# .SYNOPSIS Diagnoses KDS Root Key creation prerequisites and environment for gMSA support. .DESCRIPTION Checks forest/domain functional level, KdsSvc service, AD schema containers, KDS Root Key presence, and permissions. Outputs a diagnostic object and actionable recommendations for troubleshooting KDS Root Key creation issues. The function performs the following checks: - Forest and Domain functional levels - KdsSvc service status - Presence of required AD schema containers - Existence and validity of KDS Root Key - Required permissions for gMSA operations .EXAMPLE Test-KdsRootKeyPrerequisite -Verbose Runs all checks and outputs a detailed diagnostic report with verbose logging. .EXAMPLE $result = Test-KdsRootKeyPrerequisite $result.ForestMode Shows how to capture and examine specific aspects of the diagnostic report. .EXAMPLE Test-KdsRootKeyPrerequisite | Select-Object -ExpandProperty Recommendations Displays only the recommended actions based on the diagnostic results. .INPUTS None This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject Returns a diagnostic report object containing: - Environment status (Forest/Domain modes) - Service status - Container existence - KDS Root Key status - Actionable recommendations .NOTES Used Functions: Name ║ Module/Namespace ═══════════════════════════════════════════╬══════════════════════════════ Get-ADForest ║ ActiveDirectory Get-ADDomain ║ ActiveDirectory Get-Service ║ Microsoft.PowerShell.Management Get-KdsRootKey ║ ActiveDirectory Write-Verbose ║ Microsoft.PowerShell.Utility Write-Warning ║ Microsoft.PowerShell.Utility Write-Error ║ Microsoft.PowerShell.Utility .NOTES Version: 1.1 DateModified: 22/May/2025 LastModifiedBy: Vicente Rodriguez Eguibar vicente@eguibar.com Eguibar IT http://www.eguibarit.com .LINK https://github.com/vreguibar/EguibarIT/blob/main/Public/Test-KdsRootKeyPrerequisite.ps1 .COMPONENT Active Directory Key Distribution Service Group Managed Service Accounts .ROLE Infrastructure Administrator Domain Administrator .FUNCTIONALITY Diagnostics Security Prerequisite Validation #> [CmdletBinding()] [OutputType([PSCustomObject])] param () Begin { Set-StrictMode -Version Latest if ($null -ne $Variables -and $null -ne $Variables.Header) { $txt = ($Variables.Header -f (Get-Date).ToString('dd/MMM/yyyy'), $MyInvocation.Mycommand, (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False)) Write-Verbose -Message $txt } #end If ############################## # Module imports Import-Module -Name ActiveDirectory -ErrorAction Stop ############################## # Variables Definition [string]$ForestMode = '' [string]$DomainMode = '' [string]$KdsServiceStatus = '' [bool]$KdsContainerExists = $false [bool]$MasterRootKeysExists = $false [bool]$KdsRootKeyExists = $false [string]$KdsRootKeyId = '' [string]$PdcEmulator = '' [string]$CurrentComputer = $env:COMPUTERNAME [string]$ConfigNC = '' [string]$Recommendation = '' [string]$ErrorMessage = '' } #end Begin Process { try { # Check forest and domain functional level $Forest = Get-ADForest $Domain = Get-ADDomain $ForestMode = $Forest.ForestMode.ToString() $DomainMode = $Domain.DomainMode.ToString() $PdcEmulator = $Domain.PDCEmulator Write-Verbose -Message ('ForestMode: {0}, DomainMode: {1}' -f $ForestMode, $DomainMode) # Check KdsSvc service try { $KdsService = Get-Service -Name 'KdsSvc' -ErrorAction Stop $KdsServiceStatus = $KdsService.Status.ToString() } catch { $KdsServiceStatus = 'NotFound' Write-Warning -Message 'KdsSvc service not found.' } Write-Verbose -Message ('KdsSvc status: {0}' -f $KdsServiceStatus) # Check AD schema containers $ConfigNC = ([ADSI]'LDAP://RootDSE').configurationNamingContext $GkdsPath = 'LDAP://CN=Group Key Distribution Service,CN=Services,' + $ConfigNC $MrkPath = 'LDAP://CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,' + $ConfigNC try { $Gkds = [ADSI]$GkdsPath $null = $Gkds.distinguishedName $KdsContainerExists = $true } catch { $KdsContainerExists = $false Write-Warning -Message 'Group Key Distribution Service container missing.' } try { $Mrk = [ADSI]$MrkPath $null = $Mrk.distinguishedName $MasterRootKeysExists = $true } catch { $MasterRootKeysExists = $false Write-Warning -Message 'Master Root Keys container missing.' } # Check for KDS Root Key try { $KdsKey = Get-KdsRootKey -ErrorAction Stop if ($KdsKey) { $KdsRootKeyExists = $true $KdsRootKeyId = $KdsKey.KeyId.ToString() } } catch { $KdsRootKeyExists = $false } } catch { $ErrorMessage = $_.Exception.Message Write-Error -Message ('Error during KDS prerequisite check: {0}' -f $ErrorMessage) } # Recommendations if ($ForestMode -notlike '*2012*' -and $ForestMode -notlike '*2016*' -and $ForestMode -notlike '*2019*' -and $ForestMode -notlike '*2022*' -and $ForestMode -notlike '*2025*') { $Recommendation += 'Forest functional level must be at least Windows Server 2012. ' } if ($DomainMode -notlike '*2012*' -and $DomainMode -notlike '*2016*' -and $DomainMode -notlike '*2019*' -and $DomainMode -notlike '*2022*' -and $DomainMode -notlike '*2025*') { $Recommendation += 'Domain functional level must be at least Windows Server 2012. ' } if ($KdsServiceStatus -ne 'Running') { $Recommendation += 'KdsSvc service must be running. ' } if (-not $KdsContainerExists) { $Recommendation += 'Group Key Distribution Service container missing in AD schema. ' } if (-not $MasterRootKeysExists) { $Recommendation += 'Master Root Keys container missing in AD schema. ' } if (-not $KdsRootKeyExists) { $Recommendation += 'No KDS Root Key found. Try creating with Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)). ' } if ($ErrorMessage) { $Recommendation += 'Error encountered: ' + $ErrorMessage } if ($Recommendation -eq '') { $Recommendation = 'All prerequisites appear satisfied. If Add-KdsRootKey still fails, check event logs and consider AD schema health.' } # Output diagnostic object [PSCustomObject]@{ ForestMode = $ForestMode DomainMode = $DomainMode KdsServiceStatus = $KdsServiceStatus KdsContainerExists = $KdsContainerExists MasterRootKeysExists = $MasterRootKeysExists KdsRootKeyExists = $KdsRootKeyExists KdsRootKeyId = $KdsRootKeyId PdcEmulator = $PdcEmulator CurrentComputer = $CurrentComputer Recommendation = $Recommendation ErrorMessage = $ErrorMessage } } #end Process End { if ($null -ne $Variables -and $null -ne $Variables.Footer) { $txt = ($Variables.Footer -f $MyInvocation.InvocationName, 'KDS Root Key prerequisite diagnostics.') Write-Verbose -Message $txt } #end If } #end End } #end Function Test-KdsRootKeyPrerequisites |