Skip to main content

How to take a list of user accounts located in different OUs and move them into one with PowerShell

In smaller environments, you will from time to time need to move user accounts from one Organizational unit to another.  Active Directory Users and Computers will work fine for this task. In larger environments, you may need to move hundreds at a time.  Using AD Users and Computers for a task like this is inefficient and will greatly increase the labor cost of the project.  The labor being yours of course.

This question came from one of my Windows 2008 Server classes.  It actually came as a question from a lab as to whether or not PowerShell could do this.  Not only can it do this, bit it can do it much faster and in a more robust way then the manual method.

To set this problem up, I created the OU structure below:

image

I have 3 users each in the Indianapolis, Denver, and Tampa OU.  I want to move 6 of those nine users into the Dallas OU.  This is a very small move.  Scale this problem out to 9,000 total users with 6,000 of them needing to be moved.  now we have a problem.  The script at the bottom will work for larger environments.

You first need to obtain a list in a text file of the users whom you need to move.  Below is our list:

Neil Armstrong
Buzz Aldrin
George Washington
Barbara Bush
John Doe
Jane Doe


All we need to do is to read this into PowerShell and have it move those user object to the new OU.  What fun would this be to leave it at that.  We need to provide some error checking and a report of any user accounts that were not found.  Let’s start with the basics.  How to move a user account from one OU to another.

I first open the PowerShell environment and imported the Active Directory cmdlets by typing import-Module ActiveDirectory.

Next I user the Get-ADUser cmdlet to grab the object of one of those user accounts.  I also assign it to the variable $UserAccount.

$UserAccount = Get-ADUser –Filter {Name –like “George Washington”}

The property of the user object called DistinguishedName will have the LDAP path to the user account, CN=George Washington, OU=Denver, DC=MCTNet, DC=com, which is the format needed for our next cmdlet.

Our next step is to move the user object to the new OU using the Move-ADObject cmdlet.

Move-ADObject $UserAccount.DistinguishedName –TargetPath “OU=Dallas,DC=MCTNet,DC=com”

Now let’s turn this into a script that will handle thousands of moves automatically and keep track of any problems.

<#
===========================================================
Script Name: MoveUsers.ps1
Author: Jason A. Yoder, MCT
Website: www.MCTExpert.com
Blog: www.MCTExpert.Blogspot.com
===========================================================

===========================================================
Script Purpose:
Demonstrate how to take a list of user names and move them
to a specified OU.  This script will also create a list
of any user accounts that were not found in Active
Directory
===========================================================


===========================================================
Requirements:
PowerShell V2
Designed to be run on a Domain Controller

===========================================================

===========================================================
Global Varibles

$UserAccount
User to hold the user object information

$UserList
Holds the list of user names from the text file.
#>

$ScriptPath = "E:\MoveUsers"
# The file path where all the scripts files are stored.

$UserListFile = "UserList.txt"
# File name of the the document holding the user names.

$TargetOU = "OU=Dallas,DC=MCTNet,DC=com"
# The target OU where you want the user accounts to
# be moved to.

$ErrorLog = "ErrorLog.txt"
# Text file that stores the error data.

$ErrorCount = 0
# Holds the number of errors the script experienced.

# == End of Global Variables ================================

# ===========================================================
# Functions

Function Prep-ErrorLog{
# Clears the error log and places a header in it.
# Line 1 Captures the current date/time
# Line 2 Creates the text of the header. Lines 3 and 4
# are part of that header.
# Line 5 clears the contents of the error log and writes the header.

    $Date = get-date
    $Header = "Error log for MoveUsers.ps1 `r
    Startdate $Date `r
    ======================================"
    Set-Content -Path $ScriptPath\$Errorlog -Value $Header

}
# --End of Function: Prep-ErrorLog--------------------------

Function Get-UserNames {
# Places the contents of the user list text file into the
# variable $UserList.
    $Global:UserList = Get-Content -Path $ScriptPath\$UserListFile
}
# --End of Function: Get-UserNames--------------------------

Function Move-UserAccounts ($UserList){
    # The for loop will cycle through each name from the
    # UserList.
    For ($i = 0; $i -lt $UserList.Count; $i++){
   
        # Get the User object that matches the user name
        # from the list.
        $TestName = $UserList[$i]
        $UserAccount = Get-ADUser -Filter{Name -like $TestName}
      
        # Move the User Object to the designated OU.
        Move-ADObject $UserAccount.DistinguishedName -TargetPath $TargetOU
        
        # If an error occurs, write it to the error log.
        If($? -eq $False) {
           
            # Error log text string.
            $ErrorText = "User $TestName not found in Active Directory"
           
            # Append the error log string to the error log file.
            Add-Content -Path $ScriptPath\$Errorlog -Value $ErrorText
           
            # Increment the Error Count variable.
            $Global:ErrorCount = $Global:ErrorCount+1
        }
    }
}
# --End of Function: Move-UserAccounts-----------------------

# == End of Functions =======================================
# ===========================================================
# Main Code:

# Write text to the screen to let the user know the script
# has started.
Write-Host "Script: MoveUser.ps Starting"

# Set the error action preference to allow the script to
# continue past non fatal errors.
$ErrorActionPreference="SilentlyContinue"

# Load the Active Directory module for PowerShell.
Import-Module ActiveDirectory

# Execute the functions
Prep-ErrorLog
Get-UserNames
Move-UserAccounts($UserList)

# Set the error action preference to continue the script should
# it encounter an error. It will display errors.
$ErrorActionPreference="Continue"

# Inform the user the script has complete with a count
# of the errors encountered.
Write-Host "Script Completed with $ErrorCount errors."

# == End of Main Code =======================================

The format for the UserList.txt is just the users First and Last name.  One entry per line.

Comments

Unknown said…
I like this Script very much. Very Easy to understand, very easy to use. And it Works perfectly.
Unknown said…
I like this Script very Much. Very Easy to understand, very Easy to use, And it Works Perfectly.

Popular posts from this blog

How to list all the AD LDS instances on a server

AD LDS allows you to provide directory services to applications that are free of the confines of Active Directory.  To list all the AD LDS instances on a server, follow this procedure: Log into the server in question Open a command prompt. Type dsdbutil and press Enter Type List Instances and press Enter . You will receive a list of the instance name, both the LDAP and SSL port numbers, the location of the database, and its status.

How to run GPResult on a remote client with PowerShell

In the past, to run the GPResult command, you would need to either physically visit this client, have the user do it, or use and RDP connection.  In all cases, this will disrupt the user.  First, you need PowerShell remoting enabled on the target machine.  You can do this via Group Policy . Open PowerShell and type this command. Invoke-Command –ScriptBlock {GPResult /r} –ComputerName <ComputerName> Replace <ComputerName> with the name of the target.  Remember, the target needs to be online and accessible to you.

Error icon when creating a GPO Preference drive map

You may not have an error at all.  Take a look at the drive mapping below. The red triangle is what threw us off.  It is not an error.  It is simply a color representation of the Replace option of the Action field in the properties of the drive mappings. Create action This give you a green triangle. The Create action creates a new mapped drive for users. Replace Action The Replace action gives you a red triangle.  This action will delete and recreate mapped drives for users. The net result of the Replace action is to overwrite all existing settings associated with the mapped drive. If the drive mapping does not exist, then the Replace action creates a new drive mapping. Update Action The Update action will have a yellow triangle. Update will modify settings of an existing mapped drive for users. This action differs from Replace in that it only updates settings defined within the preference item. All other settings remain as configured on the mapped drive. If the