Skip to content

Commit

Permalink
Changes to ADDomain
Browse files Browse the repository at this point in the history
- BREAKING CHANGE: A new parameter `AllowTrustRecreation` has been added
  that when set allows a trust to be recreated in scenarios where that
  is required. This way the user have to opt-in to such destructive
  action since since it can result in service interruption (issue dsccommunity#421).
  • Loading branch information
johlju committed Aug 3, 2019
1 parent 4b6ed53 commit 2c54137
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
- BREAKING CHANGE: Renamed the parameter `DomainAdministratorCredential`
to `Credential` to better indicate that it is possible to impersonate
any credential with enough permission to perform the task ([issue #269](https://github.com/PowerShell/ActiveDirectoryDsc/issues/269)).
- BREAKING CHANGE: A new parameter `AllowTrustRecreation` has been added
that when set allows a trust to be recreated in scenarios where that
is required. This way the user have to opt-in to such destructive
action since since it can result in service interruption ([issue #421](https://github.com/PowerShell/ActiveDirectoryDsc/issues/421)).
- Updated tests and replaced `Write-Error` with `throw`
([issue #332](https://github.com/PowerShell/ActiveDirectoryDsc/pull/332)).
- Added comment-based help ([issue #335](https://github.com/PowerShell/ActiveDirectoryDsc/issues/335)).
Expand Down
88 changes: 64 additions & 24 deletions DSCResources/MSFT_ADDomainTrust/MSFT_ADDomainTrust.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_ADDomainTrust'
.PARAMETER TrustDirection
Specifies the direction of the trust.
.PARAMETER AllowTrustRecreation
Specifies if the is allowed to be recreated if required. Default value is
$false.
#>
function Get-TargetResource
{
Expand Down Expand Up @@ -53,16 +57,21 @@ function Get-TargetResource
[Parameter(Mandatory = $true)]
[ValidateSet('Bidirectional', 'Inbound', 'Outbound')]
[System.String]
$TrustDirection
$TrustDirection,

[Parameter()]
[System.Boolean]
$AllowTrustRecreation = $false
)

# Return a credential object without the password.
$cimCredentialInstance = New-CimCredentialInstance -Credential $TargetCredential

$returnValue = @{
SourceDomainName = $SourceDomainName
TargetDomainName = $TargetDomainName
TargetCredential = $cimCredentialInstance
SourceDomainName = $SourceDomainName
TargetDomainName = $TargetDomainName
TargetCredential = $cimCredentialInstance
AllowTrustRecreation = $AllowTrustRecreation
}

$getTrustTargetAndSourceObject = @{
Expand Down Expand Up @@ -127,6 +136,10 @@ function Get-TargetResource
.PARAMETER Ensure
Specifies whether the computer account is present or absent. Default
value is 'Present'.
.PARAMETER AllowTrustRecreation
Specifies if the is allowed to be recreated if required. Default value is
$false.
#>
function Set-TargetResource
{
Expand Down Expand Up @@ -158,7 +171,11 @@ function Set-TargetResource
[Parameter()]
[ValidateSet('Present', 'Absent')]
[System.String]
$Ensure = 'Present'
$Ensure = 'Present',

[Parameter()]
[System.Boolean]
$AllowTrustRecreation = $false
)

$getTrustTargetAndSourceObject = @{
Expand All @@ -170,15 +187,19 @@ function Set-TargetResource

$trustSource, $trustTarget = Get-TrustSourceAndTargetObject @getTrustTargetAndSourceObject

$compareTargetResourceStateResult = Compare-TargetResourceState @PSBoundParameters
# Only pass those properties that should be evaluated.
$compareTargetResourceStateParameters = @{} + $PSBoundParameters
$compareTargetResourceStateParameters.Remove('AllowTrustRecreation')

$compareTargetResourceStateResult = Compare-TargetResourceState @compareTargetResourceStateParameters

# Get all properties that are not in desired state.
$propertiesNotInDesiredState = $compareTargetResourceStateResult |
Where-Object -FilterScript {
-not $_.InDesiredState
}
Where-Object -FilterScript {
-not $_.InDesiredState
}

if ($propertiesNotInDesiredState.Where({ $_.ParameterName -eq 'Ensure' }))
if ($propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'Ensure' }))
{
if ($Ensure -eq 'Present')
{
Expand Down Expand Up @@ -216,7 +237,7 @@ function Set-TargetResource
$trustRecreated = $false

# Check properties.
$trustTypeProperty = $propertiesNotInDesiredState.Where({ $_.ParameterName -eq 'TrustType' })
$trustTypeProperty = $propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'TrustType' })

if ($trustTypeProperty)
{
Expand All @@ -229,19 +250,26 @@ function Set-TargetResource
)
)

$trustSource.DeleteTrustRelationship($trustTarget)
$trustSource.CreateTrustRelationship($trustTarget, $TrustDirection)
if ($AllowTrustRecreation)
{
$trustSource.DeleteTrustRelationship($trustTarget)
$trustSource.CreateTrustRelationship($trustTarget, $TrustDirection)

Write-Verbose -Message (
$script:localizedData.RecreatedTrustType -f @(
$SourceDomainName,
$TargetDomainName,
$TrustType,
$TrustDirection
Write-Verbose -Message (
$script:localizedData.RecreatedTrustType -f @(
$SourceDomainName,
$TargetDomainName,
$TrustType,
$TrustDirection
)
)
)

$trustRecreated = $true
$trustRecreated = $true
}
else
{
throw $script:localizedData.NotOptInToRecreateTrust
}
}

<#
Expand All @@ -251,7 +279,7 @@ function Set-TargetResource
#>
if (-not $trustRecreated)
{
if ($propertiesNotInDesiredState.Where({ $_.ParameterName -eq 'TrustDirection' }))
if ($propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'TrustDirection' }))
{
$trustSource.UpdateTrustRelationship($trustTarget, $TrustDirection)

Expand Down Expand Up @@ -296,6 +324,10 @@ function Set-TargetResource
.PARAMETER Ensure
Specifies whether the computer account is present or absent. Default
value is 'Present'.
.PARAMETER AllowTrustRecreation
Specifies if the is allowed to be recreated if required. Default value is
$false.
#>
function Test-TargetResource
{
Expand Down Expand Up @@ -328,18 +360,26 @@ function Test-TargetResource
[Parameter()]
[ValidateSet('Present', 'Absent')]
[System.String]
$Ensure = 'Present'
$Ensure = 'Present',

[Parameter()]
[System.Boolean]
$AllowTrustRecreation = $false
)

Write-Verbose -Message (
$script:localizedData.TestConfiguration -f $SourceDomainName, $TargetDomainName, $TrustType
)

# Only pass those properties that should be evaluated.
$compareTargetResourceStateParameters = @{} + $PSBoundParameters
$compareTargetResourceStateParameters.Remove('AllowTrustRecreation')

<#
This returns array of hashtables which contain the properties ParameterName,
Expected, Actual, and InDesiredState.
#>
$compareTargetResourceStateResult = Compare-TargetResourceState @PSBoundParameters
$compareTargetResourceStateResult = Compare-TargetResourceState @compareTargetResourceStateParameters

if ($false -in $compareTargetResourceStateResult.InDesiredState)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ class MSFT_ADDomainTrust : OMI_BaseResource
[Required, Description("Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'."), ValueMap{"External","Forest"}, Values{"External","Forest"}] String TrustType;
[Required, Description("Specifies the direction of the trust."), ValueMap{"Bidirectional","Inbound","Outbound"}, Values{"Bidirectional","Inbound","Outbound"}] String TrustDirection;
[Key, Description("Specifies the name of the Active Directory domain that is requesting the trust.")] String SourceDomainName;
[Write, Description("Specifies if the is allowed to be recreated if required. Default value is $false.")] Boolean AllowTrustRecreation;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ InDesiredState = The Active Directory trust is in the desired state.
NotInDesiredState = The Active Directory trust is not in the desired state. (ADDT0009)
NeedToRecreateTrust = The trust type is not in desired state, removing the trust between the domains '{0}' and '{1}' with the context type '{2}' to be able to recreate the trust with the correct context type '{3}'. (ADDT0010)
RecreatedTrustType = Recreated the trust between domains '{0}' and '{1}' with the context type '{2}' and direction '{3}'. (ADDT0011)
NotOptInToRecreateTrust = Not opt-in to recreate trust. To opt-in set the parameter AllowTrustRecreation to $true.
'@
62 changes: 62 additions & 0 deletions Tests/Unit/MSFT_ADDomainTrust.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,32 @@ try
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.TrustDirection | Should -Be $mockGetTargetResourceParameters.TrustDirection
$getTargetResourceResult.TrustType | Should -Be $mockGetTargetResourceParameters.TrustType
$getTargetResourceResult.AllowTrustRecreation | Should -BeFalse
}

Context 'When the called with the AllowTrustRecreation set to $true' {
BeforeEach {
$mockGetTargetResourceParameters['AllowTrustRecreation'] = $true
}

It 'Should return the state as present' {
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.Ensure | Should -Be 'Present'
}

It 'Should return the same values as passed as parameters' {
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.SourceDomainName | Should -Be $mockGetTargetResourceParameters.SourceDomainName
$getTargetResourceResult.TargetDomainName | Should -Be $mockGetTargetResourceParameters.TargetDomainName
$getTargetResourceResult.TargetCredential.UserName | Should -Be $mockCredential.UserName
$getTargetResourceResult.AllowTrustRecreation | Should -BeTrue
}

It 'Should return the correct values for the other properties' {
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.TrustDirection | Should -Be $mockGetTargetResourceParameters.TrustDirection
$getTargetResourceResult.TrustType | Should -Be $mockGetTargetResourceParameters.TrustType
}
}
}

Expand Down Expand Up @@ -157,6 +183,7 @@ try
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.TrustDirection | Should -Be $mockGetTargetResourceParameters.TrustDirection
$getTargetResourceResult.TrustType | Should -Be $mockGetTargetResourceParameters.TrustType
$getTargetResourceResult.AllowTrustRecreation | Should -BeFalse
}
}
}
Expand Down Expand Up @@ -206,6 +233,7 @@ try
$getTargetResourceResult = Get-TargetResource @mockGetTargetResourceParameters
$getTargetResourceResult.TrustDirection | Should -BeNullOrEmpty
$getTargetResourceResult.TrustType | Should -BeNullOrEmpty
$getTargetResourceResult.AllowTrustRecreation | Should -BeFalse
}
}
}
Expand Down Expand Up @@ -791,6 +819,39 @@ try
}

Context 'When a property of a domain trust is not in desired state' {
Context 'When property TrustType is not in desired state, and not opt-in to recreate trust' {
BeforeAll {
Mock -CommandName Compare-TargetResourceState -MockWith {
return @(
@{
ParameterName = 'Ensure'
Actual = 'Present'
Expected = 'Present'
InDesiredState = $true
}
@{
ParameterName = 'TrustType'
Actual = 'Domain'
Expected = 'Forest'
InDesiredState = $false
}
)
}
}

BeforeEach {
$setTargetResourceParameters = $mockDefaultParameters.Clone()
$setTargetResourceParameters['TrustType'] = 'Forest'
$setTargetResourceParameters['TrustDirection'] = 'Inbound'
}

It 'Should not throw and call the correct methods' {
{ Set-TargetResource @setTargetResourceParameters } | Should -Throw $script:localizedData.NotOptInToRecreateTrust

Assert-MockCalled -CommandName Get-TrustSourceAndTargetObject -Exactly -Times 1 -Scope It
}
}

Context 'When both properties TrustType and and TrustDirection is not in desired state' {
BeforeAll {
Mock -CommandName Compare-TargetResourceState -MockWith {
Expand Down Expand Up @@ -825,6 +886,7 @@ try
$setTargetResourceParameters = $mockDefaultParameters.Clone()
$setTargetResourceParameters['TrustType'] = 'Forest'
$setTargetResourceParameters['TrustDirection'] = 'Inbound'
$setTargetResourceParameters['AllowTrustRecreation'] = $true
}

It 'Should not throw and call the correct methods' {
Expand Down

0 comments on commit 2c54137

Please sign in to comment.