DSCResources/MSFT_ADForestProperties/MSFT_ADForestProperties.psm1
$script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent $script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules' $script:localizationModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'ActiveDirectoryDsc.Common' Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'ActiveDirectoryDsc.Common.psm1') $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_ADForestProperties' $script:psModuleName = 'ActiveDirectory' <# .SYNOPSIS Gets the current state of user principal name and service principal name suffixes in the forest. .PARAMETER Credential The user account credentials to use to perform this task. .PARAMETER ForestName The target Active Directory forest for the change. .PARAMETER ServicePrincipalNameSuffixToAdd The Service Principal Name Suffix(es) to add in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER ServicePrincipalNameSuffixToRemove The Service Principal Name Suffix(es) to remove in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER UserPrincipalNameSuffixToAdd The User Principal Name Suffix(es) to add in the forest. Cannot be used with UserPrincipalNameSuffix. .PARAMETER UserPrincipalNameSuffixToRemove The User Principal Name Suffix(es) to remove in the forest. Cannot be used with UserPrincipalNameSuffix. .NOTES Used Functions: Name | Module ------------------------------|-------------------------- Assert-Module | ActiveDirectoryDsc.Common Get-ADForest | ActiveDirectory Get-ADObject | ActiveDirectory Get-ADRootDSE | ActiveDirectory #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter(Mandatory = $true)] [System.String] $ForestName, [Parameter()] [System.String[]] $ServicePrincipalNameSuffix, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToRemove, [Parameter()] [System.String[]] $UserPrincipalNameSuffix, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToRemove ) Assert-Module -ModuleName $script:psModuleName Write-Verbose -Message ($script:localizedData.GetForest -f $ForestName) $forest = Get-ADForest -Identity $ForestName $configurationNamingContext = (Get-ADRootDSE).configurationNamingContext $identity = "CN=Directory Service,CN=Windows NT,CN=Services,$configurationNamingContext" $tombstoneLifetime = (Get-ADObject -Identity $identity -Partition $configurationNamingContext ` -Properties 'tombstonelifetime').tombstonelifetime if ($PSBoundParameters.ContainsKey('Credential')) { $cimCredential = New-CimCredentialInstance -Credential $Credential } else { $cimCredential = $null } return @{ Credential = $cimCredential ForestName = $forest.Name ServicePrincipalNameSuffix = [System.Array] $forest.SpnSuffixes ServicePrincipalNameSuffixToAdd = [System.Array] $ServicePrincipalNameSuffixToAdd ServicePrincipalNameSuffixToRemove = [System.Array] $ServicePrincipalNameSuffixToRemove TombstoneLifetime = $tombstoneLifetime UserPrincipalNameSuffix = [System.Array] $forest.UpnSuffixes UserPrincipalNameSuffixToAdd = [System.Array] $UserPrincipalNameSuffixToAdd UserPrincipalNameSuffixToRemove = [System.Array] $UserPrincipalNameSuffixToRemove } } <# .SYNOPSIS Tests the current state of user principal name and service principal name suffixes in the forest. .PARAMETER Credential The user account credentials to use to perform this task. .PARAMETER ForestName The target Active Directory forest for the change. .PARAMETER ServicePrincipalNameSuffix The Service Principal Name Suffix(es) to be explicitly defined in the forest and replace existing members. Cannot be used with ServicePrincipalNameSuffixToAdd or ServicePrincipalNameSuffixToRemove. .PARAMETER ServicePrincipalNameSuffixToAdd The Service Principal Name Suffix(es) to add in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER ServicePrincipalNameSuffixToRemove The Service Principal Name Suffix(es) to remove in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER TombstoneLifetime Specifies the AD Tombstone lifetime which determines how long deleted items exist in Active Directory before they are purged. .PARAMETER UserPrincipalNameSuffix The User Principal Name Suffix(es) to be explicitly defined in the forest and replace existing members. Cannot be used with UserPrincipalNameSuffixToAdd or UserPrincipalNameSuffixToRemove. .PARAMETER UserPrincipalNameSuffixToAdd The User Principal Name Suffix(es) to add in the forest. Cannot be used with UserPrincipalNameSuffix. .PARAMETER UserPrincipalNameSuffixToRemove The User Principal Name Suffix(es) to remove in the forest. Cannot be used with UserPrincipalNameSuffix. .NOTES Used Functions: Name | Module ------------------------------|-------------------------- Assert-MemberParameters | ActiveDirectoryDsc.Common Assert-Module | ActiveDirectoryDsc.Common Test-Members | ActiveDirectoryDsc.Common #> function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter(Mandatory = $true)] [System.String] $ForestName, [Parameter()] [System.String[]] $ServicePrincipalNameSuffix, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToRemove, [Parameter()] [System.Int32] $TombstoneLifetime, [Parameter()] [System.String[]] $UserPrincipalNameSuffix, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToRemove ) Assert-Module -ModuleName $script:psModuleName $inDesiredState = $true $targetResource = Get-TargetResource -ForestName $ForestName # Validate parameters before we even attempt to retrieve anything $assertMemberParameters = @{} if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffix') -and -not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffix)) { $assertMemberParameters['Members'] = $ServicePrincipalNameSuffix } if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffixToAdd') -and -not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffixToAdd)) { $assertMemberParameters['MembersToInclude'] = $ServicePrincipalNameSuffixToAdd } if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffixToRemove') -and -not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffixToRemove)) { $assertMemberParameters['MembersToExclude'] = $ServicePrincipalNameSuffixToRemove } Assert-MemberParameters @assertMemberParameters -ErrorAction Stop if (-not ( Test-Members @assertMemberParameters -ExistingMembers ($targetResource.ServicePrincipalNameSuffix -split ',') )) { Write-Verbose -Message ($script:localizedData.ForestSpnSuffixNotInDesiredState -f $ForestName) $inDesiredState = $false } $assertMemberParameters = @{} if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffix') -and -not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffix)) { $assertMemberParameters['Members'] = $UserPrincipalNameSuffix } if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffixToAdd') -and -not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffixToAdd)) { $assertMemberParameters['MembersToInclude'] = $UserPrincipalNameSuffixToAdd } if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffixToRemove') -and -not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffixToRemove)) { $assertMemberParameters['MembersToExclude'] = $UserPrincipalNameSuffixToRemove } Assert-MemberParameters @assertMemberParameters -ErrorAction Stop if (-not ( Test-Members @assertMemberParameters -ExistingMembers ($targetResource.UserPrincipalNameSuffix -split ',') )) { Write-Verbose -Message ($script:localizedData.ForestUpnSuffixNotInDesiredState -f $ForestName) $inDesiredState = $false } if ($PSBoundParameters.ContainsKey('TombstoneLifetime')) { if ($TombstoneLifetime -ne $targetResource.TombstoneLifetime) { Write-Verbose -Message ($script:localizedData.TombstoneLifetimeNotInDesiredState -f $ForestName, $targetResource.TombstoneLifetime, $TombstoneLifetime) $inDesiredState = $false } } return $inDesiredState } <# .SYNOPSIS Sets the user principal name and service principal name suffixes in the forest. .PARAMETER Credential The user account credentials to use to perform this task. .PARAMETER ForestName The target Active Directory forest for the change. .PARAMETER ServicePrincipalNameSuffix The Service Principal Name Suffix(es) to be explicitly defined in the forest and replace existing members. Cannot be used with ServicePrincipalNameSuffixToAdd or ServicePrincipalNameSuffixToRemove. .PARAMETER ServicePrincipalNameSuffixToAdd The Service Principal Name Suffix(es) to add in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER ServicePrincipalNameSuffixToRemove The Service Principal Name Suffix(es) to remove in the forest. Cannot be used with ServicePrincipalNameSuffix. .PARAMETER TombstoneLifetime Specifies the AD Tombstone lifetime which determines how long deleted items exist in Active Directory before they are purged. .PARAMETER UserPrincipalNameSuffix The User Principal Name Suffix(es) to be explicitly defined in the forest and replace existing members. Cannot be used with UserPrincipalNameSuffixToAdd or UserPrincipalNameSuffixToRemove. .PARAMETER UserPrincipalNameSuffixToAdd The User Principal Name Suffix(es) to add in the forest. Cannot be used with UserPrincipalNameSuffix. .PARAMETER UserPrincipalNameSuffixToRemove The User Principal Name Suffix(es) to remove in the forest. Cannot be used with UserPrincipalNameSuffix. .NOTES Used Functions: Name | Module ------------------------------|-------------------------- Assert-Module | ActiveDirectoryDsc.Common Get-ADRootDSE | ActiveDirectory New-InvalidOperationException | ActiveDirectoryDsc.Common Set-ADForest | ActiveDirectory Set-ODObject | ActiveDirectory #> function Set-TargetResource { [CmdletBinding()] param ( [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter(Mandatory = $true)] [System.String] $ForestName, [Parameter()] [System.String[]] $ServicePrincipalNameSuffix, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $ServicePrincipalNameSuffixToRemove, [Parameter()] [System.Int32] $TombstoneLifetime, [Parameter()] [System.String[]] $UserPrincipalNameSuffix, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToAdd, [Parameter()] [System.String[]] $UserPrincipalNameSuffixToRemove ) Assert-Module -ModuleName $script:psModuleName $targetResource = Get-TargetResource -ForestName $ForestName $setADForestParameters = @{} # add ServicePrincipalName parameter if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffix')) { if (-not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffix)) { $setADForestParameters['SpnSuffixes'] = @{ Replace = $($ServicePrincipalNameSuffix) } Write-Verbose -Message ($script:localizedData.ReplaceSpnSuffix -f ($ServicePrincipalNameSuffix -join ', '), $ForestName) } else { $setADForestParameters['SpnSuffixes'] = $null Write-Verbose -Message ($script:localizedData.ClearSpnSuffix -f $ForestName) } } if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffixToAdd') -and -not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffixToAdd)) { $setADForestParameters['SpnSuffixes'] = @{ Add = $($ServicePrincipalNameSuffixToAdd) } Write-Verbose -Message ($script:localizedData.AddSpnSuffix -f ($ServicePrincipalNameSuffixToAdd -join ', '), $ForestName) } if ($PSBoundParameters.ContainsKey('ServicePrincipalNameSuffixToRemove') -and -not [system.string]::IsNullOrEmpty($ServicePrincipalNameSuffixToRemove)) { if ($setADForestParameters['SpnSuffixes']) { $setADForestParameters['SpnSuffixes']['Remove'] = $($ServicePrincipalNameSuffixToRemove) } else { $setADForestParameters['SpnSuffixes'] = @{ Remove = $($ServicePrincipalNameSuffixToRemove) } } Write-Verbose -Message ($script:localizedData.RemoveSpnSuffix -f ($ServicePrincipalNameSuffixToRemove -join ', '), $ForestName) } # add UserPrincipalName parameter if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffix')) { if (-not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffix)) { $setADForestParameters['UpnSuffixes'] = @{ Replace = $($UserPrincipalNameSuffix) } Write-Verbose -Message ($script:localizedData.ReplaceUpnSuffix -f ($UserPrincipalNameSuffix -join ', '), $ForestName) } else { $setADForestParameters['UpnSuffixes'] = $null Write-Verbose -Message ($script:localizedData.ClearUpnSuffix -f $ForestName) } } if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffixToAdd') -and -not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffixToAdd)) { $setADForestParameters['UpnSuffixes'] = @{ Add = $($UserPrincipalNameSuffixToAdd) } Write-Verbose -Message ($script:localizedData.AddUpnSuffix -f ($UserPrincipalNameSuffixToAdd -join ', '), $ForestName) } if ($PSBoundParameters.ContainsKey('UserPrincipalNameSuffixToRemove') -and -not [system.string]::IsNullOrEmpty($UserPrincipalNameSuffixToRemove)) { if ($setADForestParameters['UpnSuffixes']) { $setADForestParameters['UpnSuffixes']['Remove'] = $($UserPrincipalNameSuffixToRemove) } else { $setADForestParameters['UpnSuffixes'] = @{ Remove = $($UserPrincipalNameSuffixToRemove) } } Write-Verbose -Message ($script:localizedData.RemoveUpnSuffix -f ($UserPrincipalNameSuffixToRemove -join ', '), $ForestName) } # Only run Set-ADForest if a value needs updating if ($setADForestParameters.count -gt 0) { if ($PSBoundParameters.ContainsKey('Credential')) { $setADForestParameters['Credential'] = $Credential } $setADForestParameters['Identity'] = $ForestName Set-ADForest @setADForestParameters } if ($PSBoundParameters.ContainsKey('TombstoneLifetime') -and $TombstoneLifetime -ne $targetResource.TombstoneLifetime) { Write-Verbose -Message ($script:localizedData.SetTombstoneLifetime -f $TombstoneLifetime, $ForestName) $configurationNamingContext = (Get-ADRootDSE).configurationNamingContext $identity = "CN=Directory Service,CN=Windows NT,CN=Services,$configurationNamingContext" $setADObjectParameters = @{ Identity = $identity Partition = $configurationNamingContext Replace = @{ tombstonelifetime = $TombstoneLifetime } } if ($PSBoundParameters.ContainsKey('Credential')) { $setADObjectParameters['Credential'] = $Credential } try { Set-ADObject @setADObjectParameters } catch { $errorMessage = ($script:localizedData.SetTombstoneLifetimeError -f $TombstoneLifetime, $ForestName) New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } |