DSCResources/MSFT_ADDomainTrust/MSFT_ADDomainTrust.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_ADDomainTrust' <# .SYNOPSIS Returns the current state of the Active Directory trust. .PARAMETER SourceDomainName Specifies the name of the Active Directory domain that is requesting the trust. .PARAMETER TargetDomainName Specifies the name of the Active Directory domain that is being trusted. .PARAMETER TargetCredential Specifies the credentials to authenticate to the target domain. .PARAMETER TrustType Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'. .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 { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetCredential, [Parameter(Mandatory = $true)] [ValidateSet('External', 'Forest')] [System.String] $TrustType, [Parameter(Mandatory = $true)] [ValidateSet('Bidirectional', 'Inbound', 'Outbound')] [System.String] $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 AllowTrustRecreation = $AllowTrustRecreation } $getTrustTargetAndSourceObject = @{ SourceDomainName = $SourceDomainName TargetDomainName = $TargetDomainName TargetCredential = $TargetCredential TrustType = $TrustType } $trustSource, $trustTarget = Get-TrustSourceAndTargetObject @getTrustTargetAndSourceObject try { # Find trust between source & destination. Write-Verbose -Message ( $script:localizedData.CheckingTrustMessage -f $SourceDomainName, $TargetDomainName, $directoryContextTyp ) $trust = $trustSource.GetTrustRelationship($trustTarget) $returnValue['TrustDirection'] = $trust.TrustDirection $returnValue['TrustType'] = ConvertFrom-DirectoryContextType -DirectoryContextType $trust.TrustType Write-Verbose -Message ($script:localizedData.TrustPresentMessage -f $SourceDomainName, $TargetDomainName, $directoryContextType) $returnValue['Ensure'] = 'Present' } catch { Write-Verbose -Message ($script:localizedData.TrustAbsentMessage -f $SourceDomainName, $TargetDomainName, $directoryContextType) $returnValue['Ensure'] = 'Absent' $returnValue['TrustDirection'] = $null $returnValue['TrustType'] = $null } return $returnValue } <# .SYNOPSIS Creates, removes, or updates the Active Directory trust so it is in the desired state. .PARAMETER SourceDomainName Specifies the name of the Active Directory domain that is requesting the trust. .PARAMETER TargetDomainName Specifies the name of the Active Directory domain that is being trusted. .PARAMETER TargetCredential Specifies the credentials to authenticate to the target domain. .PARAMETER TrustType Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'. .PARAMETER TrustDirection Specifies the direction of the trust. .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 { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetCredential, [Parameter(Mandatory = $true)] [ValidateSet('External', 'Forest')] [System.String] $TrustType, [Parameter(Mandatory = $true)] [ValidateSet('Bidirectional', 'Inbound', 'Outbound')] [System.String] $TrustDirection, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter()] [System.Boolean] $AllowTrustRecreation = $false ) $getTrustTargetAndSourceObject = @{ SourceDomainName = $SourceDomainName TargetDomainName = $TargetDomainName TargetCredential = $TargetCredential TrustType = $TrustType } $trustSource, $trustTarget = Get-TrustSourceAndTargetObject @getTrustTargetAndSourceObject # 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 } if ($propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'Ensure' })) { if ($Ensure -eq 'Present') { # Create trust. $trustSource.CreateTrustRelationship($trustTarget, $TrustDirection) Write-Verbose -Message ( $script:localizedData.AddedTrust -f @( $SourceDomainName, $TargetDomainName, $TrustType, $TrustDirection ) ) } else { # Remove trust. $trustSource.DeleteTrustRelationship($trustTarget) Write-Verbose -Message ( $script:localizedData.RemovedTrust -f @( $SourceDomainName, $TargetDomainName, $TrustType, $TrustDirection ) ) } } else { if ($Ensure -eq 'Present') { $trustRecreated = $false # Check properties. $trustTypeProperty = $propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'TrustType' }) if ($trustTypeProperty) { Write-Verbose -Message ( $script:localizedData.NeedToRecreateTrust -f @( $SourceDomainName, $TargetDomainName, (ConvertFrom-DirectoryContextType -DirectoryContextType $trustTypeProperty.Actual), $TrustType ) ) if ($AllowTrustRecreation) { $trustSource.DeleteTrustRelationship($trustTarget) $trustSource.CreateTrustRelationship($trustTarget, $TrustDirection) Write-Verbose -Message ( $script:localizedData.RecreatedTrustType -f @( $SourceDomainName, $TargetDomainName, $TrustType, $TrustDirection ) ) $trustRecreated = $true } else { throw $script:localizedData.NotOptInToRecreateTrust } } <# In case the trust direction property should be wrong, there is no need to update that property twice since it was set to the correct value when the trust was recreated. #> if (-not $trustRecreated) { if ($propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'TrustDirection' })) { $trustSource.UpdateTrustRelationship($trustTarget, $TrustDirection) Write-Verbose -Message ( $script:localizedData.SetTrustDirection -f $TrustDirection ) } } Write-Verbose -Message $script:localizedData.InDesiredState } else { # The trust is already absent, so in desired state. Write-Verbose -Message $script:localizedData.InDesiredState } } } <# .SYNOPSIS Determines if the properties of the Active Directory trust is in the desired state. .PARAMETER SourceDomainName Specifies the name of the Active Directory domain that is requesting the trust. .PARAMETER TargetDomainName Specifies the name of the Active Directory domain that is being trusted. .PARAMETER TargetCredential Specifies the credentials to authenticate to the target domain. .PARAMETER TrustType Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'. .PARAMETER TrustDirection Specifies the direction of the trust. .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 { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetCredential, [Parameter(Mandatory = $true)] [ValidateSet('External', 'Forest')] [System.String] $TrustType, [Parameter(Mandatory = $true)] [ValidateSet('Bidirectional', 'Inbound', 'Outbound')] [System.String] $TrustDirection, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $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 @compareTargetResourceStateParameters if ($false -in $compareTargetResourceStateResult.InDesiredState) { $testTargetResourceReturnValue = $false Write-Verbose -Message $script:localizedData.NotInDesiredState } else { $testTargetResourceReturnValue = $true Write-Verbose -Message $script:localizedData.InDesiredState } return $testTargetResourceReturnValue } <# .SYNOPSIS Compares the properties in the current state with the properties of the desired state and returns a hashtable with the comparison result. .PARAMETER SourceDomainName Specifies the name of the Active Directory domain that is requesting the trust. .PARAMETER TargetDomainName Specifies the name of the Active Directory domain that is being trusted. .PARAMETER TargetCredential Specifies the credentials to authenticate to the target domain. .PARAMETER TrustType Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'. .PARAMETER TrustDirection Specifies the direction of the trust. .PARAMETER Ensure Specifies whether the computer account is present or absent. Default value is 'Present'. #> function Compare-TargetResourceState { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetCredential, [Parameter(Mandatory = $true)] [ValidateSet('External', 'Forest')] [System.String] $TrustType, [Parameter(Mandatory = $true)] [ValidateSet('Bidirectional', 'Inbound', 'Outbound')] [System.String] $TrustDirection, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present' ) $getTargetResourceParameters = @{ SourceDomainName = $SourceDomainName TargetDomainName = $TargetDomainName TargetCredential = $TargetCredential TrustType = $TrustType TrustDirection = $TrustDirection } $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters <# If the desired state should be Absent, then there is no need to compare properties other than 'Ensure'. If the other properties would be compared, they would return a false negative during test. #> if ($Ensure -eq 'Present') { $propertiesToEvaluate = @( 'Ensure' 'TrustType' 'TrustDirection' ) } else { $propertiesToEvaluate = @( 'Ensure' ) } <# If the user did not specify Ensure property, then it is not part of the $PSBoundParameters, but it still needs to be compared. Copy the hashtable $PSBoundParameters and add 'Ensure' property to make sure it is part of the DesiredValues. #> $desiredValues = @{} + $PSBoundParameters $desiredValues['Ensure'] = $Ensure $compareResourcePropertyStateParameters = @{ CurrentValues = $getTargetResourceResult DesiredValues = $desiredValues Properties = $propertiesToEvaluate } return Compare-ResourcePropertyState @compareResourcePropertyStateParameters } <# .SYNOPSIS This returns a new object of the type System.DirectoryServices.ActiveDirectory.Domain which is a class that represents an Active Directory Domain Services domain. .PARAMETER DirectoryContext The Active Directory context from which the domain object is returned. Calling the Get-ADDirectoryContext gets a value that can be provided in this parameter. .NOTES This is a wrapper to enable unit testing of this resource. see issue https://github.com/PowerShell/ActiveDirectoryDsc/issues/324 for more information. #> function Get-ActiveDirectoryDomain { [CmdletBinding()] [OutputType([System.DirectoryServices.ActiveDirectory.Domain])] param ( [Parameter(Mandatory = $true)] [System.DirectoryServices.ActiveDirectory.DirectoryContext] $DirectoryContext ) return [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DirectoryContext) } <# .SYNOPSIS This returns a new object of the type System.DirectoryServices.ActiveDirectory.Forest which is a class that represents an Active Directory Domain Services forest. .PARAMETER DirectoryContext The Active Directory context from which the forest object is returned. Calling the Get-ADDirectoryContext gets a value that can be provided in this parameter. .NOTES This is a wrapper to enable unit testing of this resource. see issue https://github.com/PowerShell/ActiveDirectoryDsc/issues/324 for more information. #> function Get-ActiveDirectoryForest { [CmdletBinding()] [OutputType([System.DirectoryServices.ActiveDirectory.Forest])] param ( [Parameter(Mandatory = $true)] [System.DirectoryServices.ActiveDirectory.DirectoryContext] $DirectoryContext ) return [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($DirectoryContext) } <# .SYNOPSIS This returns the converted value from a Trust Type value to the correct Directory Context Type value. .PARAMETER TrustType The trust type value to convert. #> function ConvertTo-DirectoryContextType { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.String] $TrustType ) switch ($TrustType) { 'External' { $directoryContextType = 'Domain' } 'Forest' { $directoryContextType = 'Forest' } } return $directoryContextType } <# .SYNOPSIS This returns the converted value from a Directory Context Type value to the correct Trust Type value. .PARAMETER DirectoryContextType The Directory Context Type value to convert. #> function ConvertFrom-DirectoryContextType { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.String] $DirectoryContextType ) switch ($DirectoryContextType) { 'Domain' { $trustType = 'External' } 'Forest' { $trustType = 'Forest' } } return $trustType } <# .SYNOPSIS Returns two objects where the first object is for the source domain and the second object is for the target domain. .PARAMETER SourceDomainName Specifies the name of the Active Directory domain that is requesting the trust. .PARAMETER TargetDomainName Specifies the name of the Active Directory domain that is being trusted. .PARAMETER TargetCredential Specifies the credentials to authenticate to the target domain. .PARAMETER TrustType Specifies the type of trust. The value 'External' means the context Domain, while the value 'Forest' means the context 'Forest'. .OUTPUTS For both objects the type returned is either of the type System.DirectoryServices.ActiveDirectory.Domain or of the type System.DirectoryServices.ActiveDirectory.Forest. #> function Get-TrustSourceAndTargetObject { [CmdletBinding()] [OutputType([System.Object[]])] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetCredential, [Parameter(Mandatory = $true)] [ValidateSet('External', 'Forest')] [System.String] $TrustType ) $directoryContextType = ConvertTo-DirectoryContextType -TrustType $TrustType # Create the target object. $getADDirectoryContextParameters = @{ DirectoryContextType = $directoryContextType Name = $TargetDomainName Credential = $TargetCredential } $targetDirectoryContext = Get-ADDirectoryContext @getADDirectoryContextParameters # Create the source object. $getADDirectoryContextParameters = @{ DirectoryContextType = $directoryContextType Name = $SourceDomainName } $sourceDirectoryContext = Get-ADDirectoryContext @getADDirectoryContextParameters if ($directoryContextType -eq 'Domain') { $trustSource = Get-ActiveDirectoryDomain -DirectoryContext $sourceDirectoryContext $trustTarget = Get-ActiveDirectoryDomain -DirectoryContext $targetDirectoryContext } else { $trustSource = Get-ActiveDirectoryForest -DirectoryContext $sourceDirectoryContext $trustTarget = Get-ActiveDirectoryForest -DirectoryContext $targetDirectoryContext } return $trustSource, $trustTarget } Export-ModuleMember -Function *-TargetResource |