Before going into details of creating a subnet object, first let us understand what is a Site and Subnet.
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”.
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: }