Wednesday, March 5, 2014

Copy Group Membership from one Domain to Another

As a part of my job as a systems engineer I have the opportunity to work on a couple of  acquisitions. During the integration process we found a need to copy the AD security groups used to control access to shares for shared data.  Here is a little PowerShell script that I wrote that uses a CSV to map each user between the two domains. 

Prerequisites
-A CSV mapping the usernames of each user from the source domain to the userid in the destination domain. headers for CSV (SrcDomain-UserName,DestDomain-UserName)
-Read access in the source domain
-Read/Modify rights in the destination domain
-A matching group on in the destination. (Group A in the source  is named Group A in the destination)


#Copies group membership of groups from one domain to another. 
# It uses a CSV to map users between the 2 domains.
# ChangeLog
# 3/3/14-Added logging process for users who might already be in the destination group.

Import-Module ActiveDirectory

$SourceGrps=@()
$DestGrps=@()
$NewuserInfo=@()
$Compare=@()

$RemoteDomainCredential=Get-Credential "username@domainname"

$RemoteDomain="Something.org" #DomainNmae of the Source domain

$LogFile=""

$Csv=Import-Csv -Path "UserMap.csv"

$SourceGrps=Get-ADGroup -Filter * -SearchBase "OU=Groups,DC=Something,DC=org" -Server $RemoteDomain  -credential $RemoteDomainCredential  |Sort{ $_.Name.Substring(1)}

$DestGrps=Get-ADGroup -Filter * -SearchBase "OU=Groups,DC=newdomain,DC=org" |Sort{ $_.Name.Substring(1)}

$Compare=Compare-Object -ReferenceObject($SourceGrps) -DifferenceObject($DestGrps) -PassThru -Property Name

#$Compare the groups in the source and destination domain. ensuring only groups that exist in both domains are copied

ForEach ($Commparison in $Compare){

Write-Host $Commparison.sideIndicator

$Temp=$Commparison.Name

       if ($Commparison.sideIndicator -eq "=>"){

              Add-Content -Path $LogFile "$Temp Was Found in the Destination but not In the Source"

       }ElseIf ($Commparison.sideIndicator -eq "<="){

              Add-Content -Path $LogFile "$Temp Was Found in the Source but not In the Destination"

              $SourceGrps.remove($temp)

       }

}

foreach($Group In $SourceGrps){

       $NewuserInfo=@()

       $SourceGroup=$Group.Name

       $GrpUsers=Get-ADGroupMember -Identity $Group -Server $RemoteDomain  -credential $RemoteDomainCredential

       Write-Host $Group.Name

       Write-host $GrpUsers.count

       if ($GrpUsers.Count -eq $Null) {

              Add-Content -Path $LogFile "$SourceGroup,,Source Group, Group is Empty"

       }Else{

              foreach($User in $GrpUsers){

                     $SourceUser=$User.Name

                     #Add logic for no results log

                     $Result = $CSV | Where{$User.SamAccountName -eq $_.SrcDomain-UserName}

                     if ($Result -ne $null){

                           $NewuserInfo += $Result

                     }Else{                    

                           Add-Content -Path $LogFile "$SourceGroup,$SourceUser,Source Group, User not found in CSV (Failure)"

                           sleep 1

                     }

              }

              $User=$null

              Foreach($User in $NewuserInfo){

                     $DestUserName=$user.DestDomain-UserName

                     $DestGroupName=$Group.Name

                     Try{

                           #writing Group Members in destination Group
                           Add-ADGroupMember -Identity $DestGroupName -Members $DestUserName 

                           Add-Content -Path $LogFile "$DestGroupName,$DestUserName,User Added to Group (Success)"

                           sleep 1

                     }

                     catch [Microsoft.ActiveDirectory.Management.ADException]{

                           if ($_.psbase.Exception.ErrorCode -eq 1378){ #Get Errorcode from $Error[0]

                                  Add-Content -Path $LogFile "$DestGroupName,$DestUserName,User Already in Group"

                                  sleep 1

                           }else{

                                  throw

                           }

                     }

              }

       }

}