AD Migration/User Object Changes - Combining Before & After Hash Tables?

We’re doing a AD migration soon, and I’m hoping to gather the users AD before/after information into one final hash table.

The logic I’m going with is gathering each user’s AD information prior to the actual migration in one hash table, then get their AD information again after they’re migrated, and hopefully join the two hashes together into one nice OGV.

The examples I’ve found on the 'net show more of combining hashes with like keys and unique values. I’m wanting to combine unique keys and unique values.

Can anyone offer any tips on how I might join the $userInfo and $newUserInfo hashes?

function Set-EADProperties
{

	Import-Module ActiveDirectory
	$userADList = Get-ADUser -SearchBase "ou=example,dc=contoso,dc=com" -Properties Surname, DistinguishedName, GivenName, SamAccountName, Description, HomeDirectory, Department -Filter { Department -like "*IBD*" } | sort Surname 

	$groupOfUsers = @()
	
	foreach ($individualUser in $userADList)
	{
		#Gather variables
		$samaccountName = $individualUser.samaccountname
		$distinguishedName = $individualUser.distinguishedName
		$firstName = $individualUser.GivenName
		$lastName = $individualUser.Surname
		$firstNameDotLastName = "$firstName.$LastName"
		$userInfo = [ordered]@{
			LastName = $lastName
			FirstName = $firstName
			OldUserName = $individualUser.SamAccountname
			OldHomeDirectory = $individualUser.HomeDirectory
		}
		#rename samaccounts to rename fs12 folder name to match first.last, change samaccountname, displayname, and clear profile path attribute.
		#finally move to new OU
		if ($samAccountName -ne $firstNameDotLastName)
		{
			#Close open files
			Invoke-Command -ComputerName fileserver12 -ScriptBlock { openfiles /disconnect /a $using:samaccountName }
			#Do Work	
			Get-ADUser $samAccountName | Set-ADUser -SamAccountName $firstNameDotLastName -DisplayName "$lastName, $firstname - ARS" -HomeDirectory $null -PassThru | Rename-ADObject -Identity $distinguishedName -NewName "$lastName, $firstname - ARS" | Move-ADObject -TargetPath "ou=new,ou=example,dc=contoso,dc=com" -WhatIf
		}
	Start-Sleep 15

	$newuserADList = Get-ADUser -SearchBase "ou=new,ou=example,dc=contoso,dc=com" -Properties Surname, GivenName, SamAccountName, Description, HomeDirectory, Department -Filter { Department -like "*IBD*" } | sort Surname 
	
	$newgroupOfUsers = @()
	foreach ($newindividualUser in $newuserADList)
	{
		#Gather variables
		$newsamaccountName = $newindividualUser.samaccountname
		$newfirstName = $newindividualUser.GivenName
		$newlastName = $newindividualUser.Surname
		$newfirstNameDotLastName = "$newfirstName.$newLastName"
		$newuserInfo = [ordered]@{
			LastName = $newlastName
			FirstName = $newfirstName
			OldUserName = $newindividualUser.SamAccountname
			NewUserName = $newfirstNameDotLastName
			NewHomeDirectory = $newindividualUser.HomeDirectory
		}
	}
	
	#>
	}
	
	$groupOfUsers += New-Object -TypeName PSObject -Property $userInfo
	$newgroupOfUsers += New-Object -TypeName System.Management.Automation.PSObject -property $newuserInfo
	Get-ADUser -Properties DistinguishedName -filter * | where { $_.Surname -like $lastName -AND $_.GivenName -like $firstname } | Select Name, SamAccountName, DistinguishedName
	
	
	$groupOfUsers | ogv -Title "Old User Info"
	$newgroupOfUsers | ogv -Title "New User Info"
}

The below function courtesy of (Merging hashtables in PowerShell: how? - Stack Overflow)

$Hash1 = @{
    First = "Bob";
    Last = "Smiley";
    UName = "bsmiley"
    HDir = "Path1"
}

$Hash2 = @{
    First = "Bob";
    Last = "Smiley";
    NewUName = "smileyb"
    NewHDir = "Path2"
}

function mergehashtables($htold, $htnew)
{
    $keys = $htold.getenumerator() | foreach-object {$_.key}
    $keys | foreach-object {
        $key = $_
        if ($htnew.containskey($key))
        {
            $htold.remove($key)
        }
    }
    $htnew = $htold + $htnew
    return $htnew
}

mergehashtables($Hash1, $Hash2)

Results:

Name                           Value                                                                                                                                                                                            
----                           -----                                                                                                                                                                                            
UName                          bsmiley                                                                                                                                                                                          
Last                           Smiley                                                                                                                                                                                           
First                          Bob                                                                                                                                                                                              
HDir                           Path1                                                                                                                                                                                            
NewUName                       smileyb                                                                                                                                                                                          
Last                           Smiley                                                                                                                                                                                           
NewHDir                        Path2                                                                                                                                                                                            
First                          Bob

This is exactly what I’m looking for. Thanks!

I can’t tell you how many times I used Join-Object (mish mash of code from Dave Wyatt and Lucio Silveira) when designing our migration processes. One of the key pieces is that you can add a prefix or suffix to properties in one collection, helping ensure you have unique keys and don’t lose any data.

On a side note, the logic in your code might be a bit off. Tied up with life-events, but I think I see a loop generating new user details, added to an array outside of the loop (i.e. array will give you the last one only)? Also, you mentioned unique keys; if this is for user info, those aren’t going to be unique (e.g. firstname).

Good luck! Migrations are fun : )

@Warren Frame

Yep - you nailed it. Everything during the migration I ran last night worked fine, except the PSObject creation to generate the report in OGV. It just had my last users info.

I always forget to generate the PSObject within the foreach loop.

Will this work?

$psObjectCollection = @()
foreach ($newindividualUser in $newuserADList)
{
	Write-Debug "Gathering post migration details"
	$newsamaccountName = $newindividualUser.samaccountname
	$newfirstName = $newindividualUser.GivenName
	$newlastName = $newindividualUser.Surname
	$oldDisplayName = $individualUser.Name
	$newDisplayName = $newindividualUser.Name
	$newfirstNameDotLastName = "$newfirstName.$newLastName"
	$newuserInfo = [ordered]@{
		LastName = $newlastName
		FirstName = $newfirstName
		NewSamAccountName = $newsamaccountName
		OldSamAccountName = $individualUser.SamAccountname
		NewDisplayName = $newDisplayName
		OldDisplayName = $oldDisplayName
		NewHomeDirectoryAttribute = $newindividualUser.HomeDirectory
		OldHomeDirectoryAttribute = $individualUser.HomeDirectory
		NewPhysicalHomeDrivePath = $newpath
		OldPhysicalHomeDrivePath = $oldpath
		NewDistinguishedName = $newindividualUser.DistinguishedName
		OldDistinguishedName = $individualUser.DistinguishedName
	}
}#end new user foreach
$psObject = New-Object -TypeName System.Management.Automation.PSObject -property $newuserInfo
$PSObjectCollection += $PSObject


Write-Debug "Creating Results Output"
$psobjectCollection | ogv -Title "Migration Results"