How can I create Organizational Units recursively on Powershell?

7,426

Solution 1

As mentioned in the comments by Mike, you'll need to step through each level in the tree and test for the existence of the OUs ancestors, and then create the ones that doesn't exist, from the top-most level and down.

As long as New-ADOrganisationalUnit does not have a -Recurse parameter, this is the most elegant way I could think of:

function New-OrganizationalUnitFromDN
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [string]$DN
    )

    # A regex to split the DN, taking escaped commas into account
    $DNRegex = '(?<![\\]),'

    # Array to hold each component
    [String[]]$MissingOUs = @()

    # We'll need to traverse the path, level by level, let's figure out the number of possible levels 
    $Depth = ($DN -split $DNRegex).Count

    # Step through each possible parent OU
    for($i = 1;$i -le $Depth;$i++)
    {
        $NextOU = ($DN -split $DNRegex,$i)[-1]
        if($NextOU.IndexOf("OU=") -ne 0 -or [ADSI]::Exists("LDAP://$NextOU"))
        {
            break
        }
        else
        {
            # OU does not exist, remember this for later
            $MissingOUs += $NextOU
        }
    }

    # Reverse the order of missing OUs, we want to create the top-most needed level first
    [array]::Reverse($MissingOUs)

    # Prepare common parameters to be passed to New-ADOrganizationalUnit
    $PSBoundParameters.Remove('DN')

    # Now create the missing part of the tree, including the desired OU
    foreach($OU in $MissingOUs)
    {
        $newOUName = (($OU -split $DNRegex,2)[0] -split "=")[1]
        $newOUPath = ($OU -split $DNRegex,2)[1]

        New-ADOrganizationalUnit -Name $newOUName -Path $newOUPath @PSBoundParameters
    }
}

Usage using WHATIF

# The desired resulting OU DN  
$DN = "OU=Helpdesk,OU=IT Dept,OU=Users,DC=local,DC=contoso"
New-OrganizationalUnitFromDN $DN -WhatIf

Without WHATIF

# The desired resulting OU DN  
$DN = "OU=Helpdesk,OU=IT Dept,OU=Users,DC=local,DC=contoso"
New-OrganizationalUnitFromDN $DN

It will break if there are non-existing non-OU containers in the path.

Solution 2

The output of $NextOU.IndexOf("OU=") is case sensitive and will return -1 for all lowercase ou= try: $NextOU.IndexOf("OU=",[StringComparison]"CurrentCultureIgnoreCase")

Share:
7,426

Related videos on Youtube

Maurício Mota
Author by

Maurício Mota

Updated on September 18, 2022

Comments

  • Maurício Mota
    Maurício Mota almost 2 years

    I'm writing a Powershell script to populate all the company users to a Active Directory from a CSV file.

    The script uses the Powershell command New-ADUser and it should know, for every user, where is the path to add them, for example:

    "OU=IT Dept,OU=Users,DC=local,DC=contoso"
    

    The problem is: this Active Directory doesn't have any users yet, so there's no Organizational Units created, and whenever I run the script, if the path doesn't exists, the user is not created.

    I've looked up for a command to create Organizational Units, like New-ADOrganizationalUnit or dsadd, however they do not support recursive creations, like

    "OU=Helpdesk,OU=IT Dept,OU=Users,DC=local,DC=contoso"    
    

    if

    "OU=IT Dept,OU=Users,DC=local,DC=contoso"    
    

    does not exist yet.

    Is there any way of doing that using New-ADOrganizationalUnit?

    Thanks

    • Mike
      Mike almost 10 years
      You could just have it check at each level and create it if it doesn't exist right? Instead of trying to create the whole OU path in one command.
    • Maurício Mota
      Maurício Mota almost 10 years
      Sure, I could do that, in fact that was my plan B, but if there's a "native" way to do that, my script will be simpler.
  • Mathias R. Jessen
    Mathias R. Jessen almost 10 years
    Attribution? I'm not sure I understand. The $OU variable in the last block is assigned from foreach($OU in $MissingOUs). Since we reversed the order of the $MissingOUs array already, It will have these values assigned (in order) 1) "OU=Users,DC=local,DC=contoso", 2) "OU=IT Dept,OU=Users,DC=local,DC=contoso" and finally 3) "OU=HelpDesk,OU=IT Dept,OU=Users,DC=local,DC=contoso". Try to substitute Write-Host for New-ADOrganizationalUnit to see it
  • Maurício Mota
    Maurício Mota almost 10 years
    I'm not sure if i'm doing terribly wrong, but copy and pasting your code and changing only the New-ADOrganizationalUnit to Write-Host not works for me. I'm new to powershell so i'm having some trouble to find the problem. it seems the problem is in the if($NextOU.IndexOf("OU=") -ne 0 -or [ADSI]::Exists("LDAP://$NextOU/")) line.
  • Mathias R. Jessen
    Mathias R. Jessen almost 10 years
    @MaurícioMota Join me in this chat room and I'll try to help you out
  • Vaibhav Panmand
    Vaibhav Panmand almost 3 years
    your answer is unclear and lack of the description, please add some description about link provided in answer, also please refer how-to-answer to write a good answer.