Adding Groups Through PowerShell

With our Users and Computers in place, we can start adding groups. The groups will be based on the Postition ocf the characters in the StarTrek Csv file. I’ve chosen position since many characters can have the same position.

First, let’s look at all the unique Positions in the Csv file. I’m also using the Series as a Descrption and it’s also used to place the group in the correct OU.


PS > $CsvFile | Select Position, Series -Unique


Position                     Series
--------                     ------
Commanding Officer           Star Trek: The Next Generation
First Officer                Star Trek: The Next Generation
Chief Engineer               Star Trek: The Next Generation
Chief of Security            Star Trek: The Next Generation
Chief Medical Officer        Star Trek: The Next Generation
Ship's Counselor             Star Trek: The Next Generation
Chief Operations             Star Trek: The Next Generation
Conn Officer                 Star Trek: The Next Generation
Transporter Officer          Star Trek: The Next Generation
Botanist                     Star Trek: The Next Generation
Nurse                        Star Trek: The Next Generation
Bartender                    Star Trek: The Next Generation
Engineering Officer          Star Trek: The Next Generation
Federation Ambassador        Star Trek: The Next Generation
Security Officer             Star Trek: The Next Generation
Medical Officer              Star Trek: The Next Generation
Operations Officer           Star Trek: The Next Generation
Commanding Officer           Star Trek: Deep Space Nine
First Officer                Star Trek: Deep Space Nine
Chief of Security            Star Trek: Deep Space Nine
Chief Medical Officer        Star Trek: Deep Space Nine
Chief Science Officer        Star Trek: Deep Space Nine
Counselor                    Star Trek: Deep Space Nine
Strategic Operations Officer Star Trek: Deep Space Nine
Chief Operations             Star Trek: Deep Space Nine
Civilian                     Star Trek: Deep Space Nine
Bartender                    Star Trek: Deep Space Nine
Commanding Officer           Star Trek: Voyager
First Officer                Star Trek: Voyager
Second Officer               Star Trek: Voyager
Chief Engineer               Star Trek: Voyager
Medical Officer              Star Trek: Voyager
Chief Operations Officer     Star Trek: Voyager
Chief Medical Officer        Star Trek: Voyager
Chef                         Star Trek: Voyager
Aeroponics caretaker         Star Trek: Voyager
Miscellaneous                Star Trek: Voyager
Conn Officer                 Star Trek: Voyager
Science                      Star Trek: Voyager
Engineering Officer          Star Trek: Voyager
Civilian                     Star Trek: Voyager
Commanding Officer           Star Trek: Enterprise
First Officer                Star Trek: Enterprise
Armory Officer               Star Trek: Enterprise
Engineering Officer          Star Trek: Enterprise
Medical Officer              Star Trek: Enterprise
Communications Officer       Star Trek: Enterprise
Chief Engineer               Star Trek: Enterprise

I’m going to use the first entry “Commanding Officer” to explain how the script works. At first, we have to check if the group already exists. we’ll reuse the checker function that I’ve mentioned in previous blog posts.


function Check-distinguishedName ([string]$Domain, [string]$Group) {

   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Group $Group -filter distinguishedName | Out-Null
}

Next we have to build up the groups distinguishedName in order to check it.


PS > $Domain = "powershell.nu"
PS > $Position = "Commanding Officer"
PS > $Series = "Star Trek: The Next Generation"
PS > $distinguishedName = "CN=" + $Position + ",OU=Groups,OU=" + $Series +
>> $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $distinguishedName

CN=Commanding Officer,OU=Groups,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

Now that we’ve built up a distinguishedName we can check it through the Check-distinguishedName function. If the group doens’t exist, the variable $distinguishedNameDoesntExist is set to $True, which means that we can go ahead and create the group.


PS > Check-distinguishedName $Domain $distinguishedName
PS > $distinguishedNameDoesntExist

True

Now that we’re sure that the group does’t exist we can create a connection to Active-Directory and create the group. First we’ll set up the connectionstring to the correct OU and create a [adsi] connection.


PS > $Connection = "LDAP://OU=Groups" + $Series.Insert(0,",OU=") +
>> ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $AD = [adsi] $Connection

Adding the group is quite simple using the Create() method.


PS > $Group = $AD.Create("Group", "CN=$Position")
PS > $Group.SetInfo()

The part that’s not so simple is adding a unique sAMAccountName. Since there’s One Commanding officer for each ship, we will have a total of four different groups with the same name, the distinguishedName doesnt have to be unique as long as its not in the same OU but the sAMAccountName has to be.

First we have to create a sAMAccountName for the group. Since the Group names tend to be quite long, we’ll shorten the groups sAMAccountName through the subString() method if it’s longer than 10 characters. We’ll also remove spaces in the string.


PS > $sAMAccountName = ($Position.replace(" ","")).ToUpper()

PS > if ($sAMAccountName.Length -gt 10) {
  $sAMAccountName = $sAMAccountName.SubString(0,9)
}
PS > $sAMAccountName

COMMANDIN

Now that we have a sAMAccountName, we have to check so that it doesn’t exist. again through a checker function.


function Check-sAMAccountName ([string]$Domain, [string]$Group) {

  trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
  .Get-AD.ps1 -Domain $Domain -Group $Group -filter sAMAccountName | Out-Null
}

If the sAMAccountName exists, we will handle this through a while loop and append an integer at the end.


While ($Script:sAMAccountNameDoesntExist -eq $False) {

   $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

   if(1..9 -Contains $LastChar) {

    $sAMAccountName = ($sAMAccountName.TrimEnd([string]$LastChar)) +
    ([int]$LastChar + 1)
   } else {

    $sAMAccountName = $sAMAccountName + 1
   }

   Check-sAMAccountName -Domain $Domain -Group $sAMAccountName
}

Finally, we can add the additional group information, in this case: sAMAccountName and Description.


$Group.put("Description", $Position)
$Group.put("sAMAccountName", $sAMAccountName)
$Group.setinfo()

Here’s how it looks if we run it in our test environment.

add-stgroup01

Repeating the script shows that the groups already exist.

add-stgroup02

and here’s a quick look in dsa.msc

add-stgroup03

Additionally, let’s look at our Commanding Officer groups. We can do this through the Get-AD.ps1 script


PS > .Get-AD.ps1 -Domain powershell.nu -Group AllGroups -Property sAMAccountName, cn |
>> Where { $_.cn -match "Commanding Officer" }


sAMAccountName cn
-------------- --
COMMANDIN      Commanding Officer
COMMANDIN1     Commanding Officer
COMMANDIN2     Commanding Officer
COMMANDIN3     Commanding Officer

Isn’t it cool how you can take the result of a script and pipe it to the Where-Object CmdLet.

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Computers through PowerShell

Now let’s add a couple of computers to our test environment. The Computer Names are based on the Starships from the Csv file. Since there are alot of characters but not that many different ships we need to get a unique list of ships. We also wnat the Series, Location and Registry values.


PS > $CsvFile = Import-Csv StarTrek.csv
PS > $CsvFile | Select Series, Starship, Location, Registry -unique | fl


Series   : Star Trek: The Next Generation
Starship : USS Enterprise (NCC-1701-D)
Location : Alpha Quadrant
Registry : NCC-1701-D

Series   : Star Trek: Deep Space Nine
Starship : Deep Space Nine
Location : Alpha Quadrant
Registry : DS9

Series   : Star Trek: Voyager
Starship : USS Voyager (NCC-74656)
Location : Delta Quadrant
Registry : NCC-74656

Series   : Star Trek: Enterprise
Starship : Enterprise (NX-01)
Location : Alpha Quadrant
Registry : NX-01

Let’s walk through how the script handles the first Starship. At first we have to check if the Computer exists, We’ll use a checker function that checks if the Computer doesn’t exist.


function Check-distinguishedName ([string]$Domain, [string]$Computer) {

   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Computer $Computer -filter distinguishedName | Out-Null
}

Next we have to check create a variable holding a distinguishedName and check if it exists or not.


PS > $Starship = "USS Enterprise (NCC-1701-D)"
PS > $Domain = "powershell.nu"
PS > $distinguishedName = "CN=" + $Starship + ",OU=Computers,OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

Now we can run the function.


PS > Check-distinguishedName -Domain $Domain -Computer $distinguishedName

Now that we’ve checked the distinguisehdName we can connect to AD and start adding our Computer.


PS > $Connection = "LDAP://OU=Computers" + $Series.Insert(0,",OU=") + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

PS > $AD = [adsi] $Connection

PS > $Computer = $AD.Create("Computer", "CN=$Starship")
PS > $Computer.SetInfo()

Now for the additional information. We might want to change the sAMAccountName from the default name generated by AD. We also want to check that the name we choose doesn’t exist so we’ll use yet another check function.


function Check-sAMAccountName ([string]$Domain, [string]$Computer) {

   trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Computer $Computer -filter sAMAccountName | Out-Null
}

We’ll base the sAMAccountName on the Ships Registry information. In this case, the registry is NCC-1701-D


PS > $sAMAccountName = ($Registry).ToUpper()

PS > Check-sAMAccountName -Domain $Domain -Computer $sAMAccountName

If the sAMAccountName doesn’t exist the script will use it on the Computer object. If it does exist, theres a while loop that loops through and appends a digit in order to get a unique sAMAccountName. Here’s an example on the where loop.


While ($Script:sAMAccountNameDoesntExist -eq $False) {

   # Create New sAMAccountName

   $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

    if(1..9 -Contains $LastChar) {

    $sAMAccountName = $sAMAccountName.SubString(0,$sAMAccountName.Length -1) + ([int]$LastChar + 1)

   } else {

    $sAMAccountName = $sAMAccountName.SubString(0,$sAMAccountName.Length -1) + 1
   }

   Check-sAMAccountName -Domain $Domain -Computer $sAMAccountName
}

The final Steps of the script add the additional information and enables the computer.


PS > $Computer.put("sAMAccountName", $sAMAccountName)
PS > $Computer.put("Location", $Location)
PS > $Computer.put("Description", $Starship)
PS > $Computer.setinfo()

PS > $Computer.PsBase.InvokeSet("AccountDisabled", $False)
PS > $Computer.SetInfo()

Now let’s run the script in our test environment.

add-stcomputer011

If we repeat the script it’ll tell us that the computers already exist.

add-stcomputer02

If we check in dsa.msc snap-in we can see that the computer objects have been created.

add-stcomputer03

and finally, if we want to retrieve the information through PowerShell, we can use the Get-AD.ps1 script.


PS > .Get-AD.ps1 -Domain powershell.nu -Computer "Uss Enterprise (NCC-1701-D)"


objectClass          : top person organizationalPerson user computer
cn                   : USS Enterprise (NCC-1701-D)
description          : USS Enterprise (NCC-1701-D)
distinguishedName    : CN=USS Enterprise (NCC-1701-D),OU=Computers,OU=Star Trek
                       u
instanceType         : 4
whenCreated          : 4/13/2009 7:19:11 PM
whenChanged          : 4/13/2009 7:19:11 PM
uSNCreated           : System.__ComObject
uSNChanged           : System.__ComObject
name                 : USS Enterprise (NCC-1701-D)
objectGUID           : 31 54 123 251 207 232 62 72 153 101 238 77 71 88 19 27
userAccountControl   : 544
badPwdCount          : 0
codePage             : 0
countryCode          : 0
badPasswordTime      : System.__ComObject
lastLogoff           : System.__ComObject
lastLogon            : System.__ComObject
pwdLastSet           : System.__ComObject
primaryGroupID       : 513
objectSid            : 1 5 0 0 0 0 0 5 21 0 0 0 50 71 101 4 93 25 58 165 36 24
accountExpires       : System.__ComObject
logonCount           : 0
sAMAccountName       : NCC-1701-D
location             : Alpha Quadrant
sAMAccountType       : 805306368
objectCategory       : CN=Computer,CN=Schema,CN=Configuration,DC=powershell,DC=
nTSecurityDescriptor : System.__ComObject

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Users through PowerShell

Now that we have our OU structure in place, we can start adding users.

Since the Users contain alot of information we’ll go ahead and use the whole csv file.

Let’s take a quick look at the first entry in the Csv file:


PS > (Import-Csv StarTrek.csv)[0]


Character  : Jean-Luc Picard
Position   : Commanding Officer
Rank       : Captain
Department : Main Bridge
Species    : Human
Starship   : USS Enterprise (NCC-1701-D)
Class      : Galaxy
Registry   : NCC-1701-D
Series     : Star Trek: The Next Generation
Location   : Alpha Quadrant

Let’s start adding the Users to the Domain. First off, we need to build up a connectionstring. In the script, I build it based on


PS > $Series = "Star Trek: The Next Generation"
PS > $Domain = "powershell.nu"
PS > $Connection = $Series.Insert(0,"LDAP://OU=Users,OU=") + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $Connection

LDAP://OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

Now for the Fun part. In the Csv file, some Characters don’t have any surNames and some have middle names, so this is something I have to consider in the script. Thanks to the Power of PowerShell it doesn’t have to get to complex.

Step one is Checking the characters name. I use the Split() method to determine if the user has a SurName or any Middle Names.


PS > $Character = "Jean-Luc Picard"
PS > $CharacterName = $Character.Split(" ")
PS > $CharacterName

Jean-Luc
Picard

In this example, Jean-Luc would be the givenName and Picard the surName. I control this in the script through a if else statement that checks if the $CharacterName contains 1 row or more.


if (($CharacterName.Count) -le 1) {

} else {

}

In the case of Jean-Luc Picard, the Name contains more than 1 row, so let’s move on to the else statement.

The else statement starts of by setting up giveName and SurName. the $giveName variable contain all names except the last one. So if we would use Charles Trip Tucker instead of Picard, the givenName would be “Charles Trip” and surName would be set to “Tucker”.


PS > $givenName = $CharacterName[0..($CharacterName.Count -2)]
PS > $sn = $CharacterName[($CharacterName.Count -1)]
PS > $givenName

Jean-Luc

PS > $sn

Picard

Now that we’ve sliced and diced the characters name, we do an additional check to see if the character name will fit the sAMAccountName structure decided in Part 1.0.0 (First 3 from giveName and first 3 from surName).


if ($givenName.Length -lt 3 -AND $sn.Length -lt 3) {

   $Tempcn = $givenName + $sn
   $AddNum = 3 - $Tempcn.Length

   # Build Last Part Of cn

   for ($i = 0; $i -lt ($AddNum -1); $i ++) { $AddTocn += "0" }
   $AddTocn += "1"

   [string]$sAMAccountName = ($Tempcn).ToLower() + $Addtocn
   $cn = $givenName

   # Set Checker to Null

   $AddTocn = $Null

} elseif ($givenName.Length -lt 3 -OR $sn.Length -lt 3) {

   $Tempcn = $givenName + $sn

   [string]$sAMAccountName = ($Tempcn.SubString(0,6)).ToLower()
   $cn = $givenName + " " + $sn

} else {

   [string]$sAMAccountName = ($givenName.SubString(0,3)).ToLower() + ($sn.SubString(0,3)).ToLower()
   $cn = $givenName + " " + $sn
}

The if elseif else statement goes through the characters name and checks if it falls within parameters. If it does not, a number will be added at the end of the Name to compensate. The elseif statement takes care of users where givenName or surName has less than 3 characters and compensates this.

Here’s how Jean-Luc Picard is set up now:


PS > $givenName

Jean-Luc

PS > $sn

Picard

PS > $sAMAccountName

jeapic

PS > $cn

Jean-Luc Picard

Now that we have the sAMAccountName in place we have to check if the sAMAccountName is taken by some other User. We can do this by creating a function that looks up the users sAMAccountName from the Get-AD.ps1 script.


function Check-sAMAccountName ([string]$Domain, [string]$User) {

   trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -User $User -Filter sAMAccountName | Out-Null
}

If the UserName already exists the script uses a While loop to determine how many sAMAccountNames are taken and when an empty sAMAccountName is found it will be used.


if ($sAMAccountNameDoesntExist -eq $True) {

} else {

   While ($Script:sAMAccountNameDoesntExist -eq $False) {

    $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

    if(1..9 -Contains $LastChar) {

       $sAMAccountName = ($sAMAccountName.TrimEnd([string]$LastChar)) + ([int]$LastChar + 1)
    } else {

       $sAMAccountName = $sAMAccountName + 1
    }

    Check-sAMAccountName -Domain $Domain -User $sAMAccountName
   }
}

If jeapic already exists the number 1 will be appended to his sAMAccountName, and if jeapic1 already exists 1+1 ( 2) would be appended instead. Note that doing this sets the sAMAccountName to 7 characters instead of 6. If you always want to use 6 chars you could substring() out characters 1 to 5 ( 0,4 ) and build up a sAMAccountName containing only 6 characters.

Now that we have a unique sAMAccountName, we want to check the Users distinguishedName. If the distinguishedName already exists then we will not Add the User, since he already exists. If not, we will go ahead and add our user. The distinguishedName check function is basically the same as the sAMAccountName checker, only differens is that it filters on distinguishedName instead.


function Check-distinguishedName ([string]$Domain, [string]$User) {
   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -User $User -filter distinguishedName | Out-Null
}

The function takes distinguishedName as an argument, so we have to build up this string. The OU structure was set up in Part 1.1.1 so the User should be in the following OU: “OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu”.


$distinguishedName = "CN=" + $cn + ",OU=Users,OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

If the disyinguishedName doesnt exist, we can go ahead and create the User. For safety reasons, we generate a secure password for each user that we create and store the passwords in a password file. We could obviously set all Passwords to “Password1″ but that wouldn’t be fun.

Here’s a simple password generator that I’ve created. Using the System.Random Class to generate random numbers.


function Generate-Password {

  $Random = New-Object System.Random

  # Two Upper Case Characters

  [string]$Password += [char]$Random.Next(49,57)
  [string]$Password += [char]$Random.Next(65,72)

  # Two LowerCase Characters

  [string]$Password += [char]$Random.Next(97,107)
  [string]$Password += [char]$Random.Next(109,122)

  # One Special Char

  [string]$Password += [char]$Random.Next(36,43)

  # Two UpperCase Characters

  [string]$Password += [char]$Random.Next(65,72)
  [string]$Password += [char]$Random.Next(80,91)

  # One LowerCase

  [string]$Password += [char]$Random.Next(97,107)

  $Password
  $Password = $Null
}

Why not make it a a shorter script and randomize [char]49 to [char]122? Well, if I randomize any character from [char]49 to [char]122 i might get an “O” and numeric “0″, or “l”,”I” or numeric “1″. Users might find it hard to differentiate an O from an 0 so I’ve excluded Characters that look alike in the function. Also, if I use a for statement and loop through [char]$Random.Next(49,122) eight times, it’s not certain that i get an acceptable Password, i might all uppercase characters and AD wouldn’t accept that.

Now that we have a Password generator we can create our User.


PS > $Description = $Position + " (" + $Species + ")"
PS > $Title = $Rank
PS > $physicalDeliveryOfficeName = $Starship
PS > $userPrincipalName = $sAMAccountName + "@" + $Domain
PS > $mail = ([string]$Character).Replace(" ",".") + "@" + $Domain

PS > [string]$Password = Generate-Password

PS > $OU = [adsi] $Connection
PS > $User = $OU.Create("user", "cn=$cn")
PS > $User.Put("sAMAccountName", $sAMAccountName)
PS > $User.Put("userPrincipalName", $userPrincipalName)
PS > $User.Put("DisplayName", $cn)
PS > $User.Put("givenName", $givenName)
PS > $User.Put("sn", $sn)
PS > $User.Put("Description", $Description)
PS > $User.Put("l", $Starship)
PS > $User.Put("streetAddress",$Location)
PS > $User.Put("physicalDeliveryOfficeName", $physicalDeliveryOfficeName)
PS > $User.Put("Title", $Title)
PS > $User.Put("Department", $Department)
PS > $User.Put("Company", $Starship)
PS > $User.Put("mail", $mail)
PS > $User.SetInfo()

PS > $User.PsBase.Invoke("SetPassword", $Password)
PS > $User.PsBase.InvokeSet("AccountDisabled", $false)
PS > $User.SetInfo()

Now all i have to do is Collect the Generated Password in a file.


PS > $FileName = "PasswordList " + (get-date -uformat "%Y-%m-%d") + ".txt"
PS > "$sAMAccountName,$cn,$Password" | Add-Content $FileName

Running the script in our test environment would look something like this:

add-stuser01

If we repeat the script, the checker function fould tell us that the Users already exist:

add-stuser02

Now for a peek in Active-Directory snap-in dsa.msc

add-stuser03

And Finally, let’s look closer on Captain Jean-Luc Picard and see if the Values specified in the script are set.

add-stuser04

And here’s an example on the Autogenerated Password List.

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Ou Structure using Powershell

Starting of, we need to set up a couple of OrganizationalUnits in our test environment. Following the structure set up in Part 1.1.0:

Organizational Unit Structure

  • ou = Series
  • l = Location
  • Description = Starship
  • Child OU: Computers
  • Child OU: Groups
  • Child OU: Users

The first step in scripting up a OU structure from based on the StarTrek Csv file is to collect the information through PowerShell. Since the Csv file contains 68 rows of information and 10 different columns, we want to retrieve only information that we need to create a Csv Structure. The columns of interest are: Series, Starship and Location. Using Import-Csv in combination With Select-Object gets all entries matching this.


PS > Import-Csv StarTrek.csv | Select-Object Series, Starship, Location


Series                         Starship                    Location
------                         --------                    --------
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant

Now we,ve managed to retrieve the specified columns and rows. Next we need to narrrow the list down to only unique entries. We can achieve this through the -Unique SwitchParameter.


PS > Import-Csv .StarTrek.csv | Select-Object Series, Starship, Location -Unique


Series                         Starship                    Location
------                         --------                    --------
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: Deep Space Nine     Deep Space Nine             Alpha Quadrant
Star Trek: Voyager             USS Voyager (NCC-74656)     Delta Quadrant
Star Trek: Enterprise          Enterprise (NX-01)          Alpha Quadrant

Now that we’ve narrowed down our list, we can start creating the OU structure.

The OU:s Name should be “Series”, so the structure that we’re looking for is:

  • Star Trek: The Next Generation
  • Star Trek: Deep Space Nine
  • Star Trek: Voyager
  • Star Trek: Enterprise

But how do we know that these OU:s dont already exist in our Environment ? We have to check this in some way so we need a checker that makes sure that the OU doesn’t exist. This is an excellent oppurtunity to use the Get-AD.ps1 script that I wrote. The checker is rather simple, it consists of a function that sets a variable to $True if the OU does not exist.


function Check-distinguishedName ([string]$Domain, [string]$OU) {

	trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
	.\Get-AD.ps1 -Domain $Domain -OU $OU -Filter distinguishedName | Out-Null
}

The Variable $Script:distinguishedNameDoesntExist is set to $True if we test the function on a non existing OU. Here’s an example on how it works:


PS > Check-distinguishedName -Domain powershell.nu -OU "OU=Domain Controllers,DC=powershell,DC=nu"
PS > $distinguishedNameDoesntExist

Since Domain Controllers Exist, the variable $distinguishedNameDoesntExist is not set to anything. Running the same function on a OU that does not exist:


PS > Check-distinguishedName -Domain powershell.nu -OU "OU=Non Existing OU,DC=powershell,DC=nu"
PS > $distinguishedNameDoesntExist

True


PS > $distinguishedNameDoesntExist = $Null

This time the variable $distinguishedNameDoesntExist was set to True, which means that the OU does not exist and it’s available for creation. I also set the Variable to $Null so that i can reuse the function.

Moving on. If the $distinguishedNameDoesntExist equals $True we can start building up the OU Structure. In the script, there’s a paramter called -Domain which takes the domain name as an argument. In my examples I’m going to use the powershell.nu domain. Setting this as an argument is similar to creating a Variable holding the domain name:


PS > $Domain = "powershell.nu
PS > $Domain

powershell.nu

With this information we can create a Connection string that we can use when connecting to Active-Directory. We can make use of the methods() withing System.String to alter the string as we want it. I’m using Replace() and Insert() to get the result I want:


PS > $Connection = ($Domain.Replace(".",",DC=")).Insert(0,"LDAP://DC=")

PS > $AD = [adsi] $Connection
PS > $AD


distinguishedName
-----------------
{DC=powershell,DC=nu}

Now that we’ve set up a connection we can start creating an OU. It’s pretty straight forward, nothing fancy here:


PS > $OU = $AD.Create("OrganizationalUnit", "ou=$Series")
PS > $OU.SetInfo()

PS > $OU.put("l", $Location)
PS > $OU.put("Description", $Starship)
PS > $OU.setinfo()

When creating Child OU:s, we need to alter the Connection string so that we connect to the OU that we’ve just created, here’s an example on doing that:


$NewConnection = "LDAP://OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
$NewOU = [adsi]$NewConnection

Now we can start creating Child OU:s that are structured after our purpose:


$Users = $NewOU.Create("OrganizationalUnit", "ou=Users")
$Users.SetInfo()

$Users.put("l", $Location)
$Users.put("Description", $Starship)
$Users.setinfo()

This describes the steps that I’ve set up in the Script. Running the script in the test environment would look like this:

add-stou01

If i repeat the script, the Check function finds that the top OU:s already exists and the following is returned to the host:

add-stou02

Finally, taking a peek in dsa.msc.

add-stou03

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 4.50 out of 5
[?]

Scripting up an Active-Directory Test Environment through PowerShell

The first step in building up a Test Environment is analyzing the data that we have to work with. In this case, the Star Trek Reference Csv file.

Since the Csv file doesn’t say sAMAccountName or organizationalUnit I’ve to set up a routine for handling this. Based on the information, I’ve set up the following rules:

User Information

  • Common Name = Character Name
  • sAMAccountName = First 3 Characters from givenName and surName
  • userPrincipalName = sAMAccountName and Domain
  • DisplayName = Character Name
  • givenName = First part of Character Name
  • surName = Last part of Character Name
  • Description = Postition + Species
  • l = Starship
  • streetAddress = Location
  • physicalDeliveryOfficeName = Starship
  • Title = Rank
  • Department = Department
  • Company = Starship
  • mail = CharacterName and Domain

Computer Information

  • Common Name = Starship
  • sAMAccountName = Registry
  • Location = Location
  • Description = Starship

Group Information

  • Common Name = Position
  • Description = Position
  • sAMAccountName = Position

Group MemberShip

  • Members = Based on Users Position

Organizational Unit Structure

  • ou = Series
  • l = Location
  • Description = Starship
  • Child OU: Computers
  • Child OU: Groups
  • Child OU: Users

Users HomeFolder

  • HomeFolder = Based on Users sAMAccountName and a defined Path

Most of these steps may seem trivial and easy to script up based on a Csv file, but there are numerous steps to consider, for example: some Characters, such as T’pol and Phlox don’t have any surnames (at least not any surnames recorded in the Vulcan Database) so these names must be handled in the script. Another step to consider are sAMAccountNames conatining a invalid set of characters and so on. I’m going to go through each step of the scripts and explain in detail how to avoid the exceptions that we might encounter in each new post regarding the migration.

The Scripts will also use the Get-AD.ps1 script when chekcing if objects exist in the Domain.

Next step is Part 1.1: Adding Ou Structure using Powershell

The Get-AD.ps1 script.

Here’s a link to the Csv File refered to in this post.

Rating 4.00 out of 5
[?]