In an earlier post “Active Directory Powershell to manage sites – Part 1 (New-XADSite)” Jairo explained in detail about how to create a Site in Active Directory using AD Powershell. In today’s post I am going to discuss about how to create Subnets using AD Powershell.

Before going into details of creating a subnet object, first let us understand what is a Site and Subnet.

The following definition is from: http://technet.microsoft.com/en-us/library/cc782048(WS.10).aspx

In Active Directory, a site is a set of computers well-connected by a high-speed network, such as a local area network (LAN). All computers within the same site typically reside in the same building, or on the same campus network. A single site consists of one or more Internet Protocol (IP) subnets. Subnets are subdivisions of an IP network, with each subnet possessing its own unique network address. A subnet object in AD DS groups neighboring computers in much the same way that postal codes group neighboring postal addresses.

Sites and subnets are represented in Active Directory by site and subnet objects. Each site object is associated with one or more subnet objects. By associating a site with one or more subnets, you assign a set of IP addresses to the site.

NOTE: The term "subnet" in AD DS does not have the strict networking definition of the set of all addresses behind a single router. The only requirement for an AD DS subnet is that the address prefix conforms to the IP version 4 (IPv4) or IP version 6 (IPv6) format.

A subnet object (objectClass=subnet) in AD DS stores the prefix information in its name and the site information in attribute siteObject. It should be created under “CN=Subnets,CN=Sites,<Configuration-NC>”. For documentation on “how to determine the prefix of a subnet” bing for the phrase “Entering Address Prefixes”.

I have written a function below called New-XADSubnet that creates a new subnet. It accepts the subnet-prefix, site name, description and location of the subnet as input. The function also does some validation to provide a reliable experience, for example: it validates whether the specified subnet prefix length is correct or not. If a prefix length is not specified then this function will auto-generate the prefix length based on the number of trailing zero bits found in the prefix-ip-address.

NOTE: The script below uses Test-XADObject function published in a previous post.

   1:  #
   2:  # Advanced Function to create a new subnet.
   3:  #
   4:  function New-XADSubnet() {
   5:     [CmdletBinding(ConfirmImpact="Low")]
   6:     Param (
   7:        [Parameter(Mandatory=$true,
   8:                   Position=0,
   9:                   ValueFromPipeline=$true,
  10:                   HelpMessage="Prefix of the subnet to be created. This should be a combination of IP Address followed by / and Prefix length. IPv4 example: 157.54.208.0/20  IPv6 example: 3FFE:FFFF:0:C000::/64 . NOTE: If the prefix length is not specified then this cmdlet will auto-generate the prefix length based on the number of trailing zero bits. For example: If supplied Prefix is 157.54.208.0 then the subnet created is 157.54.208.0/20. Another example: If supplied Prefix is 3FFE:FFFF:0:C000:: then the subnet created is 3FFE:FFFF:0:C000::/34"
  11:                  )]
  12:        [String] $Prefix,
  13:        [Parameter(Mandatory=$false,
  14:                   Position=1,
  15:                   ValueFromPipeline=$false,
  16:                   HelpMessage="Site to which the subnet will be applied. Accepts Site name, Guid, DN or ADObject representing the site"
  17:                  )]
  18:        [Object] $Site,
  19:        [Parameter(Mandatory=$false,
  20:                   ValueFromPipeline=$false,
  21:                   HelpMessage="Description"
  22:                  )]
  23:        [String] $Description,
  24:        [Parameter(Mandatory=$false,
  25:                   ValueFromPipeline=$false,
  26:                   HelpMessage="Location"
  27:                  )]
  28:        [String] $Location
  29:     )
  30:     PROCESS {
  31:   
  32:        if ([String]::IsNullOrEmpty($Prefix)) {
  33:           throw New-Object System.Management.Automation.PSArgumentException("Prefix name cannot be an empty string, please try again.")
  34:        }
  35:        
  36:        $newSubnetName = $Prefix
  37:        
  38:        if ($Prefix.Contains("/")) {
  39:            $subnetIPAddressStr,$prefixLengthStr = $newSubnetName.Split("/")
  40:            $subnetIPAddress = [System.Net.IPAddress]::Parse($subnetIPAddressStr)
  41:            $specifiedPrefixLength = [int]::Parse($prefixLengthStr)
  42:            
  43:            $ipAddressPrefixLength = GetIPAddressPrefixLength $subnetIPAddress
  44:            if ($ipAddressPrefixLength -gt $specifiedPrefixLength) {
  45:                throw New-Object System.Management.Automation.PSArgumentException("The subnet prefix length you specified is incorrect. Please check the prefix and try again.")
  46:            }
  47:            
  48:        } else {
  49:            $subnetIPAddress = [System.Net.IPAddress]::Parse($newSubnetName)
  50:            $prefixLength = GetIPAddressPrefixLength $subnetIPAddress
  51:            $newSubnetName = $newSubnetName + "/" + $prefixLength
  52:        }
  53:   
  54:        # Get the configuration partition DN, the sites container and build the new site DN
  55:        $configNCDN = (Get-ADRootDSE).ConfigurationNamingContext
  56:        $subnetContainerDN = ("CN=Subnets,CN=Sites," + $configNCDN)
  57:        $newSubnetDN = ("CN=" + $newSubnetName +"," + $subnetContainerDN)
  58:        $siteDN = $null
  59:        if ($Site -ne $null) {
  60:            $siteDN = (Get-XADSite $Site).DistinguishedName
  61:        }
  62:   
  63:        # Verify if the subnet already exists
  64:        $subnetExists = Test-XADObject -Identity $newSubnetDN
  65:        if ($subnetExists) {
  66:           throw New-Object System.Management.Automation.PSArgumentException("Subnet already exists. Please check the name and try again.")
  67:        }
  68:        
  69:        [Hashtable] $ht = new-object -type hashtable
  70:        if ($siteDN -ne $null) {
  71:            $ht.Add("siteObject", $siteDN)
  72:        }
  73:        if (-not [String]::IsNullOrEmpty($Description)) {
  74:            $ht.Add("description", $Description)
  75:        }
  76:        if (-not [String]::IsNullOrEmpty($Location)) {
  77:            $ht.Add("location", $Location)
  78:        }
  79:   
  80:   
  81:        # Create subnet object 
  82:        if ($ht.Count -eq 0) {
  83:            New-ADObject -Name $newSubnetName -Path $subnetContainerDN -Type subnet 
  84:        } else {
  85:            New-ADObject -Name $newSubnetName -Path $subnetContainerDN -Type subnet -OtherAttributes $ht
  86:        }
  87:   
  88:        # Fetch the subnet object
  89:        Get-ADObject $newSubnetDN -properties "siteObject", "description", "location"
  90:   
  91:      }
  92:  }
  93:   
  94:   
  95:   
  96:  #
  97:  # Internal utility function
  98:  # This function returns the number of trailing zeroes in the input byte
  99:  #
 100:  function GetNumberOfTrailingZeroes {
 101:  Param ([byte] $x)
 102:  $numOfTrailingZeroes = 0;
 103:  if ( $x -eq 0) {
 104:     return 8
 105:  }
 106:  if ( $x % 2 -eq 0) {
 107:     $numOfTrailingZeroes ++;
 108:     $numOfTrailingZeroes +=  GetNumberOfTrailingZeroes($x/2);
 109:  }
 110:  return $numOfTrailingZeroes
 111:  }
 112:   
 113:   
 114:   
 115:   
 116:  #
 117:  # Internal utility function
 118:  # This function returns the number of non-zero bits in an ip-address
 119:  #
 120:  function GetIPAddressPrefixLength {
 121:  Param ([System.Net.IPAddress] $ipAddress)
 122:  $byteArray = $ipAddress.GetAddressBytes()
 123:  $numOfTrailingZeroes = 0;
 124:  for ($i = $byteArray.Length - 1; $i -ge 0; $i--) {
 125:      $numOfZeroesInByte = GetNumberOfTrailingZeroes($byteArray[$i]);
 126:      if ($numOfZeroesInByte -eq 0) {
 127:         break;
 128:      }
 129:      $numOfTrailingZeroes += $numOfZeroesInByte;
 130:  }
 131:  (($byteArray.Length * 8) - $numOfTrailingZeroes)
 132:  }

Sample usage in my test environment:

PS AD:\>
PS AD:\> New-XADSubnet "10.10.0.0/16"  -Location "Redmond,WA" -Description "Redmond Subnet"


Description       : Redmond Subnet
DistinguishedName : CN=10.10.0.0/16,CN=Subnets,CN=Sites,CN=Configuration,DC=dsw
                    amipat-w7-vm1,DC=nttest,DC=microsoft,DC=com
location          : Redmond,WA
Name              : 10.10.0.0/16
ObjectClass       : subnet
ObjectGUID        : e4c924ff-ee39-47e3-8b92-71a8600188af

Cheers,

Swami

--

Swaminathan Pattabiraman

Developer – Active Directory Powershell Team