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

Adding a Comment to a GPO with PowerShell

As I'm writing this article, I'm also writing a customization for a PowerShell course I'm teaching next week in Phoenix.  This customization deals with Group Policy and PowerShell.  For those of you who attend my classes may already know this, but I sit their and try to ask the questions to myself that others may ask as I present the material.  I finished up my customization a few hours ago and then I realized that I did not add in how to put a comment on a GPO.  This is a feature that many Group Policy Administrators may not be aware of. This past summer I attended a presentation at TechEd on Group Policy.  One organization in the crowd had over 5,000 Group Policies.  In an environment like that, the comment section can be priceless.  I always like to write in the comment section why I created the policy so I know its purpose next week after I've completed 50 other tasks and can't remember what I did 5 minutes ago. In the Group Policy module for PowerShell V3, th

Return duplicate values from a collection with PowerShell

If you have a collection of objects and you want to remove any duplicate items, it is fairly simple. # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   # Remove the duplicate values. $Set1 | Select-Object -Unique 1 2 3 4 5 6 7 What if you want only the duplicate values and nothing else? # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   #Create a second collection with duplicate values removed. $Set2 = $Set1 | Select-Object -Unique   # Return only the duplicate values. ( Compare-Object -ReferenceObject $Set2 -DifferenceObject $Set1 ) . InputObject | Select-Object – Unique 1 2 This works with objects as well as numbers.  The first command creates a collection with 2 duplicates of both 1 and 2.   The second command creates another collection with the duplicates filtered out.  The Compare-Object cmdlet will first find items that are diffe

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.