Migrating Workstations with SCCM

Sorry I haven’t posted anything lately.  I have been busy getting ready to do a number of domain migrations over the next couple of months.  This has been a major project that I have been involved with at work.  We have a total of 14 AD domains, and I am responsible for migrating 13 child domains into the parent domain.  On average, most of the child domains consist of about 300-600 users. 

In doing this project, I have found that the part involving most of the work is the migration of workstations.  For the first five migrations that we did last year, we used a free tool from Microsoft called Active Directory Migration Tool (ADMT).  We looked at other tools, such as the tool from Quest, but it was extremely expensive.  Since we are doing a intra-forest migration, we felt that ADMT would be adequate.  The one issue we ran into, though, was that if we attempted to migrate large groups of workstations, ADMT would crash.  This left us in an uncertain state and meant a lot of cleanup.  So, we decided to migrate workstations in groups of 25 at a time.

For the first 5 migrations, this method worked ok, but depended on all of the workstations being turned on when we did the actual migration.  Also, we found that the most time consuming part of a migration was the workstations.  Because of this, we had to do the migrations over a weekend meaning more time away from home.  So, we decided to pursue other methods of migrating workstations.

Enter System Center Configuration Manager (SCCM).  One of the other major projects that our team has undertaken this year was the deployment of SCCM, so we decided to leverage SCCM to assist us in migrating workstations.  Since we could migrate the workstations well before we migrate user accounts, we have made a push to migrate all workstations by the middle of February (and finish up the rest of the migrations by the end of June).  As part of this, we developed a script that we push (along with netdom.exe) to each workstation to migrate them.

Let me explain a little bit of what the below script does (although I think you will find it fairly well documented in the comments, as well).  First, we are going to use netdom.exe to perform the actual migration.  Since the workstations are already joined to a domain, we will use the /move command.  We also want to create a file that we can inventory with SCCM to help produce reports.  We are putting an extension of .netdom on this file (as it is not a normal file extension) and adding this as a file type that SCCM inventories.  Note that if there is a failure, we also create a failure file so we can rerun as necessary.

Here is a run through of each of the steps that happens:

  • Checks to see if a special folder exists at the root.  We use this folder to place the success file (as well as other purposes in the domain.)  If it doesn’t exist, it creates it.  If it does it exist, it continues.
  • Next, it checks for the success.netdom file.  If it exists, it exits.  If it doesn’t, it continues.
  • Now it checks for the failure.netdom.  If that file exists, it will delete the file.
  • Now, it pops up a window (that will be auto dismissed after 30 seconds) warning the end user that their computer will be migrating and to close all open programs.
  • Finally, it runs netdom.  The account used (from the configuration block) needs to have the following delegated permissions: to the location in the old domain where the workstation currently is (this enables it to disable the old computer account) and the new OU location where the workstation is being moved to.  Finally, netdom forces the workstation to reboot in five minutes.  This pops up a system dialog box that can not be dismissed by the end user with a countdown time.
  • The script then looks to see if netdom returns a success or failure code.  If it returns a success code, it writes the success.netdom file.  If it fails, it writes the failure.netdom file as well as writing to a remote log file.  I have found various things have caused failure messages.  For example, if the delegation permission is not set properly on the old domain, the computer will be migrated, but netdom will return a failure code as it was unable to disable the old account.  It may also return an error code if there is a DNS failure on the workstation and it is unable to find the new domain.

We have been quite pleased with how well this has worked.  In one of the child domains, we saw 350 workstations migrate in one hour and a total of about 450 by the end of the first day.  All of this was done “hands off”.

We have also made slight modifications to this script so that we can run it as a startup script.  When we do this, we copy netdom.exe locally to the machine (to C:\Netdom ) and modify the netdom command to include the direct path.  This allows us to capture any clients that may not have the SCCM client yet (we are at about 70% of our workstations with the SCCM client).  I also modify the reboot time to 5 seconds so that it happens right away on startup.

I would love to hear any questions people may have about this script and method. 

One issue to note is that you will need to modify the script if any of your OUs, Usernames or Passwords include spaces.  We find it easiest to just remove spaces for the duration of the migration.

‘==========================================================================


‘ NAME: WorkstationMigration.vbs

‘VERSION:  1.5.1
‘MODIFIED:  Doug Neely
‘DATE:  01/21/09
‘       Originally created script for Workstation Migration
‘        I have modified this script to work slightly different due to how SCCM works
‘       

‘ This script will be run via an SCCM task. 
‘ Steps:   Script will first look to see if C:\NETDOM exists.  If it doesn’t, it creates it.
‘                Next, it looks to see if success.netdom exists.  If it does, it quits the script.
‘                If success.netdom doesn’t exist, it continues and looks for failure.netdom.  If it exists, it deletes it.
‘                Finally, it runs the netdom command. 
‘                    If the netdom command returns anything other than success, it will create a file called failure.netdom. 
‘                        It will also put information into a central log file noting failures.
‘                    If it returns success, it creates the success.netdom file.’
‘Netdom options
‘        move
‘        %computername%
‘        /Domain:usw /OU:ou=workstations,ou=us,dc=contoso,dc=org
‘==========================================================================

const forReading = 1
const forWriting = 2
const forAppending = 8

Dim strDC, strNewOU, strSuccess
Dim strComputer, strTSA, strTasks, Shellcmd
Set objFSO = CreateObject ("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem")
For Each objItem In colItems
  computername = objItem.Name
Next

‘==========================================================================
‘CONFIGURATION BLOCK

‘Local DC
strDC = "usadc01.contoso.org"
strDomain = "contoso.org"

‘What is the new OU to put this object into.  This will just be the command name
strNewOU = "ou=workstations,ou=us,dc=contoso,dc=org"
strSuccess = "c:\NETDOM\Success.netdom"
strFailure = "c:\NETDOM\Failure.netdom"
strFailRemote = "\\" & strDC & "\netdom$\NetdomFailure.log"
strTSA = "c:\NETDOM"
strNetdom = "c:\NETDOM\netdom.exe"
strCopyNetdom = "\\" & strDC & "\netlogon\netdom.exe"
strUser = "CONTOSO\csNetdom"
strPassword = "SuperSecretPasswordHere"
Shellcmd = "netdom.exe move %computername% /Domain:contoso.org /OU:" & strNewOU & " /UserD:" & strUser & " /PasswordD:" & strPassword & " /UserF:" & strUser & " /PasswordF:" & strPassword & " /REBoot:300"
‘==========================================================================
‘This will first check to see if C:\TSA exists.  If it does not, it will create the folder
If Not objFSO.FolderExists(strTSA) Then
    Set objFolder = objFSO.CreateFolder(strTSA)
Else
End If
‘This now checks for the Success file.  If it exists, it does nothing.
If objFSO.FileExists(strSuccess) Then
    ‘Do Nothing
Else
    ‘This will check for the failure file
    If objFSO.FileExists(strFailure) Then
        objFSO.DeleteFile strFailure
    Else
    End If
    Set WshShell = CreateObject("WScript.Shell")
    intbutton = WshShell.Popup("Your computer is now being joined to the CONTOSO domain. Please close all open programs as the computer will restart at completion.", 30, "Computer migrating to CONTOSO domain.", 0 + 48)
    ‘Next, it will run netdom
    ND = objShell.Run(Shellcmd,,True)

    If ND <> 0 Then
   ‘This will create a failure file both locally and a message to a log file remotely
        Set objFile = objFSO.CreateTextFile(strFailure, False)
        objFile.Close
        set oFsOutput = createobject("scripting.filesystemobject")
        set oTextOutput = oFsOutput.OpenTextFile(strFailRemote, forAppending, true)
        oTextOutput.WriteLine computername & "," & Now & ",Netdom Failed"
        oTextOutput.Close
    ‘Since this creates a failure file, we will now run an inventory on this machine.
    ‘If the machine has the failure.netdom file on it, it will be put into an autocollection.
    ‘This autocollection will rerun this script with a couple of mandatory deployment times.

    Else
    ‘Finally, we will create a success file.  We will inventory this file with SCCM so we can verify success.
    Set objFile = objFSO.CreateTextFile(strSuccess, False)
    objFile.Close
    End If
End If