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.
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...
$global:xmlData = get-content ".\config.xml"
# Get Credentials for Remotesystems
$cred = Get-Credential
$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
#endregion
#region [FUNCTION BLOCK]
function ConvertTo-Scriptblock {
<#
Function to Convert a String into a Script Block
#>
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]
}
}
End {
Write-Verbose "Starting End Section"
}
}
function Enable-ICMP {
<#
Function to enable ICMP
Enable-ICMP -hostip $xmlServer01.ip
#>
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
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
Write-Host "ICMP successfully enabled..." -BackgroundColor Green -ForegroundColor Black
}
catch {
# Sending status to CP and EventLog
throw "ERROR: Could not enable ICMP"
}
}
end {
# Cleanup
$step001 = $null
}
}
function Create-ADServer {
<#
Function to Create AD on the first Server
#>
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
}
}
function Join-AD {
<#
Function to add second AD Server
Join-AD -hostname $xmlServer02.name -hostip $xmlServer02.ip -dnsip $xmlServer01.ip -domainName $xmldomain.name -adminpw $xmlServer01.adminpw
#>
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
"@
# Run Scriptblock
Write-Host "Adding " $hostname " to domain..." -BackgroundColor Black -ForegroundColor White
Invoke-Command -ComputerName $hostip -ScriptBlock (ConvertTo-Scriptblock -String $step001) -Credential $cred
Write-Host "Domainjoin for " $hostname " successfully..." -BackgroundColor Green -ForegroundColor Black
}
catch {
# Sending status to CP and EventLog
throw "ERROR: Could not add System to AD"
}
}
end {
# Cleanup
$step001 = $null
}
}
function Add-ADServer {
<#
Function to add a second AD to the Domain
#>
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
}
}
function Add-ADOU {
<#
Function to add OU to AD
Add-ADOU -hostip $xmlServer01.ip -name $namedings -path $pathdings
#>
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"
"@
# Run Scriptblock
Write-Host "Adding OU " $name " to " $path "..." -BackgroundColor Black -ForegroundColor White
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
}
}
function Add-UsersfromFile {
<#
Function to add OU to AD
Add-UsersfromFile -hostip $xmlServer01.ip -filename $xmlData.lab.config.users.file.name -path $xmlData.lab.config.users.file.path
#>
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 {
}
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)
"@
# Run Scriptblock
Write-Host "Adding Users " $userprinicpalname " to " $path "..." -BackgroundColor Black -ForegroundColor White
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
}
}
function WaitFor-Host {
<#
Function to wait for Host after Reboot
WaitFor-Host -hostip $xmlServer01.ip -service servicename
#>
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
# 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 {
}
}
#endregion
#region [MAIN BLOCK]
# Enable ICMP
Enable-ICMP -hostip $xmlServer01.ip
Enable-ICMP -hostip $xmlServer02.ip
# Create first AD Server
Create-ADServer
Start-Sleep -Seconds 30
WaitFor-Host -hostip $xmlServer01.ip
# 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
# Run DCPROMO on Second AD Server
Add-ADServer
# Add OUs to Domain
foreach ($ou in $xmlOUS.ou){
Add-ADOU -hostip $xmlServer01.ip -name $ou.name -path $ou.path
}
# 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
}
}
# 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
}
#endregion





