Active Directory Powershell to manage Sites and Subnets – Part 2 (New-XADSubnet)
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: https://technet.microsoft.com/en-us/library/cc782048(WS.10).aspx
|
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
Comments
- Anonymous
October 29, 2010
The comment has been removed - Anonymous
July 26, 2011
It seems the code references a function Get-XADSite which isn't defined in provided code. Can you please provide missing code? - Anonymous
February 29, 2012
The comment has been removed - Anonymous
March 27, 2012
I had to manually create the Get-XADSite function using code examples from the Part 3 of this series:blogs.msdn.com/.../active-directory-powershell-to-manage-sites-and-subnets-part-3-getting-site-and-subnets.aspxHere is the function that I put together:Get a specified Active Directory Site. function Get-XADSite() {
}I've tested this with the New-XADSite function and it works; just created 45 subnets and associated them with appropriate sites.Param ([String] $siteName)$configNCDN = (Get-ADRootDSE).ConfigurationNamingContext$siteContainerDN = ("CN=Sites," + $configNCDN)$siteDN = "CN=" + $siteName + "," + $siteContainerDNreturn Get-ADObject -Identity $siteDN
- Anonymous
May 14, 2012
thancks 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 # # Advanced Function to create a new subnet. # function New-XADSubnet() { [CmdletBinding(ConfirmImpact="Low")] Param ( [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, 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" )] [String] $Prefix, [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$false, HelpMessage="Site to which the subnet will be applied. Accepts Site name, Guid, DN or ADObject representing the site" )] [Object] $Site, [Parameter(Mandatory=$false, ValueFromPipeline=$false, HelpMessage="Description" )] [String] $Description, [Parameter(Mandatory=$false, ValueFromPipeline=$false, HelpMessage="Location" )] [String] $Location ) 30: PROCESS { if ([String]::IsNullOrEmpty($Prefix)) { throw New-Object System.Management.Automation.PSArgumentException("Prefix name cannot be an empty string, please try again.") } $newSubnetName = $Prefix if ($Prefix.Contains("/")) { $subnetIPAddressStr,$prefixLengthStr = $newSubnetName.Split("/") $subnetIPAddress = [System.Net.IPAddress]::Parse($subnetIPAddressStr) $specifiedPrefixLength = [int]::Parse($prefixLengthStr) $ipAddressPrefixLength = GetIPAddressPrefixLength $subnetIPAddress if ($ipAddressPrefixLength -gt $specifiedPrefixLength) { throw New-Object System.Management.Automation.PSArgumentException("The subnet prefix length you specified is incorrect. Please check the prefix and try again.") } } else { $subnetIPAddress = [System.Net.IPAddress]::Parse($newSubnetName) $prefixLength = GetIPAddressPrefixLength $subnetIPAddress $newSubnetName = $newSubnetName + "/" + $prefixLength } # Get the configuration partition DN, the sites container and build the new site DN $configNCDN = (Get-ADRootDSE).ConfigurationNamingContext $subnetContainerDN = ("CN=Subnets,CN=Sites," + $configNCDN) $newSubnetDN = ("CN=" + $newSubnetName +"," + $subnetContainerDN) $siteDN = $null if ($Site -ne $null) { $siteDN = (Get-XADSite $Site).DistinguishedName } # Verify if the subnet already exists $subnetExists = Test-XADObject -Identity $newSubnetDN if ($subnetExists) { throw New-Object System.Management.Automation.PSArgumentException("Subnet already exists. Please check the name and try again.") } [Hashtable] $ht = new-object -type hashtable if ($siteDN -ne $null) { $ht.Add("siteObject", $siteDN) } if (-not [String]::IsNullOrEmpty($Description)) { $ht.Add("description", $Description) } if (-not [String]::IsNullOrEmpty($Location)) { $ht.Add("location", $Location) } # Create subnet object if ($ht.Count -eq 0) { New-ADObject -Name $newSubnetName -Path $subnetContainerDN -Type subnet } else { New-ADObject -Name $newSubnetName -Path $subnetContainerDN -Type subnet -OtherAttributes $ht } # Fetch the subnet object Get-ADObject $newSubnetDN -properties "siteObject", "description", "location" } } # # Internal utility function # This function returns the number of trailing zeroes in the input byte # 100: function GetNumberOfTrailingZeroes { Param ([byte] $x) $numOfTrailingZeroes = 0; if ( $x -eq 0) { return 8 } if ( $x % 2 -eq 0) { $numOfTrailingZeroes ++; $numOfTrailingZeroes += GetNumberOfTrailingZeroes($x/2); } 110: return $numOfTrailingZeroes } # # Internal utility function # This function returns the number of non-zero bits in an ip-address # function GetIPAddressPrefixLength { Param ([System.Net.IPAddress] $ipAddress) $byteArray = $ipAddress.GetAddressBytes() $numOfTrailingZeroes = 0; 124: for ($i = $byteArray.Length - 1; $i -ge 0; $i--) { $numOfZeroesInByte = GetNumberOfTrailingZeroes($byteArray[$i]); if ($numOfZeroesInByte -eq 0) { break; } $numOfTrailingZeroes += $numOfZeroesInByte; } (($byteArray.Length * 8) - $numOfTrailingZeroes) }