Intra-Forest Migration with duplicate active user accounts in Source and target domains–focus on scripting Profile Translation

Hey everybody, I hope all is well.  This month an interesting situation I came across while working with a customer. Let’s set the scene:

Bit of Background

In the ideal Intra-Forest migration you are consolidating accounts and resources from one domain to another.  The main difference between inter-forest and intra-forest migration is that in intra-forest accounts move (not copy).  How does this create a problem for what I was doing? Well, users in the source domain also had exactly the same SAMAccount name in the target domain and both these accounts are in active use by the same user. All resource access is performed using group access in both source and target domains.

Since the objective of the consolidation is to use the target domain, the majority of the applications users access including Exchange are accessed using the existing account in the target domain, so the target user account will be the account that will be used by all users after consolidation.

Ok, you may say, ADMT has a merge option for migrating user accounts – but this is not available for intra-forest migration. So we can’t do that.  So, what can we do?

Migration Strategy

So the migration strategy that we decided on was as follows:

1) Convert all Global Groups in Source domain to Universal Groups

2) Migrate these Groups to the Target domain

3) Add Target domain “duplicate” accounts to the migrated universal groups

4) Migration Workstation to target domain using ADMT

5)Translate User profile to allow the target account to use the source users profile

6)Migrate Server resources using ADMT.

So steps 1,2,3,4 and 6 are straightforward and can be performed using simple administrative procedures or ADMT, step 5 is not straightforward and this is what the remainder of this post will discuss.

Translating the user profile

This step becomes an issue because normally we would use ADMT to translate the ACLs and profile.  Since we haven’t ADMT’d the user account, when we log on to the workstation with the target account it creates a new profile – this is not what we want.  We want the user to log on to the workstation with the target domain user account and get the profile that they had when they were logging on with the source domain account.

We can do this manually but for a lot of users this means a lot of desktop interaction, testing and making sure that users profile is there.  Ideally as part of the migration process we want this as automated as possible.

Scripting the translation

So I wanted to find a way of scripting this process. So I did a search on the internet and found the following article which did the bulk of what I wanted to do for me.

https://www.pcreview.co.uk/forums/thread-112155.php

It was published back in 2004 and a lot of work was done to get the profile translation right.  In that case, the scenario was translating a workgroup account to allow a new workgroup user to access an existing profile.  So some work needed to be done make it work in an intra-forest migration scenario. The script is principally targeting Windows XP clients. Some work still needs to be done to simplify it and make it work the way we want – but it works!

The script

The script is in the form of a batch file that should be executed using an administrative account as follows:

profiler.bat <target NetBIOS domain Name> <username>

In the script you will notice <srcdomain> – this is the NetBIOS name of the source domain and a reference to a usertosid.vbs script as well as other utilities subinacl and setacl.

The content of the batch file is follows:

subinacl /subdirec “c:\documents and settings\%2” /setowner=%1\%2
subinacl /subdirec “c:\documents and settings\%2 /replace=<srcdomain>\%2=%1\%2
subinacl /subdirec “c:\documents and settings\%2\*.*” /setowner=%1\%2
subinacl /subdirec “c:\documents and settings\%2\*.* /replace=<srcdomain>\%2=%1\%2
c:\windows\system32\reg load hku\script_user “c:\documents and settings\%2\ntuser.dat”
setacl users\script_user /registry /grant %1\%2 /full /r:cont_obj /silent
c”\windows\system32\reg unload hku\script_user
for /f %%1 in (‘cscript /nologo usertosid.vbs “%2”’) do set sid=%%i
echo Windows Registry Editor Version 5.00 > temp.reg
echo. >> temp.reg
echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\%sid%] >> temp.reg
echo “ProfileImagePath”=”c:\\documents and settings\\%2” >> temp.reg
echo. >> temp.reg
regedit /s temp.reg
del temp.reg

Batch File Components

subinacl is a Microsoft utility,the package should be installed on the system running the script and can be found here, :

https://www.microsoft.com/downloads/en/details.aspx?FamilyID=e8ba3e56-d8fe-4a91-93cf-ed6985e3927b&displaylang=en

setacl is a third party utility and should be in the folder where the script is being run and can be found here:

https://helgeklein.com/download/

(note that hopefully I will use subinacl to replace this command in a future update)

usertosid.vbs

This script is based on this post: https://www.winvistatips.com/re-get-user-sid-t749526.html

and as is listed as follows:

' user2sid.vbs
'
' Author: MagicWorm
' https://magicw.secuz.org
' Date: 2003-08-22
''''''''''''''''''''''''''''''''''''
Const GENERAL_FAILURE = 2
Dim ArgObj ' Object which contains the command line argument
Dim Args(10) ' Array that contains all of the non-global arguments
Dim ArgCount ' Tracks the size of the Args array
Dim strComputer
Dim Account
Set ArgObj = WScript.Arguments
If ArgObj.Count < 1 or ArgObj.Count >2 Then
DisplayHelpMessage
WScript.Quit (GENERAL_FAILURE)
End If
Select Case ArgObj.Count
Case 1
strComputer = "."
Account = argObj(0)
Case 2
strComputer = argObj (0)
Account = argObj(1)
End Select

On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Account where Name = '" & Account & "'" )
For Each objItem in colItems
Wscript.Echo objItem.SID
Next

''''''''''''''''''''''''''''
'
' Display Help Message
'
''''''''''''''''''''''''''''
Sub DisplayHelpMessage()
WScript.Echo
WScript.Echo UCase(WScript.ScriptName) & " By MagicWorm"
WScript.Echo "https://magicw.secuz.org"
WScript.Echo String(80, "_")
WScript.Echo "The goal of the utility is to obtain SID from the account
name, usage:"
WScript.Echo
WScript.Echo UCase(WScript.ScriptName) & " [computer_name]
account_name"
WScript.Echo
WScript.Echo "where computer_name is optional. By default, the search"
WScript.Echo "starts at a local Windows NT computer."
End Sub

I have replaced the section

On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Account where Name = '" & Account & "'" )
For Each objItem in colItems
Wscript.Echo objItem.SID
Next

with

On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objaccount = objWMIServce.Get(“Win32_UserAccount.Name=’”& Account &”’, Domain=’<targetdomain>’”)
Wscript.Echo objaccount.SID
Next

This replacement I got from The Scripting Guys

https://blogs.technet.com/b/heyscriptingguy/archive/2004/12/03/how-can-i-determine-the-sid-for-a-user-account.aspx

The reason this replacement was made is because the original script finds the SID of the computer as well, I don’t want that, I want the SID of account in the target domain.

Explaining What the Script does to the Profile:

subinacl /subdirec “c:\documents and settings\%2” /setowner=%1\%2
subinacl /subdirec “c:\documents and settings\%2 /replace=<srcdomain>\%2=%1\%2
subinacl /subdirec “c:\documents and settings\%2\*.*” /setowner=%1\%2
subinacl /subdirec “c:\documents and settings\%2\*.* /replace=<srcdomain>\%2=%1\%2

This section sets the owner of the target account on the profile and replaces the SID from the source domain with the SID of the account from the target domain

c:\windows\system32\reg load hku\script_user “c:\documents and settings\%2\ntuser.dat”
setacl users\script_user /registry /grant %1\%2 /full /r:cont_obj /silent
c”\windows\system32\reg unload hku\script_user

This section sets permissions on NTUser.dat for the profile

for /f %%1 in (‘cscript /nologo usertosid.vbs “%2”’) do set sid=%%i
echo Windows Registry Editor Version 5.00 > temp.reg
echo. >> temp.reg
echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\%sid%] >> temp.reg
echo “ProfileImagePath”=”c:\\documents and settings\\%2” >> temp.reg
echo. >> temp.reg
regedit /s temp.reg
del temp.reg

This section sets the SID of the target domain account in the profilelist in the registry.  This must be in the registry or a new profile will be generated.

Summary

So this is the first effort I’ve put together for the script that works, There does need to be some changes around automation but it works very nicely.  Users can log on with the new account and get their old profile with absolutely no issues and that was primarily the goal.  If any updates are done to the script I will post updates.

I hope people who come across this post find it useful.

Cheers

Jon