ACTIVE DIRECTORY POWERSHELL TO MANAGE SITES – Part 1 (New-XADSite)

In this opportunity I am going to provide a solution to manage sites in your Active Directory (AD) forest by extending Active Directory PowerShell by implementing functions that allow creation, retrieval, update (moving to a site link, renaming) and deletion of sites.

First of all we need to understand what an AD site is made of. We can say that an AD site is represented by three directory objects and a reference in an attribute in a different object (i.e. the Site Link object). In detail an AD site is a compound of:

1. The site object (objectClass=site) which is an object under the sites object in the configuration naming context.

2. The NTDS site settings object (objectClass=nTDSSiteSettings) a child object under the site object

3. The servers containers object (objectClass=serversContainer) a child object under the site object

4. A value in the multi-valued attribute siteList in the site link object.

In the first place we need to know the sites container distinguished name (DN). This object has a relative distinguished name (RDN) with value Sites RDN under the configuration naming context. The following shows how to build the DN string for the sites container:

      $configNCDN = (Get-ADRootDSE).ConfigurationNamingContext

      $sitesContainerDN = ("CN=Sites," + $configNCDN)

The new site object will be an object under the sites container object:

      $newSiteDN = ("CN=" + $newSiteName +"," + $sitesContainerDN)

We can use the New-ADObject cmdlet to create the Site, NTDS Site Settings and Servers container objects under the Sites container object:

      New-ADObject -Name $newSiteName -Path $sitesContainerDN -Type site

      New-ADObject -Name "NTDS Site Settings" -Path $newSiteDN -Type nTDSSiteSettings

      New-ADObject -Name "Servers" -Path $newSiteDN -Type serversContainer

Now to add the site to the site link we will need a reference to the site link object. The site link objects are located under the given inter-site transport object (IP or SMTP). For example for DEFAULTIPSITELINK the site link container location will be:

      $siteLinkContainer = ("CN=DEFAULTIPSITELINK,CN=IP,CN=Inter-Site Transports,CN=Sites," + $configNCDN)

The last step is to add the site to the site link by including the site name in the siteList attribute in the respective site link object. To modify the siteList attribute in the site link object we will need to get the site link object first with the siteList attribute using using the Get-ADObject cmdlet to create an instance and then modify it using the Set-ADObject cmdlet:

      $siteLink = Get-ADObject $siteLinkContainer -Properties siteList

      $siteLink.siteList.Add($newSiteDN)

      Set-ADObject -Instance $siteLink

And that will be it.

I have created the function below called New-XADSite which receives the site name and the site link name (IP based, you can do a small modification to add SMTP based site links). Also it contains special cases validations which provide you a more reliable experience if you want to use the function in your AD forests. In future posts I will show you how to extend AD PowerShell to include functions to get the site names of the forest, moving a site to a different site link, renaming a site and removing a site in the forest. Notice that the script uses the function Test-XADObject which is implemented in a previous posting.

    1:  function New-XADSite() {
    2:     [CmdletBinding(ConfirmImpact="Low")]
    3:     Param (
    4:        [Parameter(Mandatory=$true,
    5:                   Position=0,
    6:                   ValueFromPipeline=$true,
    7:                   HelpMessage="Identity of the site to be created. Name is the only supported identity for this version of the script."
    8:                  )]
    9:        [Object] $Identity,
   10:        [Parameter(Mandatory=$false,
   11:                   Position=1,
   12:                   ValueFromPipeline=$false,
   13:                   HelpMessage="Site link name to which the site will belong."
   14:                  )]
   15:        [Object] $SiteLinkName
   16:     )
   17:   
   18:     BEGIN {
   19:   
   20:     }
   21:   
   22:     PROCESS {
   23:   
   24:        # In this version of the script the only identity supported is the site name
   25:        # Replace the line below to support other identities
   26:        $newSiteName = $Identity
   27:   
   28:        if ([String]::IsNullOrEmpty($newSiteName)) {
   29:           throw New-Object System.Management.Automation.PSArgumentException("Site name cannot be an empty string, please try again.")
   30:        }
   31:   
   32:        if ($SiteLinkName -eq $null) {
   33:           $SiteLinkName = "DEFAULTIPSITELINK"
   34:        }
   35:   
   36:        # Get the configuration partition DN, the sites container and build the new site DN
   37:        $configNCDN = (Get-ADRootDSE).ConfigurationNamingContext
   38:        $sitesContainerDN = ("CN=Sites," + $configNCDN)
   39:        $newSiteDN = ("CN=" + $newSiteName +"," + $sitesContainerDN)
   40:   
   41:        $siteLinkContainerDN = ("CN=" + $SiteLinkName + ",CN=IP,CN=Inter-Site Transports,CN=Sites," + $configNCDN)
   42:        # Verify if the site link exists
   43:        $siteLinkExists = Test-XADObject -Identity $siteLinkContainerDN
   44:        if ($siteLinkExists -eq $false) {
   45:           throw New-Object System.Management.Automation.RuntimeException("The site link you provided does not exist. Please check the name and try again.")
   46:        }
   47:   
   48:        # Verify if the site already exists
   49:        $siteExists = Test-XADObject -Identity $newSiteDN
   50:        if ($siteExists) {
   51:           throw New-Object System.Management.Automation.RuntimeException("Site already exists. Please check the name and try again.")
   52:        }
   53:        else {
   54:           $siteObjectCreated = $false
   55:   
   56:           trap [Exception] {
   57:              # Output the error to the pipeline
   58:              Write-Host $_
   59:   
   60:              # Remove any objects created for consistency
   61:              if ($siteObjectCreated -eq $true) {
   62:                 Remove-ADObject -Identity $newSiteDN -Recursive -Confirm:$false
   63:              }
   64:   
   65:              # Throw a new exception with the trapped exception as inner exception
   66:              throw New-Object System.Management.Automation.RuntimeException("An exception occurred when creating the site. See inner exceptions for more details.", $_.Exception)
   67:           }
   68:   
   69:           # Create Site, NTDS Site Settings and Server objects
   70:           New-ADObject -Name $newSiteName -Path $sitesContainerDN -Type site
   71:           $siteObjectCreated = $true
   72:           New-ADObject -Name "NTDS Site Settings" -Path $newSiteDN -Type nTDSSiteSettings
   73:           New-ADObject -Name "Servers" -Path $newSiteDN -Type serversContainer
   74:   
   75:           $siteLink = Get-ADObject $siteLinkContainerDN -Properties siteList
   76:           $numberOfSitesInSiteLink = $siteLink.siteList.Add($newSiteDN)
   77:           Set-ADObject -Instance $siteLink
   78:   
   79:           # Return the directory objects that make the AD site
   80:           Get-ADObject -Identity $newSiteDN
   81:           Get-ADObject -Identity ("CN=NTDS Site Settings," + $newSiteDN)
   82:           Get-ADObject -Identity ("CN=Servers," + $newSiteDN)
   83:        }
   84:   
   85:      }
   86:   
   87:      END {
   88:   
   89:      }
   90:  }

Enjoy,

Jairo Cadena

Active Directory