When dealing with Active Directory environments containing thousands of computer objects, administrative tasks like moving accounts between organizational units (OUs) can become time-consuming. In this specific scenario, we need to move 580 computer accounts from one OU to another using only a list of computer names (without FQDNs).
PowerShell provides the most efficient way to handle bulk operations in Active Directory. The ActiveDirectory module offers cmdlets specifically designed for this purpose. Here's why PowerShell is superior to batch files for this task:
- Native AD integration through modules
- Better error handling and logging
- Ability to process input files efficiently
- Support for pipeline operations
Here's a production-ready PowerShell script that accomplishes this task:
# Import required module
Import-Module ActiveDirectory
# Define paths and parameters
$sourceOU = "OU=Computers,DC=domain,DC=com"
$destinationOU = "OU=NewComputers,DC=domain,DC=com"
$computerListFile = "C:\temp\computers.txt"
$logFile = "C:\temp\computer_move_log_$(Get-Date -Format 'yyyyMMdd').csv"
# Initialize log array
$moveResults = @()
# Read computer names from file
$computers = Get-Content $computerListFile
foreach ($computer in $computers) {
try {
# Search for computer in current OU
$computerObj = Get-ADComputer -Filter {Name -eq $computer} -SearchBase $sourceOU
if ($computerObj) {
# Move the computer to new OU
Move-ADObject -Identity $computerObj.DistinguishedName -TargetPath $destinationOU
# Log success
$moveResults += [PSCustomObject]@{
ComputerName = $computer
Status = "Success"
Timestamp = Get-Date
Message = "Moved to $destinationOU"
}
}
else {
# Log failure (computer not found)
$moveResults += [PSCustomObject]@{
ComputerName = $computer
Status = "Failed"
Timestamp = Get-Date
Message = "Computer not found in source OU"
}
}
}
catch {
# Log error
$moveResults += [PSCustomObject]@{
ComputerName = $computer
Status = "Error"
Timestamp = Get-Date
Message = $_.Exception.Message
}
}
}
# Export log to CSV
$moveResults | Export-Csv -Path $logFile -NoTypeInformation
Error Handling and Logging
The script includes comprehensive error handling that:
- Catches individual computer move failures without stopping the entire process
- Logs detailed information about each operation
- Generates a timestamped CSV log file for auditing
Performance Optimization
For large operations (500+ computers), consider these enhancements:
# Process computers in parallel (PowerShell 7+)
$computers | ForEach-Object -Parallel {
Import-Module ActiveDirectory
# Move logic here
} -ThrottleLimit 10
Input File Formatting
The script expects a simple text file with one computer name per line. Example:
WS001
WS002
SRV045
...
For more complex scenarios where you need additional metadata:
$computers = Import-Csv -Path "C:\temp\computers.csv"
foreach ($computer in $computers) {
# Access properties as $computer.Name, $computer.Department, etc.
}
After running the script:
- Spot check several computers in the new OU using AD Users and Computers
- Review the log file for any failures
- Compare count of moved computers against expected number
When managing large Active Directory environments, administrators often need to reorganize computer objects. In this scenario, we have:
- Source OU containing approximately 2,500 computer objects
- Target OU where 580 specific computers need to be moved
- Text file containing simple computer names (without domain suffix)
While batch files can handle basic operations, PowerShell provides superior capabilities for AD management:
# Import ActiveDirectory module
Import-Module ActiveDirectory
# Define paths
$sourceOU = "OU=Computers,DC=domain,DC=com"
$targetOU = "OU=NewComputers,DC=domain,DC=com"
$computerList = Get-Content "C:\temp\computers.txt"
foreach ($computer in $computerList) {
try {
Get-ADComputer -Identity $computer |
Move-ADObject -TargetPath $targetOU
Write-Host "Successfully moved $computer" -ForegroundColor Green
}
catch {
Write-Host "Failed to move $computer : $_" -ForegroundColor Red
}
}
For production environments, consider adding these improvements:
# Add logging functionality
$logFile = "C:\temp\ADMoveLog_$(Get-Date -Format yyyyMMdd).csv"
$results = @()
foreach ($computer in $computerList) {
$result = [PSCustomObject]@{
ComputerName = $computer
Timestamp = Get-Date
Status = $null
Error = $null
}
try {
$computerObj = Get-ADComputer -Identity $computer -ErrorAction Stop
Move-ADObject -Identity $computerObj -TargetPath $targetOU -ErrorAction Stop
$result.Status = "Success"
}
catch {
$result.Status = "Failed"
$result.Error = $_.Exception.Message
}
$results += $result
}
$results | Export-Csv -Path $logFile -NoTypeInformation
For large operations, implement parallel processing:
# Requires PowerShell 7+ for ForEach-Object -Parallel
$computerList | ForEach-Object -Parallel {
Import-Module ActiveDirectory
$computer = $_
try {
$compObj = Get-ADComputer -Identity $computer
Move-ADObject -Identity $compObj -TargetPath $using:targetOU
[PSCustomObject]@{
Computer = $computer
Status = "Moved"
}
}
catch {
[PSCustomObject]@{
Computer = $computer
Status = "Error: $_"
}
}
} -ThrottleLimit 10 | Export-Csv -Path "C:\temp\ParallelResults.csv" -NoTypeInformation
For more complex scenarios with additional attributes:
# CSV format: ComputerName,NewOU,Department
$computers = Import-Csv "C:\temp\computer_moves.csv"
foreach ($item in $computers) {
try {
$computer = Get-ADComputer -Identity $item.ComputerName
Move-ADObject -Identity $computer -TargetPath $item.NewOU
Set-ADComputer -Identity $computer -Department $item.Department
}
catch {
Write-Warning "Error processing $($item.ComputerName): $_"
}
}