AD Migration with powershell and fun for all.

AD migration and Powershell more fun than…

The life and times of a Active Directory Logon Migration

This blog is going to be about an active directory migration project changing about 2000 user from a named based logon to a employee number based logon. Here are all the changes

  • Change user name to employee number
  • Create new ad structure based on department structure
  • Automate logon creation based on output from HR system
  • Automate ad structure based on output from HR system
  • Automate logon terminations based on output from HR system
  • complete logon information with accurate phone, department, office, address, name, and
  • Migrate users to new 2008 R2 based home folder system using DFS, VSS, and DFS replication
  • Clean home folders of all exe’s and PST files
  • Move all non-employee logons out of the employee OU
  • Automate the creation and disabling of non-employee accounts
  • Disable and eventually delete all non-active logons
  • Automate cleanup of home drives, and email accounts when an account is deleted.

The environment is a 2003 domain and our two tools will be Hyena, windows active directory tools, and Powershell.

Oh all this has to happen with little to no downtime, and without confusing our end users.

Ok been a while

So what is the hardest part of migrating 2200 logons to a new home drives, new logons, and a new directory structure… getting everyone to take the first step. Here is why we had such a long pause:
We planned the best way to make the move
We created the script to make the move happen
We tested the migration and refined it until we could migrate with no unexpected issues
We presented our plan and schedule and… we had to get it approved through management.
So after 30 meetings, answering the questions of why this has to happen over and over everyone now agrees and we can move on.
With that said we started our conversions.
Here is a nifty script we used to find an accurate last logon for all users in a specific OU. Again we are a 2003 domain so we have to check all the domain controllers. This script goes through the domain controllers and picks the latest date.


Clear-Variable time
$NewOU = Read-Host "what do you want the output to be called"
$dcs = get-qadcomputer -SearchRoot '/domain controllers'
$usertofind = get-qaduser -Service '' -sizelimit 0 -SearchRoot ('<domain/ouyouwanttosearch')
$time = (get-date).Addyears(-50) #starting date this one ends up in 1961
$file = ('h:\' + $newou + '.csv')

Foreach ($u in $usertofind)
{
#Get-ADUserLastLogon -UserName $u.samaccountname
foreach($dc in $dcs)
{
#$dc.name
$hostname = $dc.name
$user = get-qaduser -Service $hostname $u.samaccountname
if($user.LastLogon -gt $time)
{
#$user.LastLogon
$time = $user.LastLogon
}
}
$line = $u.samaccountname + ',' + $time + ',' + $u.UserMustChangePassword
add-content $file $line
$time = (get-date).Addyears(-50)

}

And so we created 2200 users in 142 Organizational Units

So we created AD objects with powershell and it was good. While the script took us a little while to create and it probably could have been written better it got the job accomplished. When we are writing scripts I think it is important to remember we are not coders, we are not trying to write the perfect code or resell our code. If the job gets accomplished our script was successful, especially if it does no harm in the process. So when writing AD scripts be less concerned with the perfect code, and more concerned with testing it in a place that will cause no harm.

Once you have a script that will get the job done you can always post the script on line, and trust me people will point out where you went wrong. One good site to use that is helpful without being elitist is … www.scriptinganswers.com

In the Beginning

We did not decide to change our Active Directory (AD) structure,  as much as we were placed in a position where we would be stupid not to change the structure. Our HR/Payroll system wanted to go paperless and to do so each employee would have to have an AD logon. Our logons were based on first initial + lastname + number 1-10. There was no way we could map from the HR/payroll system to our AD and back. So we opted to change everyone to use their employee number, a number that our HR system creates.

Since HR needed the new logons to be done and everyone converted in about 30 days. We opted to create a new logon based on employee number for everyone. Then we could move OU by OU deleting the new employee number logon and changing the users old logon to match. We found this kept us from having to create new profiles. We used a third party webpage software to allow the end user to reset thier own password, since the HR software would not work if we set the account to change password on first login. (note accounts which went unchanged were disabled, we really had to push to get that one)

The following is the powershell script we used to create all the HR accounts needed.


$userimport = Import-Csv h:\csv.csv
$OUroot = 'xxxx.com/OU/'

foreach ( $i in $userimport)
{
$testuserexist = (get-qaduser -samaccountname $i.samaccountname)
if ($testuserexist)
{ "Found " + $i.samaccountname

Add-Content h:\exist.txt ("The Account Already exists : " + $i.samaccountname + "," + $i.lastname)
}
Else
{"Not Found"

$testouexist = (get-qadobject -Name $i.department -type organizationalUnit)
if ($testouexist)
{
}
ELSE
{
Try {
"No OU"
New-QADObject -ParentContainer xxxx.com/OU' -Type 'organizationalUnit' -name $i.department
"The directory does not exist"
}

Catch {
[system.exception]
#Add-Content h:\error.log ("The OU is wrong : " + $i.department)
$fullerror = ( $displayname + "," + $i.title + "," + $i.phonenumber + "," + $i.samaccountname)
add-content h:\error.log $error
add-content h:\error.log $fullerror
$error.clear()
}
Finally {

}
}

$OUlocation = ($OUroot + $i.department)
$password = ($i.samaccountname + $i.password)
$displayname = ("ESS-" + (Get-Culture).TextInfo.ToTitleCase($i.lastname) + ", " + (Get-Culture).TextInfo.ToTitleCase($i.firstname))
Try {
0 + $i.samaccountname | Out-Null
New-qaduser -name $displayname -SamAccountName $i.samaccountname -ParentContainer $OUlocation -userpass $password
get-qaduser -SamAccountName $i.samaccountname | set-qaduser -company $i.Company `
-department $i.department -displayname $displayname `
-lastname $i.lastname -samaccountname $i.samaccountname `
-UserPrincipalName ($i.samaccountname + "@Selfregional.org")
}
Catch {
[system.exception]
#Add-Content h:\error.log ("The user is wrong : " + $i.samaccountname + "," + $i.department + $displayname)
$fullerror = ( $displayname + "," + $i.title + "," + $i.phonenumber + "," + $i.samaccountname)
add-content h:\error.log $error
add-content h:\error.log $fullerror
}
Finally {

$error.clear()

}

Try {
enable-qaduser -identity $i.samaccountname
"User Name : " + $i.samaccountname
Add-Content h:\notexist.txt ("The Account has been Created : " + $i.samaccountname + "," + $i.lastname + "," + $password)
}
Catch {
[system.exception]
#Add-Content h:\error.log ("The user is wrong : " + $i.samaccountname + "," + $i.department + $displayname)
$fullerror = ( $displayname + "," + $i.title + "," + $i.phonenumber + "," + $i.samaccountname)
add-content h:\error.log $error
add-content h:\error.log $fullerror
}
Finally {

$error.clear()

}

}
}

Follow

Get every new post delivered to your Inbox.