2012-12-11

Import AD groups from CSV file using PowerShell

I recently had to migrate about 200 groups containing about 1500 members from one AD domain to an other. To do this manually would probably drive everyone insane, so I got some clues from the http://powershellcommunity.org/ on how to export my groups from the old domain.

I changed the Get-QADUser cmdlet to  Get-ADObject, as my groups have other groups as members.

Import were quite straight forward, and I made a script that adds (or updates) renamed groups (all my groups had either L_ or DL_ as name prefix, and these had to be changed), adds the group description and then adds members (and this supports groups as members, and creates groups if they do not exist yet).

I even added some caching, to speed it up.


#
# AD-Import script
# 
# Copyright © 2012 -  Rune Nordbøe Skillingstad <rune.skillingstad@ntnu.no>
#
# License: GPLv2 - http://www.fsf.org/licensing/licenses/info/GPLv2.html

## 
# Config
##

# File containing import data
# Needed fields are 'Group Name', 'Group Description', 'Member Name'
# If you encounter UTF-8 problems (group names or descriptions containing 
# stray ?'s), your file is most likely ANSI encoded, recode to UTF-8 to
# fix
$CSVFile = "import.csv"

# DN for new groups 
$GroupDN    = "OU=MyGroups,OU=MyDepartment,DC=ad,DC=tld"
$Domain     = "AD-TLD"

# Type and Scope of new groups
# Types = 'Security' or 'Distribution'
# Scopes = 'Global' 'Universal' or 'DomainLocal'
$GroupType  = "Security"
$GroupScope = "Universal"

# To search and replace, uncomment and use these two
$ReplaceMatch = '^D?L_'
$ReplaceTo    = "NEW_"

# Set this to Continue for debugging
$DebugPreference = "SilentlyContinue"  # "Continue"

##
# The code
##
Function GetGroup {
 param([string]$group)
 if($ReplaceMatch -and $ReplaceTo) {
  $group = $group -replace $ReplaceMatch, $ReplaceTo
 } 
 if(!($group -match "^$Domain")) {
  $group = "$Domain\$group"
 }
 $qadgroup = Get-QADGroup -SearchRoot "$GroupDN" "$group"
 if($qadgroup) {
  Write-Debug "Found existing group $group"
 } else {
  $group = $group -replace "^$Domain\\", ""
  Write-Debug "Creating new group $group ... "
  $qadgroup = New-QADGroup -ParentContainer "$GroupDN" -name "$group" `
   -samAccountName "$group" -GroupType "$GroupType" -GroupScope "Universal"
 }
 return $qadgroup
}

$MemberCache = @{}
Function GetMember {
 param([string]$member)
 if($ReplaceMatch -and $ReplaceTo) {
  $member = $member -replace $ReplaceMatch, $ReplaceTo
 }
 if(!($member -match "^$Domain")) {
  $member = "$Domain\$member"
 }
 if($MemberCache.ContainsKey($member)) {
  $qadobject = $MemberCache.Get_Item($member)
  Write-Debug "Found cached object $qadobject"
 } else {
  $qadobject = Get-QADObject $member
  if($qadobject) {
   Write-Debug "Found uncached object $qadobject"
  } else {
   Write-Debug "Not found... suspecting missing group"
   $qadobject = GetGroup $member
  }
  $MemberCache.Add($member, $qadobject)
 }
 return $qadobject
}

$import = Import-CSV $CSVFile
$prev  = ""
Foreach($line in $import) {
 if($line."Group Name" -ne $prev) {
  $prev = $line."Group Name"
  $qadgroup = GetGroup $prev
  if($ReplaceMatch -and $ReplaceTo) {
   $description = $line."Group Description" -replace $ReplaceMatch, $ReplaceTo
  } else {
   $description = $line."Group Description"
  }
  if($qadgroup.Description -ne $description) {
   Write-Debug ("Updating description to " + $qadgroup.Name)
   Set-QADGroup -identity $qadgroup.DN -description $description | Out-Null
  }
 }
 $member = GetMember $line."Member Name"
 if([array]$qadgroup.Member -notcontains $member.DN) {
  Write-Debug "Member not found in group"
  Add-QADGroupMember -identity $qadgroup.DN -Member $member.Name | Out-Null
 } else {
  Write-Debug "Member exists in group"
 }

}