Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Thursday, March 10, 2011

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:


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

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

PowerShell V2
Designed to be run on a Domain Controller


Global Varibles

User to hold the user object information

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: Starting"

# Set the error action preference to allow the script to
# continue past non fatal errors.

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

# Execute the functions

# Set the error action preference to continue the script should
# it encounter an error. It will display errors.

# 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.


Dennis Møller said...

I like this Script very much. Very Easy to understand, very easy to use. And it Works perfectly.

Dennis Møller said...

I like this Script very Much. Very Easy to understand, very Easy to use, And it Works Perfectly.