Solved

Powershell AD OU Structure from csv file

Posted on 2010-08-17
12
4,469 Views
Last Modified: 2012-05-10
Im trying to create a script to do two things first is to  create an OU structure using the following formatted into a CSV File

Domain,First Level OU,SecondLevel  OU ,Third Level OU,Final OU name
Domain.com,UserOU,SALes,,Internal
Domain.com,UserOU,SALes,,External
Domain.com,UserOU,Accounts,Internal,Pats team
Domain.com,UserOU,Accounts,external,Freds Team
Domain.com,UserOU,,,IT Team
Domain.com,UserOU,,,Comms team
Domain.com,UserOU,Finace,Ledgers,Mikes Team
Domain.com,UserOU,Fiance,auditors,Annes Team

as you can see the OU's end at various levels

then the scritp is to create a group for each OU

so an example in the finance OU would be two groups "Ledgers" and Auditors"
 and in the OU Ledgers a group called "Mikes Team"

hope this makes sence to you

Mike
0
Comment
Question by:MikeEdd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
12 Comments
 
LVL 11

Expert Comment

by:RickSheikh
ID: 33455044
See if this may help http://powershellcommunity.org/Forums/tabid/54/aff/4/aft/3896/afv/topic/Default.aspx

I recommend using the Quest cmdlets.
0
 

Author Comment

by:MikeEdd
ID: 33455228
Thanks
But I dont think it helps me (unless I cant see it) with the recursive creation. I could use that method but it would fail and error.

as some of the ou's are only 2 deep while others are 4 deep ect...
(need to go 7 levels deep in production)

The test script ive created so far is able to create the end OU only if the structure is already in place!
but I need to create the structure from scratch and then populate it with groups based on OU names and then eventually Users
Ive done this in my test enviroment by tweaking the csv file, but in production enviroment this isnt possible as its based on a HR output which I dont want to have to edit

0
 
LVL 42

Expert Comment

by:sedgwick
ID: 33455919
i changed the csv header to have no spaces:domain,FirstLevelOU,SecondLevelOU,ThirdLevelOU,FinalOUnamedomain.com,UserOU,SALes,,Internaldomain.com,UserOU,SALes,,Externaldomain.com,UserOU,Accounts,Internal,Pats teamdomain.com,UserOU,Accounts,external,Freds Teamdomain.com,UserOU,,,IT Teamdomain.com,UserOU,,,Comms teamdomain.com,UserOU,Finace,Ledgers,Mikes Teamdomain.com,UserOU,Fiance,auditors,Annes Team
function Test-QADObject {
 param($Identity)

 (Get-QADObject $Identity -DontUseDefaultIncludedProperties `
  -WarningAction SilentlyContinue -ErrorAction SilentlyContinue `
  -SizeLimit 1) -ne $null
}

$dataSource = import-csv "c:\temp\ou.csv"
foreach ($dataRecord in $dataSource){
	#Domain,FirstLevelOU,SecondLevelOU,ThirdLevelOU,FinalOUname

	$Domain = $dataRecord.Domain
	$FirstLevelOU = $dataRecord.FirstLevelOU
	$SecondLevelOU = $dataRecord.SecondLevelOU
	$ThirdLevelOU = $dataRecord.ThirdLevelOU
	$FinalOUname = $dataRecord.FinalOUname

	$Connection = ($Domain.Replace(".",",DC=")).Insert(0,"LDAP://DC=")
	$AD = [adsi] $Connection
	$Identity = $Connection.Replace("LDAP://", "ou=" + $FirstLevelOU + ",")
	$ldap=$Connection
	
	if((Test-QADObject $Identity) -eq $false){
		$OU = $AD.Create("OrganizationalUnit", "ou=" + $FirstLevelOU)
		$OU.SetInfo()
		$ldap=$OU.Path
	}else{
		$ldap = $ldap.Replace("LDAP://", "LDAP://ou=" + $FirstLevelOU + ",")
	}
	
	if ($SecondLevelOU.Trim().Length -ne 0){
		$Identity = $ldap.Replace("LDAP://", "ou=" + $SecondLevelOU + ",")
		
		if((Test-QADObject $Identity) -eq $false){
			$AD = [adsi] $ldap
			$OU = $AD.Create("OrganizationalUnit", "ou=" + $SecondLevelOU)
			$OU.SetInfo()
			$ldap=$OU.Path
		}else{
			$ldap = $ldap.Replace("LDAP://", "LDAP://ou=" + $SecondLevelOU + ",")
		}
	}
	
	if ($ThirdLevelOU.Trim().Length -ne 0){
		$Identity = $ldap.Replace("LDAP://", "ou=" + $ThirdLevelOU + ",")
		
		if((Test-QADObject $Identity) -eq $false){
			$AD = [adsi] $ldap
			$OU = $AD.Create("OrganizationalUnit", "ou=" + $ThirdLevelOU)
			$OU.SetInfo()
			$ldap=$OU.Path
		}else{
			$ldap = $ldap.Replace("LDAP://", "LDAP://ou=" + $ThirdLevelOU + ",")
		}
	}
	
	if ($FinalOUname.Trim().Length -ne 0){
		$Identity = $ldap.Replace("LDAP://", "ou=" + $FinalOUname + ",")
		
		if((Test-QADObject $Identity) -eq $false){
			$AD = [adsi] $ldap
			$OU = $AD.Create("OrganizationalUnit", "ou=" + $FinalOUname)
			$OU.SetInfo()
		}
	}
}

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 71

Expert Comment

by:Chris Dent
ID: 33457492

Hey guys!

Just so you know, DirectoryEntry (the [ADSI] thing) has a static method called Exists. Just like this:

[ADSI]::Exists("LDAP://OU=Somewhere,DC=domain,DC=com")

That'd replace Test-QADObject. Otherwise I recommend switching to New-QADObject to create. Only for the sake of consistency you see :)

And I reckon you can avoid the hard-coding of level if you treat it as text instead of CSV.

Perhaps... haven't tested it beyond text processing :)

HTH

Chris
$Import = Get-Content test.csv

# Loop through the file
For ($i = 1; $i -lt $Import.Count; $i++) {

  # Split the line and discard empty entries
  $OUs = $Import[$i].Split(",", [StringSplitOptions]::RemoveEmptyEntries)

  # Set the starting point
  $NewPath = "dc=domain,dc=com"

  # Loop through the line
  For ($j = 1; $j -lt $OUs.Count; $j++) {

    # Current is the last NewPath value
    $CurrentPath = $NewPath

    # Prefix the current column
    $NewPath = "ou=$($OUs[$j]),$NewPath"

    If (!([ADSI]::Exists("LDAP://$NewPath")) {
      Write-Verbose "Creating $NewPath"

      # Doesn't already exist. Make it.
      $OU = ([ADSI]"LDAP://$CurrentPath").Create("organizationalUnit", "ou=$($OUs[$j])")
      $OU.SetInfo()
    }
  }
}

Open in new window

0
 
LVL 71

Expert Comment

by:Chris Dent
ID: 33457869

I missed out Group creation. I've added that here.

I think this is right, has a bug fix or two for the above as well.

Chris
$Import = Get-Content test.csv

# Loop through the file
For ($i = 1; $i -lt $Import.Count; $i++) {

  # Split the line and discard empty entries
  $OUs = $Import[$i].Split(",", [StringSplitOptions]::RemoveEmptyEntries)

  # Set the starting point
  $NewPath = "dc=domain,dc=com"

  # Loop through the line
  For ($j = 1; $j -lt $OUs.Count; $j++) {

    # Current is the last NewPath value
    $CurrentPath = $NewPath

    # Prefix the current column
    $NewPath = "ou=$($OUs[$j]),$CurrentPath"
    $GroupPath = "cn=$($OUs[$j]),$CurrentPath"

    If (!([ADSI]::Exists("LDAP://$NewPath"))) {
      Write-Verbose "Creating OU: $NewPath"

      # Doesn't already exist. Make it.
      $OU = ([ADSI]"LDAP://$CurrentPath").Create("organizationalUnit", "ou=$($OUs[$j])")
      $OU.SetInfo()
    }
    If (!([ADSI]::Exists("LDAP://$GroupPath"))) {
      Write-Verbose "Creating Group: $GroupPath"

      $Group = ([ADSI]"LDAP://$CurrentPath").Create("group", "cn=$($OUs[$j])")
      $Group.Put("sAMAccountName", "$($OUs[$j]) -Replace ' ')")
      $Group.SetInfo()
    }
  }
}

Open in new window

0
 
LVL 71

Accepted Solution

by:
Chris Dent earned 500 total points
ID: 33458021

Sorry, still bugs..

Chris
$Import = Get-Content test.csv

# Loop through the file
For ($i = 1; $i -lt $Import.Count; $i++) {

  # Split the line and discard empty entries
  $OUs = $Import[$i].Split(",", [StringSplitOptions]::RemoveEmptyEntries)

  # Set the starting point
  $NewPath = "dc=domain,dc=com"

  # Loop through the line
  For ($j = 1; $j -lt $OUs.Count; $j++) {

    # Current is the last NewPath value
    $CurrentPath = $NewPath

    # Prefix the current column
    $NewPath = "ou=$($OUs[$j]),$CurrentPath"
    $GroupPath = "cn=$($OUs[$j]),$CurrentPath"

    If (!([ADSI]::Exists("LDAP://$NewPath"))) {
      Write-Verbose "Creating OU: $NewPath"

      # Doesn't already exist. Make it.
      $OU = ([ADSI]"LDAP://$CurrentPath").Create("organizationalUnit", "ou=$($OUs[$j])")
      $OU.SetInfo()
    }
    If (!([ADSI]::Exists("LDAP://$GroupPath"))) {
      Write-Verbose "Creating Group: $GroupPath"

      $Group = ([ADSI]"LDAP://$CurrentPath").Create("group", "cn=$($OUs[$j])")
      $Group.Put("sAMAccountName", "$($OUs[$j] -Replace ' ')")
      $Group.SetInfo()
    }
  }
}

Open in new window

0
 

Author Comment

by:MikeEdd
ID: 33463623
Thanks Chris,
this is what I have so for ( a Little tweak for the production env, as alot of the groups already exsist)
and to put the group in the OU with the same name

how hard would it now be to add the groups recussivly to the Group in the OU above it location?

so that
Pats team ADGroup, is a member of Internal ADGroup
Internal ADGroup, is a member of    Accounts ADGroup
Accounts ADGroup, is a member of   UserOU ADGroup

what my end game result will be is to use this structure for the Data structure too and use the same groups for access,

then when I create a new user I add them to the correct OU and "OUname ADGroup" and the permissions are all set


thanks
$Import = Get-Content "C:\Scripts\PowerShell\OU Creation\test.csv"

# Loop through the file
For ($i = 1; $i -lt $Import.Count; $i++) {

  # Split the line and discard empty entries
  $OUs = $Import[$i].Split(",", [StringSplitOptions]::RemoveEmptyEntries)
    #echo $ous
  # Set the starting point
  $NewPath = "dc=test,dc=domain,dc=com"

  # Loop through the line
  For ($j = 1; $j -lt $OUs.Count; $j++) {

    # Current is the last NewPath value
    $CurrentPath = $NewPath

    # Prefix the current column
    $NewPath = "ou=$($OUs[$j]),$CurrentPath"
    $GroupPath = "cn=$($OUs[$j]),$CurrentPath"

    If (!([ADSI]::Exists("LDAP://$NewPath"))) {
      Write-Verbose "Creating OU: $NewPath"

      # Doesn't already exist. Make it.
      $OU = ([ADSI]"LDAP://$CurrentPath").Create("organizationalUnit", "ou=$($OUs[$j])")
      $OU.SetInfo()
    }
    If (!([ADSI]::Exists("LDAP://$GroupPath"))) {
      Write-Verbose "Creating Group: $GroupPath"
        #$temp = "cn=$($OUs[$j]) ADGroup"
        #echo $temp
     $Group = ([ADSI]"LDAP://$CurrentPath").Create("group", "ou=$($OUs[$j]) ADGroup,ou=$($OUs[$j])")
      $Group.Put("sAMAccountName", "$($OUs[$j] -Replace ' ') ADGroup")
      echo $Group
      $Group.SetInfo()
      
    }
  }
}

Open in new window

0
 
LVL 71

Expert Comment

by:Chris Dent
ID: 33463808

In theory all we should need is one line.

      ([ADSI]"LDAP://$($CurrentPath -Replace '^OU=', 'CN=')").Add("LDAP://$GroupPath")

This takes the current path, replaces "OU=" with "CN=" at the beginning, that gets us the group in the parent OU. Then it attempts to add the newly created group as a member.

We might also store the previous GroupPath (in addition to CurrentPath) but I figured this had a chance of being less code :)

Chris
0
 

Author Comment

by:MikeEdd
ID: 33466252
Ok Almost there I think...
However
when it tries to create the groups now I get eth error

Exception calling "SetInfo" with "0" argument(s): "There is a naming violation. (Exception from HRESULT: 0x80072037)"
At C:\Scripts\PowerShell\OU Creation\OUcreation.ps1:37 char:21
+       $Group.SetInfo <<<< ()
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : CatchFromBaseAdapterMethodInvokeTI


$Import = Get-Content "C:\Scripts\PowerShell\OU Creation\test.csv"

# Loop through the file
For ($i = 1; $i -lt $Import.Count; $i++) {

  # Split the line and discard empty entries
  $OUs = $Import[$i].Split(",", [StringSplitOptions]::RemoveEmptyEntries)
    #echo $ous
  # Set the starting point
  $NewPath = "dc=domain,dc=com"

  # Loop through the line
  For ($j = 1; $j -lt $OUs.Count; $j++) {



    # Current is the last NewPath value
    $CurrentPath = $NewPath

    # Prefix the current column
    $NewPath = "ou=$($OUs[$j]),$CurrentPath"
    $GroupPath = "cn=$($OUs[$j]),$CurrentPath"

    If (!([ADSI]::Exists("LDAP://$NewPath"))) {
      Write-Verbose "Creating OU: $NewPath"

      # Doesn't already exist. Make it.
      $OU = ([ADSI]"LDAP://$CurrentPath").Create("organizationalUnit", "ou=$($OUs[$j])")
      $OU.SetInfo()
    }
    If (!([ADSI]::Exists("LDAP://$GroupPath"))) {
      Write-Verbose "Creating Group: $GroupPath"
      $Group = ([ADSI]"LDAP://$CurrentPath").Create("group", "ou=$($OUs[$j]) ADGroup,ou=$($OUs[$j])")
      echo $Group
      $Group.Put("sAMAccountName", "$($OUs[$j] -Replace ' ') ADGroup")
      echo $Group
      $Group.SetInfo()
      
      #$k = $j-1
      
      #$test2 = $OUs[$k]
      #$test3 = "$test2 ADGroup"

      #$ExsGroup = "cn=$test3,$CurrentPath"
     # echo $Exsgroup
      #$AddGroup = "cn=$($OUs[$j]) ADGroup,$($grouppath -Replace '^cn=', 'ou=')"
      #echo $addgroup
      

      #echo "Current path $currentpath"
      
      #([ADSI]"LDAP://$addgroup").Add("LDAP://$Exsgroup")
      
      
      #echo $groupname

    }
  }
}

Open in new window

0
 
LVL 71

Expert Comment

by:Chris Dent
ID: 33466379

I had meant to check that today, I couldn't last night.

Anyway, we cannot give two objects in the same container the same name. We might suffix the group with something to distinguish it?

Chris
0
 

Author Comment

by:MikeEdd
ID: 33466455
yeah I added ADG to the end

Mike
0
 

Author Closing Comment

by:MikeEdd
ID: 33577658
Thanks for your help and sorry about the delay in closing the Q.


Mike
0

Featured Post

PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Active Directory security has been a hot topic of late, and for good reason. With 90% of the world’s organization using this system to manage access to all parts of their IT infrastructure, knowing how to protect against threats and keep vulnerabil…
Auditing domain password hashes is a commonly overlooked but critical requirement to ensuring secure passwords practices are followed. Methods exist to extract hashes directly for a live domain however this article describes a process to extract u…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question