From 053b5af07f1eace31caadfc90156f765a57c2240 Mon Sep 17 00:00:00 2001 From: RobBiddle Date: Wed, 20 Dec 2017 18:40:00 -0500 Subject: [PATCH 1/2] Added a function to determine the AD domain FQDN of an AD Object from its DN string --- .../MSFT_xADCommon/MSFT_xADCommon.ps1 | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/DSCResources/MSFT_xADCommon/MSFT_xADCommon.ps1 b/DSCResources/MSFT_xADCommon/MSFT_xADCommon.ps1 index 5ce68dc97..d14c71536 100644 --- a/DSCResources/MSFT_xADCommon/MSFT_xADCommon.ps1 +++ b/DSCResources/MSFT_xADCommon/MSFT_xADCommon.ps1 @@ -104,6 +104,37 @@ function Test-ADDomain return ($null -ne $domain); } +<# +.Synopsis + Author: Robert D. Biddle (https://github.com/RobBiddle) + Created: December.20.2017 +.DESCRIPTION + Takes an Active Directory DistinguishedName as input, returns the domain FQDN +.EXAMPLE + Get-ADDomainNameFromDistinguishedName 'CN=ExampleObject,OU=ExampleOU,DC=example,DC=com' +#> +function Get-ADDomainNameFromDistinguishedName +{ + [CmdletBinding()] + param + ( + [Parameter( + Mandatory = $false, + ValueFromPipeline = $false)] + [string]$DN + ) + + $SplitDN = ($DN -split 'DC='); + $DomainDNSplitParts = $SplitDN[1..$SplitDN.Length]; + $DomainDN = ""; + foreach($part in $DomainDNSplitParts) { + $DomainDN += "DC=$part" + }; + $DomainName = (($DomainDN -replace 'DC=', '') -replace ',', '.'); + return $DomainName; + +} #end function Get-ADDomainNameFromDistinguishedName + # Internal function to get an Active Directory object's parent Distinguished Name function Get-ADObjectParentDN { From 38d1f640b9bd7593d52017f49b1274f0e1ee17cf Mon Sep 17 00:00:00 2001 From: RobBiddle Date: Wed, 20 Dec 2017 18:50:01 -0500 Subject: [PATCH 2/2] FIX for Issue #152. This DSC Resource now supports AD Group membership consisting of AD Objects from multiple AD Domains. When using a MembershipAttribute of DistinguishedName the Member Objects will now be properly obtained from the Objects' Domain rather than the Domain of the AD Group. --- DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1 | 115 +++++++++++++++++- README.md | 1 + 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1 b/DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1 index e23cff3fb..22ea31fbd 100644 --- a/DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1 +++ b/DSCResources/MSFT_xADGroup/MSFT_xADGroup.psm1 @@ -4,11 +4,13 @@ data LocalizedData # culture="en-US" ConvertFrom-StringData @' RetrievingGroupMembers = Retrieving group membership based on '{0}' property. + GroupMembershipMultipleDomains = Group membership objects are in '{0}' different AD Domains. GroupMembershipInDesiredState = Group membership is in the desired state. GroupMembershipNotDesiredState = Group membership is NOT in the desired state. AddingGroupMembers = Adding '{0}' member(s) to AD group '{1}'. RemovingGroupMembers = Removing '{0}' member(s) from AD group '{1}'. + AddingGroupMember = Adding member '{0}' from domain '{1}' to AD group '{2}'. AddingGroup = Adding AD Group '{0}' UpdatingGroup = Updating AD Group '{0}' RemovingGroup = Removing AD Group '{0}' @@ -335,6 +337,23 @@ function Set-TargetResource $adGroupParams = Get-ADCommonParameters @PSBoundParameters; try { + + if ($MembershipAttribute -eq 'DistinguishedName') + { + $AllMembers = $Members + $MembersToInclude + $MembersToExclude + $GroupMemberDomains = @(); + foreach($member in $AllMembers) + { + $GroupMemberDomains += Get-ADDomainNameFromDistinguishedName -DN $member + } + $GroupMemberDomainCount = ($GroupMemberDomains | Select-Object -Unique).count + if( ($GroupMemberDomainCount -gt 1) -or ($GroupMemberDomains -ine (Get-DomainName)).count -gt 0 ) + { + Write-Verbose ($LocalizedData.GroupMembershipMultipleDomains -f $GroupMemberDomainCount); + $MembersInMultipleDomains = $true + } + } + $adGroup = Get-ADGroup @adGroupParams -Property Name,GroupScope,GroupCategory,DistinguishedName,Description,DisplayName,ManagedBy,Info; if ($Ensure -eq 'Present') { @@ -403,13 +422,57 @@ function Set-TargetResource Remove-ADGroupMember @adGroupParams -Members $adGroupMembers -Confirm:$false; } Write-Verbose -Message ($LocalizedData.AddingGroupMembers -f $Members.Count, $GroupName); - Add-ADGroupMember @adGroupParams -Members $Members; + if ($MembersInMultipleDomains) + { + foreach($member in $Members) + { + $memberDomain = Get-ADDomainNameFromDistinguishedName -DN $member; + Write-Verbose -Message ($LocalizedData.AddingGroupMember -f $member, $memberDomain, $GroupName); + $memberObjectClass = (Get-ADObject -Identity $member -Server $memberDomain -Properties ObjectClass).ObjectClass; + if ($memberObjectClass -eq 'computer') + { + $memberObject = Get-ADComputer -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'group') + { + $memberObject = Get-ADGroup -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'user') + { + $memberObject = Get-ADUser -Identity $member -Server $memberDomain; + } + Add-ADGroupMember @adGroupParams -Members $memberObject; + } + }else + { + Add-ADGroupMember @adGroupParams -Members $Members; + } } if ($PSBoundParameters.ContainsKey('MembersToInclude') -and -not [system.string]::IsNullOrEmpty($MembersToInclude)) { $MembersToInclude = Remove-DuplicateMembers -Members $MembersToInclude; Write-Verbose -Message ($LocalizedData.AddingGroupMembers -f $MembersToInclude.Count, $GroupName); - Add-ADGroupMember @adGroupParams -Members $MembersToInclude; + if ($MembersInMultipleDomains) + { + foreach($member in $MembersToInclude) + { + $memberDomain = Get-ADDomainNameFromDistinguishedName -DN $member; + Write-Verbose -Message ($LocalizedData.AddingGroupMember -f $member, $memberDomain, $GroupName); + $memberObjectClass = (Get-ADObject -Identity $member -Server $memberDomain -Properties ObjectClass).ObjectClass; + if ($memberObjectClass -eq 'computer') + { + $memberObject = Get-ADComputer -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'group') + { + $memberObject = Get-ADGroup -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'user') + { + $memberObject = Get-ADUser -Identity $member -Server $memberDomain; + } + Add-ADGroupMember @adGroupParams -Members $memberObject; + } + }else + { + Add-ADGroupMember @adGroupParams -Members $MembersToInclude; + } } if ($PSBoundParameters.ContainsKey('MembersToExclude') -and -not [system.string]::IsNullOrEmpty($MembersToExclude)) { @@ -472,13 +535,57 @@ function Set-TargetResource { $Members = Remove-DuplicateMembers -Members $Members; Write-Verbose -Message ($LocalizedData.AddingGroupMembers -f $Members.Count, $GroupName); - Add-ADGroupMember @adGroupParams -Members $Members; + if ($MembersInMultipleDomains) + { + foreach($member in $Members) + { + $memberDomain = Get-ADDomainNameFromDistinguishedName -DN $member; + Write-Verbose -Message ($LocalizedData.AddingGroupMember -f $member, $memberDomain, $GroupName); + $memberObjectClass = (Get-ADObject -Identity $member -Server $memberDomain -Properties ObjectClass).ObjectClass; + if ($memberObjectClass -eq 'computer') + { + $memberObject = Get-ADComputer -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'group') + { + $memberObject = Get-ADGroup -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'user') + { + $memberObject = Get-ADUser -Identity $member -Server $memberDomain; + } + Add-ADGroupMember @adGroupParams -Members $memberObject; + } + }else + { + Add-ADGroupMember @adGroupParams -Members $Members; + } } elseif ($PSBoundParameters.ContainsKey('MembersToInclude') -and -not [system.string]::IsNullOrEmpty($MembersToInclude)) { $MembersToInclude = Remove-DuplicateMembers -Members $MembersToInclude; Write-Verbose -Message ($LocalizedData.AddingGroupMembers -f $MembersToInclude.Count, $GroupName); - Add-ADGroupMember @adGroupParams -Members $MembersToInclude; + if ($MembersInMultipleDomains) + { + foreach($member in $MembersToInclude) + { + $memberDomain = Get-ADDomainNameFromDistinguishedName -DN $member; + Write-Verbose -Message ($LocalizedData.AddingGroupMember -f $member, $memberDomain, $GroupName); + $memberObjectClass = (Get-ADObject -Identity $member -Server $memberDomain -Properties ObjectClass).ObjectClass; + if ($memberObjectClass -eq 'computer') + { + $memberObject = Get-ADComputer -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'group') + { + $memberObject = Get-ADGroup -Identity $member -Server $memberDomain; + }elseif ($memberObjectClass -eq 'user') + { + $memberObject = Get-ADUser -Identity $member -Server $memberDomain; + } + Add-ADGroupMember @adGroupParams -Members $memberObject; + } + }else + { + Add-ADGroupMember @adGroupParams -Members $MembersToInclude; + } } } diff --git a/README.md b/README.md index b0be46e73..26374defe 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ Setting an ODJ Request file path for a configuration that creates a computer acc ## Versions ### Unreleased +* xADGroup: Fixes for issue #152 relating to errors when adding Group Members from a different domain. This DSC Resource now supports AD Group membership consisting of AD Objects from multiple AD Domains. ### 2.16.0.0