Powershell : Scripting OU creation in Active Directory

If you need to create a n OU in the Active Directory that is new (or it does not exist) then this script can help you, it is driven off a file called "ou.txt"

This file needs to be formatted correctly as below, here is an example of that file:

The format for this file is as follows as its driven by the amount of dashes used:

No Dash = Root OU
1 Dash = Sub-OU
2 Dash = Next OU off Sub-OU

If we use the file contents above we will get the structure as shown below based on the dashes, this has been generated by the script with the preview option:



When you are happy with the formatting you can then run option 2 to create the OU structure, as simple as that.


Script : OUCreation.ps1

# Import the Active Directory module
Import-Module ActiveDirectory

# Setup logging
$logFile = "OU_Creation_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

# Function to write to both console and log file
function Write-Log {
    param(
        [string]$Message,
        [string]$Color = "White"
    )   

    # Get current timestamp
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"    

    # Write to console with color
    Write-Host $Message -ForegroundColor $Color    

    # Write to log file (without color formatting)
    "$timestamp - $Message" | Out-File -FilePath $logFile -Append
}

# Function to count leading dashes in a line
function Get-DashLevel {
    param([string]$line)
    if ($line -match '^(-*)') {
        return $matches[1].Length
    }
    return 0
}

# Function to clean OU name (remove dashes and trim)
function Get-CleanOUName {
    param([string]$line)
    return $line -replace '^-+', '' -replace '\s+$', '' -replace '^\s+', ''
}

# Function to preview OU structure
function Show-OUPreview {
    param([string[]]$content)
    Write-Log "`nPreviewing OU Structure:`n" "Cyan"   
    foreach ($line in $content) {
        if ([string]::IsNullOrWhiteSpace($line)) { continue }       
        $level = Get-DashLevel $line
        $ouName = Get-CleanOUName $line        

        # Create indentation based on level
        $indent = "    " * $level
        Write-Log "$indent$ouName"       
        if ($level -eq 0) {
            Write-Log "$indent└─── (Root Level)" "Yellow"
        } elseif ($level -eq 1) {
            Write-Log "$indent└─── (Sub OU)" "Green"
        } else {
            Write-Log "$indent└─── (Nested Sub OU)" "Magenta"
        }
    }
}

# Function to create OUs
function Create-OUStructure {
    param([string[]]$content)   
    Write-Log "Starting OU creation process..." "Cyan"    

    # Stack to keep track of parent OUs
    $ouStack = @()
    $currentLevel = -1   
    foreach ($line in $content) {
        if ([string]::IsNullOrWhiteSpace($line)) { continue }       
        $level = Get-DashLevel $line
        $ouName = Get-CleanOUName $line        

        # Adjust the stack based on the current level
        while ($currentLevel -ge $level) {
            $ouStack.RemoveAt($ouStack.Count - 1)
            $currentLevel--
        }        

        # Create the OU path
        $ouPath = ""
        if ($level -eq 0) {
            # Root level OU
            $ouPath = "DC=bear,DC=local"
        } else {
            # Build the OU path from the stack
            $ouPath = ($ouStack | ForEach-Object { "OU=$_" }) -join ','
            $ouPath += ",DC=bear,DC=local"
        }       
        try {
            # Check if OU already exists
            $existingOU = Get-ADOrganizationalUnit -Filter "Name -eq '$ouName'" -SearchBase $ouPath -ErrorAction SilentlyContinue           
            if (-not $existingOU) {
                Write-Log "Creating OU: $ouName in $ouPath" "Green"
                New-ADOrganizationalUnit -Name $ouName -Path $ouPath -ProtectedFromAccidentalDeletion $true
            } else {
                Write-Log "OU already exists: $ouName in $ouPath" "Yellow"
            }            

            # Update the stack
            $ouStack += $ouName
            $currentLevel = $level           
        } catch {
            Write-Log "Error creating OU '$ouName': $_" "Red"
        }
    }
        Write-Log "`nOU creation complete!" "Cyan"
}

# Main menu function
function Show-Menu {
    Clear-Host
    Write-Log "=== OU Creation Tool ===" "Cyan"
    Write-Log "Current log file: $logFile" "Gray"
    Write-Log ""
    Write-Log "1: Preview OU Structure" "Yellow"
    Write-Log "2: Create OUs" "Green"
    Write-Log "3: View Log File" "Purple"
    Write-Log "4: Exit" "Red"
    Write-Log ""
    Write-Host "Please make a selection (1-4): " -NoNewline
}

# Main script execution
$ouFile = "ou.txt"

# Check if ou.txt exists
if (-not (Test-Path $ouFile)) {
    Write-Log "Error: ou.txt file not found!" "Red"
    Write-Log "Please create an ou.txt file in the same directory as this script." "Yellow"
    exit
}

# Initialize log file with header
"=== OU Creation Tool Log ===" | Out-File -FilePath $logFile
"Script started at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" | Out-File -FilePath $logFile -Append
"" | Out-File -FilePath $logFile -Append

# Read the content once
$content = Get-Content $ouFile

# Menu loop
do {
    Show-Menu
    $selection = Read-Host   
    switch ($selection) {
        '1' {
            Show-OUPreview $content
            Write-Log "`nPress any key to continue..."
            $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
        }
        '2' {
            Write-Log "`nPreparing to create OUs..." "Yellow"
            Write-Log "Are you sure you want to proceed? (Y/N): " -NoNewline
            $confirm = Read-Host           
            if ($confirm -eq 'Y' -or $confirm -eq 'y') {
                Create-OUStructure $content
            } else {
                Write-Log "`nOU creation cancelled." "Yellow"
            }           
            Write-Log "`nPress any key to continue..."
            $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
        }
        '3' {
            Write-Log "`nOpening log file..."
            notepad.exe $logFile
        }
        '4' {
            Write-Log "`nExiting..." "Yellow"
            Write-Log "Script ended at: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" "Gray"
            exit
        }
        default {
            Write-Log "`nInvalid selection. Please try again." "Red"
            Start-Sleep -Seconds 2
        }
    }
} while ($true)

Previous Post Next Post

نموذج الاتصال