Automated Active Directory Deployment with PowerShell

Powershell

For a small presentation at KTSI I created a PowerShell script will automatically will deploys Active Directory Servers, adds other member servers, creates Organization Units and adds users via Powershell Remoting. As source there is a XML configuration file and CSV files for User Data.

Install AD with Powershell

This script is just for Lab deployments not for production, and it is not perfect, but I think maybe some people will enhance this script with their own code.

I do not support this script. it is just something I need to deploy my test environments and nothing more. More it shows diffrent

You can find more information about it works in this document.

XML Config file:

 
<?xml version="1.0" encoding="utf-8"?>
<lab>
<config>
<servers>
<server name="ADS01" ip="192.168.100.11" id="1" adminpw="passw0rd"/>
<server name="ADS02" ip="192.168.100.12" id="2" adminpw="passw0rd"/>
</servers>
<ad>
<domain name="ktsi.local" netbiosname="ktsi" forestlevel="4" domainlevel="4" safemodepw="passw0rd" />
</ad>
<ous>
<ou name="UserAccounts" path="DC=KTSI,DC=LOCAL" />
<ou name="BASEL" path="OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="CHICAGO" path="OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="NEWYORK" path="OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="SALES" path="OU=BASEL,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="IT" path="OU=BASEL,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="ADMINISTRATION" path="OU=BASEL,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="PRODUCTION" path="OU=BASEL,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="SALES" path="OU=CHICAGO,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="IT" path="OU=CHICAGO,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="ADMINISTRATION" path="OU=CHICAGO,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="PRODUCTION" path="OU=CHICAGO,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="SALES" path="OU=NEWYORK,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="IT" path="OU=NEWYORK,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="ADMINISTRATION" path="OU=NEWYORK,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
<ou name="PRODUCTION" path="OU=NEWYORK,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
</ous>
<users>
<file name="users.csv" path="OU=ADMINISTRATION,OU=BASEL,OU=USERACCOUNTS,DC=KTSI,DC=LOCAL" />
</users>
<members>
<member name="PC101" ip="192.168.100.21" />
<member name="PC101" ip="192.168.100.22" />
<member name="PC101" ip="192.168.100.23" />
</members>
</config>
</lab>

The PowerShell Script:

 
 
 
# ---------------------------------------------------------------------------------------------- #
 
# Powershell AD Creator $Rev: 748 $
 
# (c) 2011 Thomas Maurer. All rights reserved.
 
# created by Thomas Maurer
 
# last Update by $Author: tmaurer $ on $Date: 2010-11-22 14:07:36 +0100 (Mo, 04 Nov 2011) $
 
# ---------------------------------------------------------------------------------------------- #
 
 
 
 
 
# Set Debug Mode (true/false)
 
$DebugOn = $false
 
 
 
 
 
 
 
#region [INFO BLOCK]
 
# INFO
 
Write-Host " " -BackgroundColor Black -ForegroundColor White
 
Write-Host "PowerShell AD Deplyoment" -BackgroundColor Black -ForegroundColor White
 
Write-Host " " -BackgroundColor Black -ForegroundColor White
 
Write-Host "Enter Credentials for Remote System:" -BackgroundColor Black -ForegroundColor White
 
#endregion
 
 
 
 
 
#region [VERBOSE BLOCK]
 
# Verbose Loop
 
 
 
if ($DebugOn -eq $true){
 
#Debug
 
Clear-Host
 
Write-Host "Debug mode on" -BackgroundColor Red -ForegroundColor White
 
$VerbosePreference = "Continue"
 
}
 
else {
 
#NoDebug
 
Clear-Host
 
$VerbosePreference = "SilentlyContinue"
 
}
 
#endregion
 
 
 
#region [CONFIG BLOCK]
 
# Get XML Information and create some funny objects...
 
<pre lang="xml">$global:xmlData = get-content ".\config.xml"
 
&nbsp;
 
# Get Credentials for Remotesystems
 
$cred = Get-Credential
 
&nbsp;
 
$global:xmlServer01 = $xmlData.lab.config.servers.server | Where-Object { $_.id -eq "1"}
 
$global:xmlServer02 = $xmlData.lab.config.servers.server | Where-Object { $_.id -eq "2"}
 
$global:xmlDomain = $xmlData.lab.config.ad.domain
 
$global:xmlOUS = $xmlData.lab.config.ous
 
&nbsp;
 
#endregion
 
&nbsp;
 
#region [FUNCTION BLOCK]
 
&nbsp;
 
function ConvertTo-Scriptblock {
 
&lt;#
 
Function to Convert a String into a Script Block
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$string
 
)
 
Begin {
 
Write-Verbose "Starting Begin Section"
 
}
 
Process {
 
Write-Verbose "Starting Process Section"
 
try {
 
Write-Verbose "Convert String to Scriptblock"
 
$sb = [scriptblock]::Create($string)
 
return $sb
 
}
 
catch {
 
Write-Host "Could not convert String to Scriptblock" $Error[0]
 
&nbsp;
 
}
 
}
 
End {
 
Write-Verbose "Starting End Section"
 
}
 
}
 
&nbsp;
 
&nbsp;
 
function Enable-ICMP {
 
&lt;#
 
Function to enable ICMP
 
&nbsp;
 
Enable-ICMP -hostip $xmlServer01.ip
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostip
 
)
 
begin {
 
# Write Command
 
$step001 = @"
 
netsh firewall set icmpsetting 8
 
"@
 
}
 
process {
 
try {
 
# Run Scriptblock
 
Write-Host "Enable ICMP on " $hostip "..." -BackgroundColor Black -ForegroundColor White
 
&nbsp;
 
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "ICMP successfully enabled..." -BackgroundColor Green -ForegroundColor Black
 
&nbsp;
 
&nbsp;
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Could not enable ICMP"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
function Create-ADServer {
 
&lt;#
 
Function to Create AD on the first Server
 
#&gt;
 
begin {
 
# Prepair for First AD Server
 
Write-Host "Preparing Script Block for " + $xmlServer01.name + "..." -BackgroundColor Black -ForegroundColor White
 
$domainName = $xmldomain.name
 
$domainNetBiosName = $xmldomain.netbiosname
 
$domainForestLevel = $xmldomain.forestlevel
 
$domainDomainLevel = $xmldomain.domainlevel
 
$domainSafemodePW = $xmldomain.safemodepw
 
$adTempFolder = "temp4"
 
$adTempPath = "C:\" + $adTempFolder
 
$adFilePath = $adTempPath + "\adinstall.txt"
 
}
 
process {
 
try {
 
# Script Block for First AD Server
 
$step001 = @"
 
New-Item -ItemType directory $adTempPath
 
New-Item -ItemType file $adFilePath
 
Add-Content $adFilePath "[DCINSTALL]"
 
Add-Content $adFilePath "InstallDNS=yes"
 
Add-Content $adFilePath "NewDomain=forest"
 
Add-Content $adFilePath "NewDomainDNSName=$domainName"
 
Add-Content $adFilePath "DomainNetBiosName=$domainNetBiosName"
 
Add-Content $adFilePath "ReplicaOrNewDomain=domain"
 
Add-Content $adFilePath "ForestLevel=$domainForestLevel"
 
Add-Content $adFilePath "DomainLevel=$domainDomainLevel"
 
Add-Content $adFilePath "RebootOnCompletion=yes"
 
Add-Content $adFilePath "SafeModeAdminPassword=$domainSafemodePW"
 
Write-Host "Unattend File created successfully..." - -BackgroundColor Green
 
dcpromo /unattend:$adFilePath
 
"@
 
# Run Scriptblock
 
Write-Host "Configure " $xmlServer01 "..." -BackgroundColor Black -ForegroundColor White
 
Invoke-Command -ComputerName $xmlServer01.ip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "Configuration for " $xmlServer01.name " successfully..." -BackgroundColor Green -ForegroundColor Black
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Could not Create AD"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
function Join-AD {
 
&lt;#
 
Function to add second AD Server
 
&nbsp;
 
Join-AD -hostname $xmlServer02.name -hostip $xmlServer02.ip -dnsip $xmlServer01.ip -domainName $xmldomain.name -adminpw $xmlServer01.adminpw
 
&nbsp;
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostname,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostip,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$dnsip,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$domainName,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$adminpw
 
)
 
begin {
 
# Prepair for Second AD Server
 
}
 
process {
 
try {
 
# Script Block join AD
 
$step001 = @"
 
netsh interface ipv4 add dnsserver name="Local Area Connection" address=$dnsip index=1
 
netdom join $hostname /domain:"$domainName" /userd:administrator /passwordd:$adminpw /REBoot
 
"@
 
&nbsp;
 
# Run Scriptblock
 
Write-Host "Adding " $hostname " to domain..." -BackgroundColor Black -ForegroundColor White
 
&nbsp;
 
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "Domainjoin for " $hostname " successfully..." -BackgroundColor Green -ForegroundColor Black
 
&nbsp;
 
&nbsp;
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Could not add System to AD"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
function Add-ADServer {
 
&lt;#
 
Function to add a second AD to the Domain
 
#&gt;
 
begin {
 
# Prepair for First AD Server
 
Write-Host "Preparing Script Block for DCPROMO " $xmlServer02.name "..." -BackgroundColor Black -ForegroundColor White
 
$server01ip = $xmlServer01.ip
 
$domainName = $xmldomain.name
 
$server01pw = $xmlServer01.adminpw
 
$domainSafemodePW = $xmldomain.safemodepw
 
}
 
process {
 
try {
 
# Script Block for First AD Server
 
$step001 = @"
 
Dcpromo /unattend /replicaOrnewDomain:replica /replicaDomainDNSName:$domainName /ConfirmGC:yes /username:administrator /Password:$server01pw /safeModeAdminPassword:$domainSafemodePW
 
"@
 
# Run Scriptblock
 
Write-Host "Running DCPROMO " $xmlServer02.name "..." -BackgroundColor Black -ForegroundColor White
 
Invoke-Command -ComputerName $xmlServer02.ip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "DCPROMO " $xmlServer02.name " successfully..." -BackgroundColor Green -ForegroundColor Black
 
}
 
catch {
 
throw "ERROR: Could not add Second Server to AD"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
function Add-ADOU {
 
&lt;#
 
Function to add OU to AD
 
&nbsp;
 
Add-ADOU -hostip $xmlServer01.ip -name $namedings -path $pathdings
 
&nbsp;
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostip,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$name,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$path
 
)
 
begin {
 
# Prepair for Second AD Server
 
}
 
process {
 
try {
 
# Script Block join AD
 
$step001 = @"
 
Import-Module ActiveDirectory
 
New-ADOrganizationalUnit -name "$name" -Path "$path"
 
"@
 
&nbsp;
 
# Run Scriptblock
 
Write-Host "Adding OU " $name " to " $path "..." -BackgroundColor Black -ForegroundColor White
 
&nbsp;
 
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "OU added " $name " successfully..." -BackgroundColor Green -ForegroundColor Black
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Could not add OU to AD"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
function Add-UsersfromFile {
 
&lt;#
 
Function to add OU to AD
 
&nbsp;
 
Add-UsersfromFile -hostip $xmlServer01.ip -filename $xmlData.lab.config.users.file.name -path $xmlData.lab.config.users.file.path
 
&nbsp;
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostip,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$SamAccountName,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$UserPrincipalName,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$name,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$DisplayName,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$GivenName,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$SurName,
 
[Parameter(
 
Mandatory = $false,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$Manager,
 
[Parameter(
 
Mandatory = $false,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$Department,
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$path
 
)
 
begin {
 
&nbsp;
 
}
 
process {
 
try {
 
# Script Block join AD
 
$step001 = @"
 
Import-Module ActiveDirectory
 
New-ADUser -SamAccountName $SamAccountName -UserPrincipalName $userprinicpalname -DisplayName $displayname -GivenName $GivenName -SurName $SurName -Path "$path" -AccountPassword (ConvertTo-SecureString "test41;" -AsPlainText -force)
 
"@
 
&nbsp;
 
# Run Scriptblock
 
Write-Host "Adding Users " $userprinicpalname " to " $path "..." -BackgroundColor Black -ForegroundColor White
 
&nbsp;
 
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
 
Write-Host "Users " $userprinicpalname " added successfully..." -BackgroundColor Green -ForegroundColor Black
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Could not add Users to AD"
 
}
 
}
 
end {
 
# Cleanup
 
$step001 = $null
 
}
 
}
 
&nbsp;
 
&nbsp;
 
function WaitFor-Host {
 
&lt;#
 
Function to wait for Host after Reboot
 
&nbsp;
 
WaitFor-Host -hostip $xmlServer01.ip -service servicename
 
&nbsp;
 
#&gt;
 
Param(
 
[Parameter(
 
Mandatory = $true,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$hostip,
 
[Parameter(
 
Mandatory = $false,
 
ParameterSetName = '',
 
ValueFromPipeline = $true)]
 
[string]$service
 
)
 
begin {
 
#
 
}
 
process {
 
try {
 
# Wait until Server is offline
 
Write-Host "Waiting for Reboot " $hostip "..." -BackgroundColor Black -ForegroundColor White
 
Start-Sleep -Seconds 10
 
&nbsp;
 
# Wait for Server Reboot
 
Write-Host "Waiting for Host " $hostip "..." -BackgroundColor Black -ForegroundColor White
 
while (!(Test-Connection $hostip -quiet)) {
 
Write-Host 'Unreachable!'
 
}
 
Write-Host "Server up..." -BackgroundColor Green -ForegroundColor Black
 
Start-Sleep -Seconds 30
 
}
 
catch {
 
# Sending status to CP and EventLog
 
throw "ERROR: Waiting for reboot failed"
 
}
 
}
 
end {
 
}
 
}
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
#endregion
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
#region [MAIN BLOCK]
 
&nbsp;
 
# Enable ICMP
 
Enable-ICMP -hostip $xmlServer01.ip
 
Enable-ICMP -hostip $xmlServer02.ip
 
&nbsp;
 
# Create first AD Server
 
Create-ADServer
 
Start-Sleep -Seconds 30
 
WaitFor-Host -hostip $xmlServer01.ip
 
&nbsp;
 
# Add Second AD Server to Domain
 
Join-AD -hostname $xmlServer02.name -hostip $xmlServer02.ip -dnsip $xmlServer01.ip -domainName $xmldomain.name -adminpw $xmlServer01.adminpw
 
Start-Sleep -Seconds 30
 
WaitFor-Host -hostip $xmlServer02.ip
 
&nbsp;
 
# Run DCPROMO on Second AD Server
 
Add-ADServer
 
&nbsp;
 
# Add OUs to Domain
 
foreach ($ou in $xmlOUS.ou){
 
Add-ADOU -hostip $xmlServer01.ip -name $ou.name -path $ou.path
 
}
 
&nbsp;
 
&nbsp;
 
# Add Users to Domain
 
foreach ($file in $xmlData.lab.config.users.file){
 
$tempfile = ".\" + $file.name
 
Import-Csv $tempfile | Foreach-Object {
 
$userprinicpalname = $_.SamAccountName + "@" + $xmlDomain.name
 
Add-UsersfromFile -hostip $xmlServer01.ip -SamAccountName $_.SamAccountName -UserPrincipalName $userprinicpalname -Name $_.name -DisplayName $_.name -GivenName $_.GivenName -SurName $_.SurName -Manager $_.Manager -Department $_.Department -Path $file.path
 
}
 
}
 
&nbsp;
 
&nbsp;
 
&nbsp;
 
# Add Members to Domain
 
foreach ($member in $xmlData.lab.config.members.member){
 
Join-AD -hostname $member.name -hostip $member.ip -dnsip $xmlServer01.ip -domainName $xmldomain.name -adminpw $xmlServer01.adminpw
 
}
 
&nbsp;
 
#endregion