Monday, August 18, 2008

Creating AD objects with Powershell - OUs - Part 1

When you have your management server to RDP into to manage your environment it is a good time to create some objects in your active directory, and it makes sense to start with the basic structure of Organizational Units (OUs).

You need to define the name of the OU and the Distinuguished Name of the domain and pass these in as variables and it would be useful if we checked if the OU already exists so that we can reduce errors we would get if the script was re-run with the same OUname passed to it:-


param([string]$ouname,$DomainDN)

$LDAPPATH = "LDAP://"+ $DomainDN
$search = [System.DirectoryServices.DirectorySearcher]$LDAPPATH
$search.Filter = "(&(name=$ouname)(objectCategory=organizationalunit))"
$result = $search.FindOne()

Next you need to check that the script didn't find an OU with that name then to create the OU, however if the OU already exists, simply record this in the install log:-

if ($result -eq $null) {
$date = get-date -uformat %d/%m/%y" "%H:%M:%S
$date + " Creating OU: " + $ouname>>C:\Install\Logs\ModularADInstall.log

$LDAPCONN = [adsi] $LDAPPATH$newou = $LDAPCONN.Create("OrganizationalUnit",$ouname) $newou.Put("description","AD Auto Deploy")$newou.SetInfo();
$date = get-date -uformat %d/%m/%y" "%H:%M:%S
$date + " Created OU: " + $ou>>C:\Install\Logs\ModularADInstall.log}

else{
$date = get-date -uformat %d/%m/%y" "%H:%M:%S
$date + " OU already exists : " + $ouname>>C:\Install\Logs\ModularADInstall.log}

Powershell - Simple Logging

A very simple yet useful way of dumping messages to a log file during the running of your powershell scripts is by using the following code snippet:-

$date = get-date -uformat %d/%m/%y" "%H:%M:%S
$date + " Creating OU: " + $ouname>>C:\Install\Logs\ModularADInstall.log


This code will basically log a message to file that begins with the date and time and then "Creating OU: followed by the vaule of the variable $ouname, the line in the log file could look something like this:-

18/08/08 13:15:40 Creating OU: OU1

If you want to change the date format then you can change this on the first line.

Adding a Machine to the Domain with powershell

The thing you might want to do just after you have setup your first domain controller and raised the functional levels of the domain and forest is create a management server that you will install all the tools required to administer the other servers (including the Domain Controllers) so that admins will not have to RDP directly to those servers.

There is a pretty simple script you can run on this management server to add it to the domain and it uses WMI to set this information on the machine, you can either hardcode the domain name, deployment username and password into the code or the best thing to do is pass them into the script as parameters:-

param([string]$DNSDomName,$pw,$DeployAcct)
$domainName=$DNSDomName
$domainPw=$pw
$domainAcc=$DNSDomName + "\" + $DeployAcct

$comp = get-wmiobject Win32_ComputerSystem
$comp.JoinDomainOrWorkGroup($domainName,$domainPw,$domainAcc,$null,3)


If you checked the domain the machine is a member of using system information at this point it would show the machine is a member of the domain, however you need to reboot the machine to complete the process.

Raising Active Directory Functional Levels with Powershell

It has been a while since I updated this blog but I have had a number of posts about using Powershell to automate Active Directory builds and this is a good a place as any.

So you have your first Domain Controller up and running after the post DCpromo reboot and you need to raise the functional level of the Domain and the forest to get the extra functionality that this give you.

The first job is to raise the domain functional level of this first domain, as the support for Active Directory built into Powershell is limited we use .Net framework:-

$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::getcurrentforest()

Here we can retrieve the domains in the current forest:-

$domains=$forest.domains

Next we go through each existing domain in turn and check the functional level, if you have just built the first domain you should only have one domain, and it should initially be set to Windows 2000 mixed, in order to raise this using Powershell you need to raise it to Windows 2000 native, then up to Windows 2003 functional level:-

foreach ($domain in $domains) {if ($domain.DomainMode -ne "Windows2003Domain") { $domain.RaiseDomainFunctionality('Windows2000NativeDomain') $domain.RaiseDomainFunctionality('Windows2003Domain') }}

So the script in full is:-

$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::getcurrentforest()
$domains=$forest.domains
foreach ($domain in $domains) {if ($domain.DomainMode -ne "Windows2003Domain") { $domain.RaiseDomainFunctionality('Windows2000NativeDomain') $domain.RaiseDomainFunctionality('Windows2003Domain') }}


This just raises the domain functional level, but to raise the forest functional level I tried putting it in the same script, and telling the script to sleep for some time before raising the forest functional level, in the end I just used a separate script that looks fairly similar:-

$forest = [System.DirectoryServices.ActiveDirectory.Forest]::getcurrentforest()
if ($forest.forestMode -ne "Windows2003Forest") {$forest.RaiseForestFunctionality("Windows2003Forest")}