Author Posts

August 4, 2014 at 1:26 pm

Hello all..

I am in the middle of writing a script to export my active directory (OU, user, computer, group) to a csv file and import it into another domain for some testing. I have been working on this all day, so I may be in the weeds instead of noticing the wide open field right in front of me – hopefully you can help.

A simplified version of my export script..


$ou = Get-ADOrganizationalUnit -Filter * | select -Property distinguishedName, name, SamAccountName
# add some note property members so that all objects have the same properties
$ou | Add-Member -MemberType NoteProperty -Name UserPrincipalName -Value OU
$ou | Add-Member -MemberType NoteProperty -Name EmailAddress -Value OU
$ou | Add-Member -MemberType NoteProperty -Name GroupScope -Value OU
$ou | Add-Member -MemberType NoteProperty -Name ObjectType -Value OU
$ou | Export-Csv -Path $objectFile -NoTypeInformation

$user = Get-ADUser -Filter * -Properties * | select -Property distinguishedName, name, SamAccountName, UserPrincipalName, EmailAddress
# add some note property members so that all objects have the same properties
$user | Export-Csv -Path $objectFile -NoTypeInformation -Append

$pc = Get-ADComputer -Filter * | select -Property distinguishedName, name, SamAccountName
# add some note property members so that all objects have the same properties
$pc | Export-Csv -Path $objectFile -NoTypeInformation -Append

$group = Get-ADGroup -Filter * | select -Property distinguishedName, name, SamAccountName, GroupScope
# add some note property members so that all objects have the same properties
$group | Export-Csv -Path $objectFile -NoTypeInformation -Append

The above script exports a to a csv file the OUs, users, groups, and computers.

Now – for the import –

I prompt for a new domain name, and then find and replace all necessary instances of the production domain vs the lab domain. Then I import the csv file of all of the objects...


# add a script method to the objects object to count the number of commas in the dn field name
# this allows me to sort on the number of commas in the DN so I (hopefully) create the OUs in the correct order - for nested OUs
$objects | Add-Member -MemberType ScriptProperty -Name OULevel -Value {$this.distinguishedName -split "," | Measure-object | select -ExpandProperty Count}

### - here is where I am stuck ###

$objects | Add-Member -MemberType ScriptMethod -Name BaseDN -Value {$i=$this.distinguishedName.IndexOf(","); $this.distinguishedName.SubString($i, $this.distinguishedName.Length - 1);} 

That doesn't seem to work. I keep getting "Exception Calling BaseDN with "0" arguments: Exception calling "Substring" with 2 arguments.: Index and length must refer to a location within the string"

What am I doing wrong?

Thanks in advance
sb

August 4, 2014 at 3:12 pm

My initial suggestion is to use XML to store and manipulate complex data types as opposed to CSV, as in using Export-Clixml and Import-Clixml
I gather the intent is to migrate user, group, computer objects from one forest to another, preserving the group memberships. Any other requirements?
Is ADMT an option?

August 4, 2014 at 5:08 pm

Thanks for the response. I will check out XML and see if it makes any of my issue different. But – my issue isn't with the CSV. I am able to export it and import it without any issue.

One of the properties I am exporting is distinguished name. So for example – I export OU=New Computers,DC=mydomain,DC=local. I want to create this OU based on the path – so I want to remove the OU=New Computers, from the DN leaving me with DC=stewartsshops,DC=local for the path parameter to New-ADOrganizationalUnit.

I have tried using -replace with my splatting. I have tried making a script property and a script method. Something just isn't jiving.

I am doing this to play around with AD FS for Office 365.

Thanks again
sb

August 5, 2014 at 1:45 am

The replace method should just work like:

# Replace all example:
#
$SearchFor = "mydomain"
$ReplaceWith = "stewartsshops"
[string]$DN = "OU=bl1 1,OU=mydomain,OU=New Computers,DC=mydomain,DC=local."
#
[string]$newDN = $DN.Replace($SearchFor,$ReplaceWith)
Write-Output "   DN == $DN"
Write-Output "newDN == $newDN"

Output will look like:

       DN => OU=bl1 1,OU=mydomain,OU=New Computers,DC=mydomain,DC=local.
newDN => OU=bl1 1,OU=stewartsshops,OU=New Computers,DC=stewartsshops,DC=local.

note that all occurrences of the $Searchfor substring have been replaced
However, if you need to replace substring at a specific level and not thoughout the entire string, Try this:

# Replace a spcific level example:
#
$SearchFor = "mydomain"
$ReplaceWith = "stewartsshops"
$Level = 2
[string]$DN = "OU=bl1 1,OU=mydomain,OU=New Computers,DC=mydomain,DC=local."
# break out the input string into array to facilitate text manipulation
[array]$Pieces = $DN.Split(",")
# Replace the text at the given level only
$TargetLevel = $Pieces[$Pieces.Length-$Level]
$newTargetLevel = $TargetLevel.Replace($SearchFor,$ReplaceWith)
# re-assemble the string back
[string]$newDN = $null
foreach ($Piece in $Pieces) {
    if ($Piece -eq $TargetLevel) { $newDN += "$newTargetLevel," } else { $newDN += "$Piece," }
}
# remove last comma
$newDN = $newDN.Substring(0,$newDN.Length -1)
#
Write-Output "   DN == $DN"
Write-Output "newDN == $newDN"

output will look like:

   DN == OU=bl1 1,OU=mydomain,OU=New Computers,DC=mydomain,DC=local.
newDN == OU=bl1 1,OU=mydomain,OU=New Computers,DC=stewartsshops,DC=local.

here, only substring occurrence at the specified level 2 has been replaced