Other Posts in this Series:
- Use PowerShell ADSI to Search Computers in Active Directory
- Use PowerShell ADSI to Search Groups in Active Directory
- Use PowerShell ADSI to Create an AD Group
- Use PowerShell ADSI to Delete an AD Group
- Use PowerShell ADSI to Modify an AD Group
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