From 66b9e6e7a9c2b77184f9a9dc5b8b89409b75a94a Mon Sep 17 00:00:00 2001 From: Chris Hill <53898223+Borgquite@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:26:44 +0000 Subject: [PATCH] ADDomain: Add DomainType support (#705) - ADDomain - Added support for creating a Tree domain via the DomainType field (issue #689, issue #692). --- CHANGELOG.md | 7 ++ .../MSFT_ADDomain/MSFT_ADDomain.psm1 | 36 +++++++++- .../MSFT_ADDomain/MSFT_ADDomain.schema.mof | 1 + .../en-US/about_ADDomain.help.txt | 53 +++++++++++++++ .../2-ADDomain_NewChildDomain_Config.ps1 | 1 + .../3-ADDomain_NewDomainTree_Config.ps1 | 67 +++++++++++++++++++ tests/Unit/MSFT_ADDomain.Tests.ps1 | 7 +- 7 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 source/Examples/Resources/ADDomain/3-ADDomain_NewDomainTree_Config.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index fb27e28d2..17e6040e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md) ## [Unreleased] +### Added + +- ADDomain + - Added support for creating a Tree domain via the DomainType field + ([issue #689](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/689)) + ([issue #692](https://github.com/dsccommunity/ActiveDirectoryDsc/issues/692)). + ### Fixed - Move test pipeline to Windows PowerShell. The hosted agent was updated diff --git a/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.psm1 b/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.psm1 index 348748928..7e17125c1 100644 --- a/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.psm1 +++ b/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.psm1 @@ -30,6 +30,11 @@ $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' .PARAMETER ParentDomainName Fully qualified domain name (FQDN) of the parent domain. + .PARAMETER DomainType + When installing a new domain, specifies whether it is a new domain tree in an existing forest + ('TreeDomain'), or a child of an existing domain ('ChildDomain'). Only used when installing a + new domain. Default value is 'ChildDomain'. + .NOTES Used Functions: Name | Module @@ -62,7 +67,12 @@ function Get-TargetResource [Parameter()] [ValidateNotNullOrEmpty()] [System.String] - $ParentDomainName + $ParentDomainName, + + [Parameter()] + [ValidateSet('ChildDomain', 'TreeDomain')] + [System.String] + $DomainType = 'ChildDomain' ) Assert-Module -ModuleName 'ADDSDeployment' -ImportModule @@ -126,6 +136,7 @@ function Get-TargetResource ParentDomainName = $domain.ParentDomain DomainNetBiosName = $domain.NetBIOSName DnsDelegationCredential = $null + DomainType = $DomainType DatabasePath = $serviceNTDS.'DSA Working Directory' LogPath = $serviceNTDS.'Database log files path' SysvolPath = $serviceNETLOGON.SysVol -replace '\\sysvol$', '' @@ -145,6 +156,7 @@ function Get-TargetResource ParentDomainName = $ParentDomainName DomainNetBiosName = $null DnsDelegationCredential = $null + DomainType = $DomainType DatabasePath = $null LogPath = $null SysvolPath = $null @@ -186,6 +198,11 @@ function Get-TargetResource .PARAMETER DnsDelegationCredential Credential used for creating DNS delegation. + .PARAMETER DomainType + When installing a new domain, specifies whether it is a new domain tree in an existing forest + ('TreeDomain'), or a child of an existing domain ('ChildDomain'). Only used when installing a + new domain. Default value is 'ChildDomain'. + .PARAMETER DatabasePath Path to a directory that contains the domain database. @@ -239,6 +256,11 @@ function Test-TargetResource [System.Management.Automation.PSCredential] $DnsDelegationCredential, + [Parameter()] + [ValidateSet('ChildDomain', 'TreeDomain')] + [System.String] + $DomainType = 'ChildDomain', + [Parameter()] [ValidateNotNullOrEmpty()] [System.String] @@ -327,6 +349,11 @@ function Test-TargetResource .PARAMETER DnsDelegationCredential Credential used for creating DNS delegation. + .PARAMETER DomainType + When installing a new domain, specifies whether it is a new domain tree in an existing forest + ('TreeDomain'), or a child of an existing domain ('ChildDomain'). Only used when installing a + new domain. Default value is 'ChildDomain'. + .PARAMETER DatabasePath Path to a directory that contains the domain database. @@ -387,6 +414,11 @@ function Set-TargetResource [System.Management.Automation.PSCredential] $DnsDelegationCredential, + [Parameter()] + [ValidateSet('ChildDomain', 'TreeDomain')] + [System.String] + $DomainType = 'ChildDomain', + [Parameter()] [ValidateNotNullOrEmpty()] [System.String] @@ -474,7 +506,7 @@ function Set-TargetResource $installADDSParameters['Credential'] = $Credential $installADDSParameters['NewDomainName'] = $DomainName $installADDSParameters['ParentDomainName'] = $ParentDomainName - $installADDSParameters['DomainType'] = 'ChildDomain' + $installADDSParameters['DomainType'] = $DomainType if ($PSBoundParameters.ContainsKey('DomainNetBiosName')) { diff --git a/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.schema.mof b/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.schema.mof index 542c9fe6c..5667094be 100644 --- a/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.schema.mof +++ b/source/DSCResources/MSFT_ADDomain/MSFT_ADDomain.schema.mof @@ -7,6 +7,7 @@ class MSFT_ADDomain : OMI_BaseResource [Write, Description("Fully qualified domain name (FQDN) of the parent domain.")] String ParentDomainName; [Write, Description("NetBIOS name for the new domain.")] String DomainNetBiosName; [Write, Description("Credential used for creating DNS delegation."), EmbeddedInstance("MSFT_Credential")] String DnsDelegationCredential; + [Write, Description("When installing a new domain, specifies whether it is a new domain tree in an existing forest ('TreeDomain'), or a child of an existing domain ('ChildDomain'). Only used when installing a new domain. Default value is 'ChildDomain'."), ValueMap{"ChildDomain", "TreeDomain"}, Values{"ChildDomain", "TreeDomain"}] String DomainType; [Write, Description("Path to a directory that contains the domain database.")] String DatabasePath; [Write, Description("Path to a directory for the log file that will be written.")] String LogPath; [Write, Description("Path to a directory where the Sysvol file will be written.")] String SysvolPath; diff --git a/source/DSCResources/MSFT_ADDomain/en-US/about_ADDomain.help.txt b/source/DSCResources/MSFT_ADDomain/en-US/about_ADDomain.help.txt index acf51880c..56ccc5767 100644 --- a/source/DSCResources/MSFT_ADDomain/en-US/about_ADDomain.help.txt +++ b/source/DSCResources/MSFT_ADDomain/en-US/about_ADDomain.help.txt @@ -32,6 +32,11 @@ Write - PSCredential Credential used for creating DNS delegation. +.PARAMETER DomainType + Write - String + Allowed values: ChildDomain, TreeDomain + When installing a new domain, specifies whether it is a new domain tree in an existing forest ('TreeDomain'), or a child of an existing domain ('ChildDomain'). Only used when installing a new domain. Default value is 'ChildDomain'. + .PARAMETER DatabasePath Write - String Path to a directory that contains the domain database. @@ -155,10 +160,58 @@ Configuration ADDomain_NewChildDomain_Config DomainName = 'child' Credential = $Credential SafemodeAdministratorPassword = $SafeModePassword + DomainType = 'ChildDomain' DomainMode = 'Win2012R2' ParentDomainName = 'contoso.com' } } } +.EXAMPLE 3 + +This configuration will create a new domain tree in an existing forest with +a Domain Functional Level of Windows Server 2012R2. + +Configuration ADDomain_NewDomainTree_Config +{ + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SafeModePassword + ) + Import-DscResource -ModuleName PSDesiredStateConfiguration + Import-DscResource -ModuleName ActiveDirectoryDsc + + node 'localhost' + { + WindowsFeature 'ADDS' + { + Name = 'AD-Domain-Services' + Ensure = 'Present' + } + + WindowsFeature 'RSAT' + { + Name = 'RSAT-AD-PowerShell' + Ensure = 'Present' + } + + ADDomain 'fabrikam.com' + { + DomainName = 'fabrikam.com' + Credential = $Credential + SafemodeAdministratorPassword = $SafeModePassword + DomainType = 'TreeDomain' + DomainMode = 'Win2012R2' + ParentDomainName = 'contoso.com' + } + } +} diff --git a/source/Examples/Resources/ADDomain/2-ADDomain_NewChildDomain_Config.ps1 b/source/Examples/Resources/ADDomain/2-ADDomain_NewChildDomain_Config.ps1 index a656e75ad..d6301f242 100644 --- a/source/Examples/Resources/ADDomain/2-ADDomain_NewChildDomain_Config.ps1 +++ b/source/Examples/Resources/ADDomain/2-ADDomain_NewChildDomain_Config.ps1 @@ -59,6 +59,7 @@ Configuration ADDomain_NewChildDomain_Config DomainName = 'child' Credential = $Credential SafemodeAdministratorPassword = $SafeModePassword + DomainType = 'ChildDomain' DomainMode = 'WinThreshold' ParentDomainName = 'contoso.com' } diff --git a/source/Examples/Resources/ADDomain/3-ADDomain_NewDomainTree_Config.ps1 b/source/Examples/Resources/ADDomain/3-ADDomain_NewDomainTree_Config.ps1 new file mode 100644 index 000000000..32df945e6 --- /dev/null +++ b/source/Examples/Resources/ADDomain/3-ADDomain_NewDomainTree_Config.ps1 @@ -0,0 +1,67 @@ +<#PSScriptInfo +.VERSION 1.0.1 +.GUID 77c6a983-7bb0-4457-88e2-3e4f36727748 +.AUTHOR DSC Community +.COMPANYNAME DSC Community +.COPYRIGHT DSC Community contributors. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/dsccommunity/ActiveDirectoryDsc/blob/main/LICENSE +.PROJECTURI https://github.com/dsccommunity/ActiveDirectoryDsc +.ICONURI https://dsccommunity.org/images/DSC_Logo_300p.png +.RELEASENOTES +Updated author, copyright notice, and URLs. + +#> + +#Requires -Module ActiveDirectoryDsc + +<# + .DESCRIPTION + This configuration will create a new domain tree in an existing forest with + a Domain Functional Level of Windows Server 2016 (WinThreshold). + The credential parameter must contain the domain qualified credentials of a + user in the forest who has permissions to create a new domain tree. +#> +Configuration ADDomain_NewDomainTree_Config +{ + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SafeModePassword + ) + + Import-DscResource -ModuleName PSDesiredStateConfiguration + Import-DscResource -ModuleName ActiveDirectoryDsc + + node 'localhost' + { + WindowsFeature 'ADDS' + { + Name = 'AD-Domain-Services' + Ensure = 'Present' + } + + WindowsFeature 'RSAT' + { + Name = 'RSAT-AD-PowerShell' + Ensure = 'Present' + } + + ADDomain 'fabrikam.com' + { + DomainName = 'fabrikam.com' + Credential = $Credential + SafemodeAdministratorPassword = $SafeModePassword + DomainType = 'TreeDomain' + DomainMode = 'WinThreshold' + ParentDomainName = 'contoso.com' + } + } +} diff --git a/tests/Unit/MSFT_ADDomain.Tests.ps1 b/tests/Unit/MSFT_ADDomain.Tests.ps1 index 35ef481a5..8670f3241 100644 --- a/tests/Unit/MSFT_ADDomain.Tests.ps1 +++ b/tests/Unit/MSFT_ADDomain.Tests.ps1 @@ -44,6 +44,7 @@ try $mockDnsRoot = $mockDomainName $mockParentDomainName = '' $mockDomainFQDN = $mockDomainName + $mockDomainType = 'ChildDomain' $mockNTDSPath = 'C:\Windows\NTDS' $mockSysVolPath = 'C:\Windows\SysVol' $mockDomainSysVolPath = Join-Path -Path $mockSysVolPath -ChildPath $mockDomainName @@ -67,6 +68,7 @@ try ParentDomainName = $mockParentDomainName DomainNetBiosName = $null DnsDelegationCredential = $null + DomainType = $mockDomainType DatabasePath = $null LogPath = $null SysvolPath = $null @@ -84,6 +86,7 @@ try ParentDomainName = $mockParentDomainName DomainNetBiosName = $mockNetBiosName DnsDelegationCredential = $null + DomainType = $mockDomainType DatabasePath = $mockNTDSPath LogPath = $mockNTDSPath SysvolPath = $mockSysVolPath @@ -265,6 +268,7 @@ try Describe 'ADDomain\Set-TargetResource' { $mockDomainName = 'present.com' $mockParentDomainName = 'parent.com' + $mockDomainType = 'ChildDomain' $mockDomainNetBIOSNameName = 'PRESENT' $mockDomainForestMode = 'WinThreshold' $mockPath = 'TestPath' @@ -283,6 +287,7 @@ try ParentDomainName = $mockParentDomainName Credential = $mockAdministratorCredential SafeModeAdministratorPassword = $mockSafemodeCredential + DomainType = $mockDomainType } Mock -CommandName Get-TargetResource -MockWith { return $mockADDomainAbsent } @@ -385,7 +390,7 @@ try Set-TargetResource @setTargetResourceDomainParams Assert-MockCalled -CommandName Install-ADDSDomain ` - -ParameterFilter { $DomainType -eq 'ChildDomain' } + -ParameterFilter { $DomainType -eq $mockDomainType } } It 'Calls "Install-ADDSDomain" with "SafeModeAdministratorPassword"' {