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... <pre lang="xml">$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
Tags: Active Directory, Config, CSV, Dcpromo, Deployment, install, Lab, Microsoft, PowerShell, Remoting, XML Last modified: December 12, 2011
Can you make these files available as text file downloads? Copying and pasting from web pages doesn’t always work. Great example of using an XML configuration file.
Sure I can :)
You can download the files here:
https://skydrive.live.com/redir.aspx?cid=7298a00d5b74ec3c&resid=7298A00D5B74EC3C!764&parid=7298A00D5B74EC3C!731
But don’t be surprise I did not have enough time to fix some bugs and some improper code… ;)
Very slick layout. How long did it take you to write?
Difficult to say… I think if I add all together, I needed maybe 2-3 hours… most of the time I needed was time for testing…