DSCResources/MSFT_xADDomainTrust/MSFT_xADDomainTrust.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 'xActiveDirectory.Common' Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'xActiveDirectory.Common.psm1') $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_xADDomainTrust' 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] $TargetDomainAdministratorCredential, [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' ) # Load the .NET assembly try { Add-type -AssemblyName System.DirectoryServices } # If not found, means ADDS role is not installed catch { $missingRoleMessage = $($script:localizedData.MissingRoleMessage) -f 'AD-Domain-Services' New-ObjectNotFoundException -Message $missingRoleMessage -ErrorRecord $_ } try { switch ($TrustType) { 'External' { $DomainOrForest = 'Domain' } 'Forest' { $DomainOrForest = 'Forest' } } # Create the target object $trgDirectoryContext = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @($DomainOrForest, $TargetDomainName, $TargetDomainAdministratorCredential.UserName, $TargetDomainAdministratorCredential.GetNetworkCredential().Password) $trgDomain = ([type]"System.DirectoryServices.ActiveDirectory.$DomainOrForest")::"Get$DomainOrForest"($trgDirectoryContext) # Create the source object $srcDirectoryContext = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @($DomainOrForest, $SourceDomainName) $srcDomain = ([type]"System.DirectoryServices.ActiveDirectory.$DomainOrForest")::"Get$DomainOrForest"($srcDirectoryContext) # Find trust between source & destination. Write-Verbose -Message ($script:localizedData.CheckingTrustMessage -f $SourceDomainName, $TargetDomainName) $trust = $srcDomain.GetTrustRelationship($trgDomain) Write-Verbose -Message ($script:localizedData.TrustPresentMessage -f $SourceDomainName, $TargetDomainName) $Ensure = 'Present' } catch { Write-Verbose -Message ($script:localizedData.TrustAbsentMessage -f $SourceDomainName, $TargetDomainName) $Ensure = 'Absent' } # return a credential object without password $CIMCredential = New-CimInstance -ClassName MSFT_Credential -ClientOnly ` -Namespace 'root/microsoft/windows/desiredstateconfiguration' ` -Property @{ UserName = [System.String] $TargetDomainAdministratorCredential.UserName Password = [System.String] $null } return @{ SourceDomainName = $SourceDomainName TargetDomainName = $TargetDomainName Ensure = $Ensure TrustType = $trust.TrustType TrustDirection = $trust.TrustDirection TargetDomainAdministratorCredential = $CIMCredential } } function Set-TargetResource { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "", Justification = 'Verbose messaging in helper function')] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetDomainAdministratorCredential, [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' ) if ($PSBoundParameters.ContainsKey('Debug')) { $null = $PSBoundParameters.Remove('Debug') } Confirm-ResourceProperties @PSBoundParameters -Apply } function Test-TargetResource { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "", Justification = 'Verbose messaging in helper function')] [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetDomainAdministratorCredential, [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' ) #region Input Validation # Load the .NET assembly try { Add-type -AssemblyName System.DirectoryServices } # If not found, means ADDS role is not installed catch { $missingRoleMessage = $($script:localizedData.MissingRoleMessage) -f 'AD-Domain-Services' New-ObjectNotFoundException -Message $missingRoleMessage -ErrorRecord $_ } #endregion if ($PSBoundParameters.ContainsKey('Debug')) { $null = $PSBoundParameters.Remove('Debug') } Confirm-ResourceProperties @PSBoundParameters } function Confirm-ResourceProperties { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $SourceDomainName, [Parameter(Mandatory = $true)] [System.String] $TargetDomainName, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $TargetDomainAdministratorCredential, [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.Management.Automation.SwitchParameter] $Apply ) try { $checkingTrustMessage = $script:localizedData.CheckingTrustMessage -f $SourceDomainName, $TargetDomainName Write-Verbose -Message $checkingTrustMessage switch ($TrustType) { 'External' { $DomainOrForest = 'Domain' } 'Forest' { $DomainOrForest = 'Forest' } } # Create the target object $trgDirectoryContext = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @($DomainOrForest, $TargetDomainName, $TargetDomainAdministratorCredential.UserName, $TargetDomainAdministratorCredential.GetNetworkCredential().Password) $trgDomain = ([type]"System.DirectoryServices.ActiveDirectory.$DomainOrForest")::"Get$DomainOrForest"($trgDirectoryContext) # Create the source object $srcDirectoryContext = New-Object -TypeName 'System.DirectoryServices.ActiveDirectory.DirectoryContext' -ArgumentList @($DomainOrForest, $SourceDomainName) $srcDomain = ([type]"System.DirectoryServices.ActiveDirectory.$DomainOrForest")::"Get$DomainOrForest"($srcDirectoryContext) # Find trust try { # Find trust between source & destination. $trust = $srcDomain.GetTrustRelationship($TargetDomainName) $TestTrustMessage = $script:localizedData.TestTrustMessage -f 'present', $Ensure Write-Verbose -Message $TestTrustMessage if ($Ensure -eq 'Present') { #region Test for trust direction $CheckPropertyMessage = $script:localizedData.CheckPropertyMessage -f 'trust direction' Write-Verbose -Message $CheckPropertyMessage if ($trust.TrustDirection -ne $TrustDirection) { # Set the trust direction if not correct $notDesiredPropertyMessage = $script:localizedData.NotDesiredPropertyMessage -f 'Trust direction', $TrustDirection, $trust.TrustDirection Write-Verbose -Message $notDesiredPropertyMessage if ($Apply) { $srcDomain.UpdateTrustRelationship($trgDomain, $TrustDirection) $setPropertyMessage = $script:localizedData.SetPropertyMessage -f 'Trust direction' Write-Verbose -Message $setPropertyMessage } else { return $false } } # end trust direction is not correct else { # Trust direction is correct $desiredPropertyMessage = $script:localizedData.DesiredPropertyMessage -f 'Trust direction' Write-Verbose -Message $desiredPropertyMessage } #endregion trust direction #region Test for trust type $CheckPropertyMessage = $script:localizedData.CheckPropertyMessage -f 'trust type' Write-Verbose -Message $CheckPropertyMessage if ($trust.TrustType -ne $TrustType) { # Set the trust type if not correct $notDesiredPropertyMessage = $script:localizedData.NotDesiredPropertyMessage -f 'Trust type', $TrustType, $trust.TrustType Write-Verbose -Message $notDesiredPropertyMessage if ($Apply) { # Only way to fix the trust direction is to delete it and create again # TODO: Add a property to ask user permission to delete an existing trust $srcDomain.DeleteTrustRelationship($trgDomain) $srcDomain.CreateTrustRelationship($trgDomain, $TrustDirection) $setPropertyMessage = $script:localizedData.SetPropertyMessage -f 'Trust type' Write-Verbose -Message $setPropertyMessage } else { return $false } } # end trust type is not correct else { # Trust type is correct $desiredPropertyMessage = $script:localizedData.DesiredPropertyMessage -f 'Trust type' Write-Verbose -Message $desiredPropertyMessage } #endregion Test for trust type # If both trust type and trust direction are correct, return true if (-not $Apply) { return $true } } # end Ensure -eq present else { # If the trust should be absent, remove the trust if ($Apply) { $removingTrustMessage = $script:localizedData.RemovingTrustMessage -f $SourceDomainName, $TargetDomainName Write-Verbose -Message $removingTrustMessage $srcDomain.DeleteTrustRelationship($trgDomain) $deleteTrustMessage = $script:localizedData.DeleteTrustMessage Write-Verbose -Message $deleteTrustMessage } else { return $false } } # end Ensure -eq absent } # end find trust catch [System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException] { # Trust does not exist between source and destination $TestTrustMessage = $script:localizedData.TestTrustMessage -f 'absent', $Ensure Write-Verbose -Message $TestTrustMessage if ($Ensure -eq 'Present') { if ($Apply) { $addingTrustMessage = $script:localizedData.AddingTrustMessage -f $SourceDomainName, $TargetDomainName Write-Verbose -Message $addingTrustMessage $srcDomain.CreateTrustRelationship($trgDomain, $TrustDirection) $setTrustMessage = $script:localizedData.SetTrustMessage Write-Verbose -Message $setTrustMessage } else { return $false } } # end Ensure -eq Present else { if (-not $Apply) { return $true } } } # end no trust } # end getting directory object catch [System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException] { throw } } Export-ModuleMember -Function *-TargetResource |