Use PowerShell ADSI to Migrate AD Group Members

Other Posts in this Series:

UPDATE: I’ve updated this script because LDAP does not return all Active Directory group members if there are more than 1500 members in the group.

This post provides a function which enables us to use PowerShell ADSI to migrate AD group members. We can also specify whether to copy or move the group members.

function  Get-ADGroupMembers {
param ([string]$adgroup)
$searcher=[adsisearcher]""
$searcher.Filter="(&(objectClass=group)(cn=$adgroup))"
$searcher.PageSize=200
#find group   
$result=$searcher.FindOne()
#if group found
if ($result) {
#if range exists because group is large
$moreThan1500Members = [bool]($result.Properties.PropertyNames | where { $_ -like "member;range=*" })
#if group has more than 1500 members
if($moreThan1500Members) {     
#we need to recurse through ranges
$iteratedAllRanges=$false
$rangeBottom =0
$rangeTop= 0
while (!($iteratedAllRanges)) {
$rangeTop=$rangeBottom + 1499
#set new range
$memberRange="member;range=$rangeBottom-$rangeTop"
$searcher.PropertiesToLoad.Clear()
[void]$searcher.PropertiesToLoad.Add("$memberRange")
try {
#if range invalid, throw exception
$result = $searcher.FindOne()
$rangedProperty = $result.Properties.PropertyNames -like "member;range=*"
$members +=$result.Properties.item($rangedProperty)
if ($members.count -eq 0) { $iteratedAllRanges=$true }
} catch {
$iteratedAllRanges=$true
}
#increment bottom of range for next iteration
$rangeBottom+=1500
}
} else {
#group member count is less than 1500
$members += $result.properties.item("member")
}
$searcher.Dispose()
return $members
}
return $false   
}
function Migrate-ADGroup
{
Param
(
[string]$sourceDN, 
[string]$targetDN,
[bool]$move
)
if (!([adsi]::Exists("LDAP://$sourceDN"))) {
write-host "$sourceDN does not exist"
return     
}
if (!([adsi]::Exists("LDAP://$targetDN"))) {
write-host "$targetDN does not exist"
return
}
$sourceDNADSI = [ADSI]"LDAP://$sourceDN"
$targetDNADSI = [ADSI]"LDAP://$targetDN"
try {
$count = 0;
Get-ADGroupMembers ($sourceDNADSI.Name) | ForEach-Object {
$count++
$groupObject = [adsisearcher]"(distinguishedname=$($_))"   
if ($move) {
write-host "Moving $($groupObject.FindOne().Properties.name)"
try { $targetDNADSI.Add("LDAP://$_") } catch {}
try { $sourceDNADSI.Remove("LDAP://$_") } catch {}
} else {
write-host "Copying $($groupObject.FindOne().Properties.name)"
try { $targetDNADSI.Add("LDAP://$_") } catch {}
}
}
write-host "Processesed $count objects"
} catch {
write-host $_.Exception.Message
}
}
$sourcegroup = "CN=application1,OU=Apps,DC=alkanesolutions,DC=co,DC=uk"
$targetgroup = "CN=application2,OU=Apps,DC=alkanesolutions,DC=co,DC=uk"
#source group to migrate from, target group to migrate to, false (copy members) or true (move members)
Migrate-ADGroup $sourcegroup $targetgroup $false