The Inflatable Dinghy
Preface: Don’t do this on prod gear. This is a bad idea!
I’ve long been a fan of automated deployment.
During the fourth semester technical project at Fanshawe, I had a wonderful domain tree with OUs and global groups, group policies and delegated permissions. It was truly a nice domain. It just…. Felt a little lonely.
Enter PowerShell. Using a fairly simple script, I was able to cozy up the domains with the right users in the right places.
This table shows the imaginary organization we were presented with. By simply pasting this into a CSV file, we can easily bring it into the script:
$csvStructure = Import-Csv -Delimiter ',' -Path .\OrganizationalStructure.csv
This assumes the following about this domain:
- There is an OU in the root of all your domains called ‘Accounts’
- This script will be done as the Administrator in the domain that holds the InfrastructureMaster role.
- We’re crazy enough to let a script written by a stranger on the Internet run on one of the most important servers in the organization
Okay. Let’s try it out..!
[System.Collections.ArrayList]$Departments = (($csvStructure | gm -MemberType NoteProperty).Name)
foreach ($Unit in $csvStructure) {
Write-Verbose $Unit.BusinessName -Verbose
$UnitDN = "ou=Accounts"
Write-Output $UnitDN
$UnitDNFullyQualifiedPath = $Unit.domain.split('.')
$UnitDNFullyQualifiedPath | foreach { $UnitDN += ",dc=$_" }
Starting off, let’s establish the base DN of the business unit. In the case of HealthUnit this is "ou=HealthUnit,ou=Accounts,DC=sub,DC=domain,DC=ca"
Let’s create a container there, as well as a security group for all objects in that Unit:
New-ADOrganizationalUnit `
-name $Unit.BusinessName `
-Path $UnitDN `
-server $Unit.DomainControllerFQDN
$UnitDN = "ou=$($Unit.businessName),$UnitDN"
New-ADGroup -Name "$($Unit.BusinessName)"
-Path $businessUnitDN `
-GroupCategory Security `
-GroupScope DomainLocal `
-Server $Unit.DomainControllerFQDN
Next, we iterate through each department and create sub containers for only occupied departments. We then create a User and Computer container within that Unit’s Department.
Foreach ($Department in $Departments ) {
if($Unit.$Department -eq 0) { Continue; }
# Create business unit OU
$DepartmentDN = "ou=$Department,$UnitDN"
Write-Verbose "`t$DepartmentDN "
New-ADOrganizationalUnit -name $Department `
-Path $businessUnitDN `
-Server $Unit.DomainControllerFQDN
# Create a User container in that Unit's Department:
Write-Verbose "`t`tou=UserAccounts,$DepartmentDN"
New-ADOrganizationalUnit `
-name "UserAccounts" `
-path $DepartmentDN `
-server $Unit.DomainControllerFQDN
# Create a Workstation container in that Unit's Department:
Write-Verbose "`t`tou=Workstations,$DepartmentDN"
New-ADOrganizationalUnit `
-name "Workstations" `
-path $DepartmentDN `
-server $Unit.DomainControllerFQDN
Finally, let’s create an AD group for that Unit’s Department, and add it to the Unit’s security group:
New-ADGroup `
-name "$($Unit.BusinessName)-$Department" `
-path "$DepartmentDN" `
-GroupCategory Security -GroupScope DomainLocal `
-server $Unit.DomainControllerFQDN
Add-ADGroupMember `
-Identity "cn=$($Unit.BusinessName),$UnitDN" `
-Members "cn=$($Unit.BusinessName)-$Department,$DepartmentDN" `
-Server $Unit.DomainControllerFQDN
}
}
Nice! Now we have a fully laid out and standardized AD domain!
…We still have a problem though. We’ve built all the rooms and hallways, but we’re still horribly lonely in here!
For this part, I found a list of the top 10K first names and last names on the internet. These aren’t too hard to find and import, so I will leave that part to the reader. They exist in my script as the lists $Top10kFirstNames
and $Top10kLastNames
.
Let’s start by re-using some of the control code from the last script:
foreach ($Unit in $csvStructure) {
$UnitDN = "ou=Accounts"
$UnitDNFullyQualifiedPath = $Unit.domain.split('.')
$UnitDNFullyQualifiedPath | foreach { $UnitDN += ",dc=$_" }
$UnitDN = "ou=$($Unit.businessName),$UnitDN"
Foreach ($Department in $Departments ) {
if($Unit.$Department -eq 0) { Continue; }
$DepartmentDN = "ou=$Department,$UnitDN"
And right about here we’ll drop in some new code to add users. We will iterate through the Departments in that Unit, and for each one generate a random username. Passwords are generated using the New-Guid
command. We will then add this user to the correct security group for that Department.
$usersPath = "ou=UserAccounts,$DepartmentDN"
1..$Unit.$Department | Foreach {
$FirstName = ($Top10kFirstNames | Get-Random)
$LastName = ($Top10kLastNames | Get-Random)
$UPN = "$FirstName.$LastName@$($Unit.Domain)"
$SamAccountName = (($FirstName[0..10] -join '') `
+ ($LastName[0..1] -join '')).ToLower()
$GroupName = "cn=$($Unit.BusinessName)-$Department"
New-ADUser -GivenName "$FirstName" `
-Surname "$LastName" `
-Name "$FirstName $LastName" `
-AccountPassword:$(New-Guid) `
-Path $usersPath
-UPN $UPN
-SamAccountName $SamAccountName
-Server $Unit.DomainControllerFQDN
$userID = Get-ADUser "cn=$FirstName $LastName,$usersPath" `
-Server $Unit.DomainControllerFQDN
$groupID = Get-ADGroup "$GroupName,$DepartmentDN" `
-Server $Unit.DomainControllerFQDN
Add-ADGroupMember -Identity $groupID `
-Members $userID `
-Server $Unit.domainControllerFQDN
}
}
}
…And that’s it! After a couple minutes, our domain controllers are toasty hot, our replication is going nuts, and most importantly, we’re a little less lonely here in the testing environment.