PowerInfoblox.psm1
function Get-IPAddressRangeInformation { <# .SYNOPSIS Provides information about IP Address range .DESCRIPTION Provides information about IP Address range .PARAMETER Network Network in form of IP/NetworkLength (e.g. 10.2.10.0/24') .PARAMETER IPAddress IP Address to use .PARAMETER NetworkLength Network length to use .PARAMETER CIDRObject CIDRObject to use .EXAMPLE $CidrObject = @{ Ip = '10.2.10.0' NetworkLength = 24 } Get-IPAddressRangeInformation -CIDRObject $CidrObject | Format-Table .EXAMPLE Get-IPAddressRangeInformation -Network '10.2.10.0/24' | Format-Table .EXAMPLE Get-IPAddressRangeInformation -IPAddress '10.2.10.0' -NetworkLength 24 | Format-Table .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'Network')] param( [Parameter(ParameterSetName = 'Network', Mandatory)][string] $Network, [Parameter(ParameterSetName = 'IPAddress', Mandatory)][string] $IPAddress, [Parameter(ParameterSetName = 'IPAddress', Mandatory)][int] $NetworkLength, [Parameter(ParameterSetName = 'CIDR', Mandatory)][psobject] $CIDRObject ) $IPv4Regex = '(?:(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)' if ($Network) { $CIDRObject = @{ Ip = $Network.Split('/')[0] NetworkLength = $Network.Split('/')[1] } } elseif ($IPAddress -and $NetworkLength) { $CIDRObject = @{ Ip = $IPAddress NetworkLength = $NetworkLength } } elseif ($CIDRObject) { } else { Write-Error "Get-IPAddressRangeInformation - Invalid parameters specified" return } $o = [ordered] @{} $o.IP = [string] $CIDRObject.IP $o.BinaryIP = Convert-IPToBinary $o.IP if (-not $o.BinaryIP) { return } $o.NetworkLength = [int32] $CIDRObject.NetworkLength $o.SubnetMask = Convert-BinaryToIP ('1' * $o.NetworkLength).PadRight(32, '0') $o.BinarySubnetMask = ('1' * $o.NetworkLength).PadRight(32, '0') $o.BinaryNetworkAddress = $o.BinaryIP.SubString(0, $o.NetworkLength).PadRight(32, '0') if ($Contains) { if ($Contains -match "\A${IPv4Regex}\z") { return Test-IPIsInNetwork $Contains $o.BinaryNetworkAddress $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1') } else { Write-Error "Get-IPAddressRangeInformation - Invalid IPv4 address specified with -Contains" return } } $o.NetworkAddress = Convert-BinaryToIP $o.BinaryNetworkAddress if ($o.NetworkLength -eq 32 -or $o.NetworkLength -eq 31) { $o.HostMin = $o.IP } else { $o.HostMin = Convert-BinaryToIP ([System.Convert]::ToString(([System.Convert]::ToInt64($o.BinaryNetworkAddress, 2) + 1), 2)).PadLeft(32, '0') } [string] $BinaryBroadcastIP = $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1') $o.BinaryBroadcast = $BinaryBroadcastIP [int64] $DecimalHostMax = [System.Convert]::ToInt64($BinaryBroadcastIP, 2) - 1 [string] $BinaryHostMax = [System.Convert]::ToString($DecimalHostMax, 2).PadLeft(32, '0') $o.HostMax = Convert-BinaryToIP $BinaryHostMax $o.TotalHosts = [int64][System.Convert]::ToString(([System.Convert]::ToInt64($BinaryBroadcastIP, 2) - [System.Convert]::ToInt64($o.BinaryNetworkAddress, 2) + 1)) $o.UsableHosts = $o.TotalHosts - 2 if ($o.NetworkLength -eq 32) { $o.Broadcast = $Null $o.UsableHosts = [int64] 1 $o.TotalHosts = [int64] 1 $o.HostMax = $o.IP } elseif ($o.NetworkLength -eq 31) { $o.Broadcast = $Null $o.UsableHosts = [int64] 2 $o.TotalHosts = [int64] 2 [int64] $DecimalHostMax2 = [System.Convert]::ToInt64($BinaryBroadcastIP, 2) [string] $BinaryHostMax2 = [System.Convert]::ToString($DecimalHostMax2, 2).PadLeft(32, '0') $o.HostMax = Convert-BinaryToIP $BinaryHostMax2 } elseif ($o.NetworkLength -eq 30) { $o.UsableHosts = [int64] 2 $o.TotalHosts = [int64] 4 $o.Broadcast = Convert-BinaryToIP $BinaryBroadcastIP } else { $o.Broadcast = Convert-BinaryToIP $BinaryBroadcastIP } if ($Enumerate) { $IPRange = @(Get-IPRange $o.BinaryNetworkAddress $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1')) if ((31, 32) -notcontains $o.NetworkLength ) { $IPRange = $IPRange[1..($IPRange.Count - 1)] $IPRange = $IPRange[0..($IPRange.Count - 2)] } $o.IPEnumerated = $IPRange } else { $o.IPEnumerated = @() } [PSCustomObject]$o } function Join-UriQuery { <# .SYNOPSIS Provides ability to join two Url paths together including advanced querying .DESCRIPTION Provides ability to join two Url paths together including advanced querying which is useful for RestAPI/GraphApi calls .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url (optional) .PARAMETER QueryParameter Parameters and their values in form of hashtable .PARAMETER EscapeUriString If set, will escape the url string .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-UrlQuery')] [CmdletBinding()] param ( [parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory = $false)][uri] $RelativeOrAbsoluteUri, [Parameter()][System.Collections.IDictionary] $QueryParameter, [alias('EscapeUrlString')][switch] $EscapeUriString ) Begin { Add-Type -AssemblyName System.Web } Process { if ($BaseUri -and $RelativeOrAbsoluteUri) { $Url = Join-Uri -BaseUri $BaseUri -RelativeOrAbsoluteUri $RelativeOrAbsoluteUri } else { $Url = $BaseUri } if ($QueryParameter) { $Collection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($key in $QueryParameter.Keys) { $Collection.Add($key, $QueryParameter.$key) } } $uriRequest = [System.UriBuilder] $Url if ($Collection) { $uriRequest.Query = $Collection.ToString() } if (-not $EscapeUriString) { $uriRequest.Uri.AbsoluteUri } else { [System.Uri]::EscapeUriString($uriRequest.Uri.AbsoluteUri) } } } function Remove-EmptyValue { <# .SYNOPSIS Removes empty values from a hashtable recursively. .DESCRIPTION This function removes empty values from a given hashtable. It can be used to clean up a hashtable by removing keys with null, empty string, empty array, or empty dictionary values. The function supports recursive removal of empty values. .PARAMETER Hashtable The hashtable from which empty values will be removed. .PARAMETER ExcludeParameter An array of keys to exclude from the removal process. .PARAMETER Recursive Indicates whether to recursively remove empty values from nested hashtables. .PARAMETER Rerun Specifies the number of times to rerun the removal process recursively. .PARAMETER DoNotRemoveNull If specified, null values will not be removed. .PARAMETER DoNotRemoveEmpty If specified, empty string values will not be removed. .PARAMETER DoNotRemoveEmptyArray If specified, empty array values will not be removed. .PARAMETER DoNotRemoveEmptyDictionary If specified, empty dictionary values will not be removed. .EXAMPLE $hashtable = @{ 'Key1' = ''; 'Key2' = $null; 'Key3' = @(); 'Key4' = @{} } Remove-EmptyValue -Hashtable $hashtable -Recursive Description ----------- This example removes empty values from the $hashtable recursively. #> [alias('Remove-EmptyValues')] [CmdletBinding()] param( [alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable, [string[]] $ExcludeParameter, [switch] $Recursive, [int] $Rerun, [switch] $DoNotRemoveNull, [switch] $DoNotRemoveEmpty, [switch] $DoNotRemoveEmptyArray, [switch] $DoNotRemoveEmptyDictionary ) foreach ($Key in [string[]] $Hashtable.Keys) { if ($Key -notin $ExcludeParameter) { if ($Recursive) { if ($Hashtable[$Key] -is [System.Collections.IDictionary]) { if ($Hashtable[$Key].Count -eq 0) { if (-not $DoNotRemoveEmptyDictionary) { $Hashtable.Remove($Key) } } else { Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } } if ($Rerun) { for ($i = 0; $i -lt $Rerun; $i++) { Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive } } } function Select-Properties { <# .SYNOPSIS Allows for easy selecting property names from one or multiple objects .DESCRIPTION Allows for easy selecting property names from one or multiple objects. This is especially useful with using AllProperties parameter where we want to make sure to get all properties from all objects. .PARAMETER Objects One or more objects .PARAMETER Property Properties to include .PARAMETER ExcludeProperty Properties to exclude .PARAMETER AllProperties All unique properties from all objects .PARAMETER PropertyNameReplacement Default property name when object has no properties .EXAMPLE $Object1 = [PSCustomobject] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object2 = [PSCustomobject] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object1, $Object2 -AllProperties #OR: $Object1, $Object2 | Select-Properties -AllProperties -ExcludeProperty Name6 -Property Name3 .EXAMPLE $Object3 = [Ordered] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object4 = [Ordered] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object3, $Object4 -AllProperties $Object3, $Object4 | Select-Properties -AllProperties .NOTES General notes #> [CmdLetBinding()] param( [Array][Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] $Objects, [string[]] $Property, [string[]] $ExcludeProperty, [switch] $AllProperties, [string] $PropertyNameReplacement = '*' ) Begin { function Select-Unique { [CmdLetBinding()] param( [System.Collections.IList] $Object ) [Array] $CleanedList = foreach ($O in $Object) { if ($null -ne $O) { $O } } $New = $CleanedList.ToLower() | Select-Object -Unique $Selected = foreach ($_ in $New) { $Index = $Object.ToLower().IndexOf($_) if ($Index -ne -1) { $Object[$Index] } } $Selected } $ObjectsList = [System.Collections.Generic.List[Object]]::new() } Process { foreach ($Object in $Objects) { $ObjectsList.Add($Object) } } End { if ($ObjectsList.Count -eq 0) { Write-Warning 'Select-Properties - Unable to process. Objects count equals 0.' return } if ($ObjectsList[0] -is [System.Collections.IDictionary]) { if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $_.Keys } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].Keys } if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_ -and $ExcludeProperty -notcontains $_) { $_ continue } } } elseif ($Property.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_) { $_ continue } } } elseif ($ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($ExcludeProperty -notcontains $_) { $_ continue } } } } elseif ($ObjectsList[0].GetType().Name -match 'bool|byte|char|datetime|decimal|double|ExcelHyperLink|float|int|long|sbyte|short|string|timespan|uint|ulong|URI|ushort') { $FirstObjectProperties = $PropertyNameReplacement } else { if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property -ExcludeProperty $ExcludeProperty } elseif ($Property.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property } elseif ($ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property '*' -ExcludeProperty $ExcludeProperty } if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $ListProperties = $_.PSObject.Properties.Name if ($null -ne $ListProperties) { $ListProperties } } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].PSObject.Properties.Name } } $FirstObjectProperties } } function Write-Color { <# .SYNOPSIS Write-Color is a wrapper around Write-Host delivering a lot of additional features for easier color options. .DESCRIPTION Write-Color is a wrapper around Write-Host delivering a lot of additional features for easier color options. It provides: - Easy manipulation of colors, - Logging output to file (log) - Nice formatting options out of the box. - Ability to use aliases for parameters .PARAMETER Text Text to display on screen and write to log file if specified. Accepts an array of strings. .PARAMETER Color Color of the text. Accepts an array of colors. If more than one color is specified it will loop through colors for each string. If there are more strings than colors it will start from the beginning. Available colors are: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackGroundColor Color of the background. Accepts an array of colors. If more than one color is specified it will loop through colors for each string. If there are more strings than colors it will start from the beginning. Available colors are: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER StartTab Number of tabs to add before text. Default is 0. .PARAMETER LinesBefore Number of empty lines before text. Default is 0. .PARAMETER LinesAfter Number of empty lines after text. Default is 0. .PARAMETER StartSpaces Number of spaces to add before text. Default is 0. .PARAMETER LogFile Path to log file. If not specified no log file will be created. .PARAMETER DateTimeFormat Custom date and time format string. Default is yyyy-MM-dd HH:mm:ss .PARAMETER LogTime If set to $true it will add time to log file. Default is $true. .PARAMETER LogRetry Number of retries to write to log file, in case it can't write to it for some reason, before skipping. Default is 2. .PARAMETER Encoding Encoding of the log file. Default is Unicode. .PARAMETER ShowTime Switch to add time to console output. Default is not set. .PARAMETER NoNewLine Switch to not add new line at the end of the output. Default is not set. .PARAMETER NoConsoleOutput Switch to not output to console. Default all output goes to console. .EXAMPLE Write-Color -Text "Red ", "Green ", "Yellow " -Color Red,Green,Yellow .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan -StartTab 3 -LinesBefore 1 -LinesAfter 1 .EXAMPLE Write-Color "1. ", "Option 1" -Color Yellow, Green Write-Color "2. ", "Option 2" -Color Yellow, Green Write-Color "3. ", "Option 3" -Color Yellow, Green Write-Color "4. ", "Option 4" -Color Yellow, Green Write-Color "9. ", "Press 9 to exit" -Color Yellow, Gray -LinesBefore 1 .EXAMPLE Write-Color -LinesBefore 2 -Text "This little ","message is ", "written to log ", "file as well." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" -TimeFormat "yyyy-MM-dd HH:mm:ss" Write-Color -Text "This can get ","handy if ", "want to display things, and log actions to file ", "at the same time." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" .EXAMPLE Write-Color -T "My text", " is ", "all colorful" -C Yellow, Red, Green -B Green, Green, Yellow Write-Color -t "my text" -c yellow -b green Write-Color -text "my text" -c red .EXAMPLE Write-Color -Text "Testuję czy się ładnie zapisze, czy będą problemy" -Encoding unicode -LogFile 'C:\temp\testinggg.txt' -Color Red -NoConsoleOutput .NOTES Understanding Custom date and time format strings: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings Project support: https://github.com/EvotecIT/PSWriteColor Original idea: Josh (https://stackoverflow.com/users/81769/josh) #> [alias('Write-Colour')] [CmdletBinding()] param ( [alias ('T')] [String[]]$Text, [alias ('C', 'ForegroundColor', 'FGC')] [ConsoleColor[]]$Color = [ConsoleColor]::White, [alias ('B', 'BGC')] [ConsoleColor[]]$BackGroundColor = $null, [alias ('Indent')][int] $StartTab = 0, [int] $LinesBefore = 0, [int] $LinesAfter = 0, [int] $StartSpaces = 0, [alias ('L')] [string] $LogFile = '', [Alias('DateFormat', 'TimeFormat')][string] $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss', [alias ('LogTimeStamp')][bool] $LogTime = $true, [int] $LogRetry = 2, [ValidateSet('unknown', 'string', 'unicode', 'bigendianunicode', 'utf8', 'utf7', 'utf32', 'ascii', 'default', 'oem')][string]$Encoding = 'Unicode', [switch] $ShowTime, [switch] $NoNewLine, [alias('HideConsole')][switch] $NoConsoleOutput ) if (-not $NoConsoleOutput) { $DefaultColor = $Color[0] if ($null -ne $BackGroundColor -and $BackGroundColor.Count -ne $Color.Count) { Write-Error "Colors, BackGroundColors parameters count doesn't match. Terminated." return } if ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line before if ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host -Object "`t" -NoNewline } } # Add TABS before text if ($StartSpaces -ne 0) { for ($i = 0; $i -lt $StartSpaces; $i++) { Write-Host -Object ' ' -NoNewline } } # Add SPACES before text if ($ShowTime) { Write-Host -Object "[$([datetime]::Now.ToString($DateTimeFormat))] " -NoNewline } # Add Time before output if ($Text.Count -ne 0) { if ($Color.Count -ge $Text.Count) { # the real deal coloring if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewline } } else { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewline } } } else { if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewline } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -NoNewline } } else { for ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewline } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $BackGroundColor[0] -NoNewline } } } } if ($NoNewLine -eq $true) { Write-Host -NoNewline } else { Write-Host } # Support for no new line if ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host -Object "`n" -NoNewline } } # Add empty line after } if ($Text.Count -and $LogFile) { # Save to file $TextToFile = "" for ($i = 0; $i -lt $Text.Length; $i++) { $TextToFile += $Text[$i] } $Saved = $false $Retry = 0 Do { $Retry++ try { if ($LogTime) { "[$([datetime]::Now.ToString($DateTimeFormat))] $TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append -ErrorAction Stop -WhatIf:$false } else { "$TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append -ErrorAction Stop -WhatIf:$false } $Saved = $true } catch { if ($Saved -eq $false -and $Retry -eq $LogRetry) { Write-Warning "Write-Color - Couldn't write to log file $($_.Exception.Message). Tried ($Retry/$LogRetry))" } else { Write-Warning "Write-Color - Couldn't write to log file $($_.Exception.Message). Retrying... ($Retry/$LogRetry)" } } } Until ($Saved -eq $true -or $Retry -ge $LogRetry) } } function Convert-BinaryToIP { <# .SYNOPSIS Converts a binary string to an IP address format. .DESCRIPTION This function takes a binary string as input and converts it to an IP address format. The binary string must be evenly divisible by 8. .PARAMETER Binary The binary string to convert to an IP address format. .EXAMPLE Convert-BinaryToIP -Binary "01000001000000100000000100000001" Output: 65.0.1.1 #> [cmdletBinding()] param( [string] $Binary ) $Binary = $Binary -replace '\s+' if ($Binary.Length % 8) { Write-Warning -Message "Convert-BinaryToIP - Binary string '$Binary' is not evenly divisible by 8." return $Null } [int] $NumberOfBytes = $Binary.Length / 8 $Bytes = @(foreach ($i in 0..($NumberOfBytes - 1)) { try { [System.Convert]::ToByte($Binary.Substring(($i * 8), 8), 2) } catch { Write-Warning -Message "Convert-BinaryToIP - Error converting '$Binary' to bytes. `$i was $i." return $Null } }) return $Bytes -join '.' } function Convert-IPToBinary { <# .SYNOPSIS Converts an IPv4 address to binary format. .DESCRIPTION This function takes an IPv4 address as input and converts it to binary format. .PARAMETER IP Specifies the IPv4 address to convert to binary format. .EXAMPLE Convert-IPToBinary -IP "192.168.1.1" Converts the IPv4 address "192.168.1.1" to binary format. .EXAMPLE Convert-IPToBinary -IP "10.0.0.1" Converts the IPv4 address "10.0.0.1" to binary format. #> [cmdletBinding()] param( [string] $IP ) $IPv4Regex = '(?:(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)' $IP = $IP.Trim() if ($IP -match "\A${IPv4Regex}\z") { try { return ($IP.Split('.') | ForEach-Object { [System.Convert]::ToString([byte] $_, 2).PadLeft(8, '0') }) -join '' } catch { Write-Warning -Message "Convert-IPToBinary - Error converting '$IP' to a binary string: $_" return $Null } } else { Write-Warning -Message "Convert-IPToBinary - Invalid IP detected: '$IP'. Conversion failed." return $Null } } function Get-IPRange { <# .SYNOPSIS Generates a list of IP addresses within a specified binary range. .DESCRIPTION This function takes two binary strings representing the start and end IP addresses and generates a list of IP addresses within that range. .PARAMETER StartBinary Specifies the starting IP address in binary format. .PARAMETER EndBinary Specifies the ending IP address in binary format. .EXAMPLE Get-IPRange -StartBinary '11000000' -EndBinary '11000010' Description: Generates a list of IP addresses between '192.0.0.0' and '192.0.2.0'. .EXAMPLE Get-IPRange -StartBinary '10101010' -EndBinary '10101100' Description: Generates a list of IP addresses between '170.0.0.0' and '172.0.0.0'. #> [cmdletBinding()] param( [string] $StartBinary, [string] $EndBinary ) [int64] $StartInt = [System.Convert]::ToInt64($StartBinary, 2) [int64] $EndInt = [System.Convert]::ToInt64($EndBinary, 2) for ($BinaryIP = $StartInt; $BinaryIP -le $EndInt; $BinaryIP++) { Convert-BinaryToIP ([System.Convert]::ToString($BinaryIP, 2).PadLeft(32, '0')) } } function Join-Uri { <# .SYNOPSIS Provides ability to join two Url paths together .DESCRIPTION Provides ability to join two Url paths together .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url .EXAMPLE Join-Uri 'https://evotec.xyz/' '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri 'https://evotec.xyz/' 'wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/test/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-Url')] [cmdletBinding()] param( [parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory)][uri] $RelativeOrAbsoluteUri ) return ($BaseUri.OriginalString.TrimEnd('/') + "/" + $RelativeOrAbsoluteUri.OriginalString.TrimStart('/')) } function Test-IPIsInNetwork { <# .SYNOPSIS Checks if an IP address falls within a specified range defined by binary start and end values. .DESCRIPTION This function compares the binary representation of an IP address with the binary start and end values to determine if the IP address falls within the specified range. .EXAMPLE Test-IPIsInNetwork -IP "192.168.1.10" -StartBinary "11000000101010000000000100000000" -EndBinary "11000000101010000000000111111111" Description: Checks if the IP address 192.168.1.10 falls within the range defined by the binary start and end values. #> [cmdletBinding()] param( [string] $IP, [string] $StartBinary, [string] $EndBinary ) $TestIPBinary = Convert-IPToBinary $IP [int64] $TestIPInt64 = [System.Convert]::ToInt64($TestIPBinary, 2) [int64] $StartInt64 = [System.Convert]::ToInt64($StartBinary, 2) [int64] $EndInt64 = [System.Convert]::ToInt64($EndBinary, 2) if ($TestIPInt64 -ge $StartInt64 -and $TestIPInt64 -le $EndInt64) { return $True } else { return $False } } function Convert-IpAddressToPtrString { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$IPAddress ) # Split the IP address into its octets $octets = $IPAddress -split "\." # Reverse the octets [array]::Reverse($octets) # Join the reversed octets with dots and append the standard PTR suffix $ptrString = ($octets -join ".") + ".in-addr.arpa" $ptrString } function Get-FieldsFromSchema { [CmdletBinding()] param( [PSCustomobject] $Schema, [string] $SchemaObject ) if (-not $Script:InfobloxSchemaFields) { $Script:InfobloxSchemaFields = [ordered] @{} } if ($Script:InfobloxSchemaFields[$SchemaObject]) { $Script:InfobloxSchemaFields[$SchemaObject] } else { if (-not $Schema) { $Schema = Get-InfobloxSchema -Object $SchemaObject } if ($Schema -and $Schema.fields.name) { $FilteredFields = foreach ($Field in $Schema.fields) { if ($Field.supports -like "*r*") { $Field.Name } } $Script:InfobloxSchemaFields[$SchemaObject] = ($FilteredFields -join ',') $Script:InfobloxSchemaFields[$SchemaObject] } else { Write-Warning -Message "Get-FieldsFromSchema - Failed to fetch schema for record type 'allrecords'. Using defaults" } } } function Hide-SelfSignedCerts { [cmdletbinding()] param( ) if ($PSVersionTable.PSVersion.Major -gt 5) { #Write-Warning -Message "Hide-SelfSignedCerts - This function is only supported in PowerShell 6 and later" $Script:InfobloxConfiguration['SkipCertificateValidation'] = $true return } try { Add-Type -TypeDefinition @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = [TrustAllCertsPolicy]::new() } catch { Write-Warning -Message "Hide-SelfSignedCerts - Error when trying to hide self-signed certificates: $($_.Exception.Message)" } } function New-WebSession { [cmdletbinding()] param( [System.Collections.IDictionary]$Cookies, [Uri]$For ) $newSession = [Microsoft.PowerShell.Commands.WebRequestSession]::new() foreach ($entry in $Cookies.GetEnumerator()) { $cookie = [System.Net.Cookie]::new($entry.Name, $entry.Value) if ($For) { $newSession.Cookies.Add([uri]::new($For, '/'), $cookie) } else { $newSession.Cookies.Add($cookie) } } $newSession } function Select-ObjectByProperty { [CmdletBinding()] param( [Parameter(Position = 0, ValueFromPipeline)][Array] $Object, [System.Collections.IDictionary] $AddObject, [alias('FirstProperty')][Parameter()][string[]] $FirstProperties, [alias('LastProperty')][Parameter()][string[]] $LastProperties, [string[]] $AllProperties ) process { foreach ($O in $Object) { # If we have an object, we can get the properties from it # we assume user can provide AllProperties instead of current object properties $Properties = if ($AllProperties) { $AllProperties } else { $O.PSObject.Properties.Name } $ReturnObject = [ordered] @{} foreach ($Property in $FirstProperties) { if ($Properties -contains $Property) { $ReturnObject[$Property] = $O.$Property } } if ($AddObject) { foreach ($Property in $AddObject.Keys) { $ReturnObject[$Property] = $AddObject[$Property] } } foreach ($Property in $Properties) { if ($Property -notin $LastProperties -and $Property -notin $FirstProperties) { $ReturnObject[$Property] = $O.$Property } } foreach ($Property in $LastProperties) { if ($Properties -contains $Property) { $ReturnObject[$Property] = $O.$Property } } [pscustomobject]$ReturnObject } } } function Add-InfobloxDHCPRange { <# .SYNOPSIS Adds a DHCP range to Infoblox. .DESCRIPTION This function adds a DHCP range to Infoblox. It requires an established connection to an Infoblox server, which can be done using the Connect-Infoblox function. .PARAMETER StartAddress The starting IP address of the DHCP range. This parameter is mandatory. .PARAMETER EndAddress The ending IP address of the DHCP range. This parameter is mandatory. .PARAMETER Name The name of the DHCP range. .PARAMETER Comment A comment for the DHCP range. .PARAMETER NetworkView The network view in which the DHCP range will be added. The default is 'default'. .PARAMETER MSServer The Microsoft server to which the DHCP range will be added. .PARAMETER ReturnOutput If this switch is present, the function will return the output of the operation. .PARAMETER ExtensibleAttribute An extensible attribute to be added to the DHCP range. .PARAMETER FailoverAssociation The failover association for the DHCP range. .PARAMETER Options An array of options to be added to the DHCP range. .PARAMETER MSOptions An array of Microsoft options to be added to the DHCP range. .PARAMETER ServerAssociationType The server association type for the DHCP range. The possible values are 'MEMBER', 'MS_FAILOVER', 'NONE', 'MS_SERVER', 'FAILOVER'. .PARAMETER Exclude An array of IP addresses or IP address ranges to be excluded from the DHCP range. .PARAMETER AlwaysUpdateDns If this switch is present, DNS will always be updated for the DHCP range. .PARAMETER Disable If this switch is present, the DHCP range will be disabled. .EXAMPLE Add-InfobloxDHCPRange -StartAddress '192.168.1.100' -EndAddress '192.168.1.200' -Name 'DHCP Range 1' -Comment 'This is a DHCP range.' Adds a DHCP range from 192.168.1.100 to 192.168.1.200 with the name 'DHCP Range 1' and a comment 'This is a DHCP range.'. .EXAMPLE Add-InfobloxDHCPRange -StartAddress '10.22.41.15' -EndAddress '10.22.41.30' Adds a reserved range from 10.22.41.15 to 10.22.41.30 .EXAMPLE $addInfobloxDHCPRangeSplat = @{ StartAddress = '10.22.41.51' EndAddress = '10.22.41.60' Verbose = $true MSServer = 'dhcp2016.evotec.pl' Name = 'DHCP Range Me?' ServerAssociationType = 'MS_SERVER' } Add-InfobloxDHCPRange @addInfobloxDHCPRangeSplat .EXAMPLE $addInfobloxDHCPRangeSplat = @{ StartAddress = '10.22.41.70' EndAddress = '10.22.41.90' Verbose = $true MSServer = 'dhcp2019.evotec.pl' Name = 'DHCP Range Me2?' ServerAssociationType = 'MS_SERVER' Exclude = '10.22.41.75-10.22.41.79' } Add-InfobloxDHCPRange @addInfobloxDHCPRangeSplat .EXAMPLE $addInfobloxDHCPRangeSplat = @{ StartAddress = '10.10.12.5' EndAddress = '10.10.12.10' Options = @( New-InfobloxOption -Name "dhcp-lease-time" -Number 51 -UseOption -Value '86400' -VendorClass 'DHCP' New-InfobloxOption -Name "domain-name-servers" -Number 6 -UseOption -Value '192.168.0.15' -VendorClass 'DHCP' New-InfobloxOption -Name 'routers' -Number 3 -UseOption -Value '192.168.11.12' -VendorClass 'DHCP' New-InfobloxOption -Name 'time-servers' -Number 4 -UseOption -Value '11' -VendorClass 'DHCP' ) Verbose = $true } Add-InfobloxDHCPRange @addInfobloxDHCPRangeSplat .NOTES You must first connect to an Infoblox server using Connect-Infoblox before running this function. Please note that when using MSServer parameter you need to provide a valid server name that is already added to Infoblox, and it also needs to be part of Members in Add-InfobloxNetwork. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][string] $StartAddress, [Parameter(Mandatory)][string] $EndAddress, [string] $Name, [string] $Comment, [string] $NetworkView = 'default', [string] $MSServer, [switch] $ReturnOutput, [System.Collections.IDictionary] $ExtensinbleAttribute, [Array] $Options, [Alias('ms_options')][Array] $MSOptions, [alias('failover_association')][string] $FailoverAssociation, [ValidateSet('MEMBER', 'MS_FAILOVER', 'NONE', 'MS_SERVER', 'FAILOVER')] [string] $ServerAssociationType, [Array] $Exclude, [switch] $AlwaysUpdateDns, [switch] $Disable ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxDHCPRange - You must first connect to an Infoblox server using Connect-Infoblox' return } $Body = [ordered] @{ "start_addr" = $StartAddress "end_addr" = $EndAddress "network_view" = $NetworkView } if ($Name) { $Body["name"] = $Name } if ($Comment) { $Body["comment"] = $Comment } if ($ServerAssociationType) { $Body["server_association_type"] = $ServerAssociationType } if ($MSServer) { $Body["ms_server"] = [PSCustomObject] @{ "_struct" = "msdhcpserver" "ipv4addr" = $MSServer } } if ($ExtensinbleAttribute) { $Body["extattrs"] = [ordered] @{} foreach ($Key in $ExtensinbleAttribute.Keys) { if ($ExtensinbleAttribute[$Key] -is [System.Collections.IDictionary]) { $Body["extattrs"][$Key] = $ExtensinbleAttribute[$Key] } else { $Body["extattrs"][$Key] = @{ value = $ExtensinbleAttribute[$Key] } } } } if ($Options) { $Body["options"] = @( foreach ($Option in $Options) { $Option } ) } if ($MSOptions) { $Body["ms_options"] = @( foreach ($MSOption in $MSOptions) { $MSOption } ) } if ($FailoverAssociation) { $Body["failover_association"] = $FailoverAssociation } if ($Exclude) { $Body["exclude"] = @( foreach ($ExcludeItem in $Exclude) { if ($ExcludeItem -is [string]) { if ($ExcludeItem -like "*-*") { $ExcludeItem = $ExcludeItem -split '-' $ExcludeItem = @{ StartAddress = $ExcludeItem[0] EndAddress = $ExcludeItem[1] } } else { $ExcludeItem = @{ StartAddress = $ExcludeItem EndAddress = $ExcludeItem } } } [ordered] @{ "start_address" = $ExcludeItem.StartAddress "end_address" = $ExcludeItem.EndAddress } } ) } if ($PSBoundParameters.ContainsKey('AlwaysUpdateDns')) { $Body["always_update_dns"] = $AlwaysUpdateDns.IsPresent } if ($PSBoundParameters.ContainsKey('Disable')) { $Body["disable"] = $Disable.IsPresent } Remove-EmptyValue -Hashtable $Body $invokeInfobloxQuerySplat = @{ RelativeUri = "range" Method = 'POST' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Add-InfobloxDHCPRange - $Output" if ($ReturnOutput) { $Output } } } function Add-InfobloxDHCPRangeOptions { <# .SYNOPSIS Adds DHCP range options to an Infoblox server. .DESCRIPTION This function adds specified DHCP range options to an Infoblox server. It allows adding options and Microsoft-specific options for a given network or reference ID. .PARAMETER Type Specifies the type of options to add. Valid values are 'Options' and 'MsOptions'. .PARAMETER Network The network for which to add DHCP options. .PARAMETER ReferenceID The unique identifier for the DHCP range to be modified. .PARAMETER Name The name of the DHCP option to be added. .PARAMETER Number The number of the DHCP option. .PARAMETER Value The value of the DHCP option. .PARAMETER VendorClass The vendor class of the DHCP option. .PARAMETER UseOption Indicates whether to use the option. .EXAMPLE Add-InfobloxDHCPRangeOptions -Type 'Options' -Network '192.168.1.0/24' -Name 'domain-name-servers' -Number 6 -Value '192.168.0.15' -VendorClass 'DHCP' -UseOption .EXAMPLE Add-InfobloxDHCPRangeOptions -Type 'MsOptions' -ReferenceID 'DHCPRange-1' -Name 'time-servers' -Number 4 -Value '11' -VendorClass 'DHCP' .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)] [ValidateSet('Options', 'MsOptions')] [string] $Type, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [string] $Network, [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $ReferenceID, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $Name, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [alias('Num')][System.Nullable[int]] $Number, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [string] $Value, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [string] $VendorClass, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [switch] $UseOption ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxDHCPRangeOptions - You must first connect to an Infoblox server using Connect-Infoblox' return } $Object = [ordered] @{ "name" = $Name "num" = $Number "use_option" = if ($PSBoundParameters.ContainsKey('UseOption')) { $UseOption.IsPresent } else { $null } "value" = $Value "vendor_class" = $VendorClass } if ($Type -eq 'options') { } else { if ($UseOption.IsPresent) { Write-Warning -Message 'Add-InfobloxDHCPRangeOptions - use_option is not a valid parameter for MSOptions' $Object.Remove('use_option') } } Remove-EmptyValue -Hashtable $Object if ($Network) { $DHCPRange = Get-InfobloxDHCPRange -Network $Network -ReturnFields 'options', 'ms_options' } elseif ($ReferenceID) { $DHCPRange = Get-InfobloxDHCPRange -ReferenceID $ReferenceID -ReturnFields 'options', 'ms_options' } else { Write-Warning -Message 'You must specify either a Network or a ReferenceID' return } if (-not $DHCPRange -or $null -eq $DHCPRange._ref) { Write-Warning -Message 'Add-InfobloxDHCPRangeOptions - No DHCP Range found' return } $OptionFound = $false [Array] $NewOptions = @( if ($Type -eq 'options') { $Options = $DHCPRange.options | Select-Object -Property name, num, use_option, value, vendor_class foreach ($Option in $Options) { if ($Option.name -eq $Name) { $OptionFound = $true break } else { $Option } } if (-not $OptionFound) { Write-Verbose -Message "Add-InfobloxDHCPRangeOptions - Changes required for $Name. Does not exist yet!" $Object } } else { $MSOptions = $DHCPRange.ms_options | Select-Object -Property name, num, value, vendor_class foreach ($MSOption in $MSOptions) { if ($MSOption.name -eq $Name) { $OptionFound = $true break } else { $MSOption } } if (-not $OptionFound) { Write-Verbose -Message "Add-InfobloxDHCPRangeOptions - Changes required for $Name. Does not exist yet!" $Object } } ) if (-not $OptionFound) { if ($Type -eq 'options') { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -Options $NewOptions } else { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -MSOptions $NewOptions } } else { Write-Warning -Message 'Add-InfobloxDHCPRangeOptions - No changes required' } } function Add-InfobloxDHCPReservation { <# .SYNOPSIS Add a DHCP reservation to an Infoblox server .DESCRIPTION Add a DHCP reservation to an Infoblox server .PARAMETER IPv4Address IPv4 address to add the mac address to .PARAMETER MacAddress Mac address to add to the IPv4 address .PARAMETER Name Name of the fixed address .PARAMETER Comment Comment for the fixed address .PARAMETER Network Subnet to add the reservation to .PARAMETER MicrosoftServer Microsoft server to use for the fixed address .EXAMPLE Add-InfobloxDHCPReservation -IPv4Address '10.2.2.18' -MacAddress '00:50:56:9A:00:01' -Name 'MyReservation' -Network '10.2.2.0/24' -Comment 'This is a test reservation' -MicrosoftServer 'myserver' .NOTES General notes #> [CmdletBinding(SupportsShouldProcess)] param( [ValidateNotNullOrEmpty()][parameter(Mandatory)][string] $IPv4Address, [ValidatePattern("([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")][parameter(Mandatory)][string] $MacAddress, [ValidateNotNullOrEmpty()][parameter(Mandatory)][string] $Name, [ValidateNotNullOrEmpty()][parameter(Mandatory)][string] $Network, [string] $Comment, [alias('ms_server')][string] $MicrosoftServer ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxDHCPReservation - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = 'record:dhcpreservation' Method = 'POST' QueryParameter = @{ ipv4addr = $IPv4Address mac = $MacAddress.ToLower() network = $Network } } if ($Name) { $invokeInfobloxQuerySplat.QueryParameter.name = $Name } if ($Comment) { $invokeInfobloxQuerySplat.QueryParameter.comment = $Comment } if ($MicrosoftServer) { $invokeInfobloxQuerySplat.QueryParameter.ms_server = $MicrosoftServer } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Add-InfobloxDHCPReservation - Added $($Output.ipv4addr) with mac address $($Output.mac) / $Output" } } function Add-InfoBloxDNSRecord { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .PARAMETER IPAddress Parameter description .PARAMETER CanonicalName Parameter description .PARAMETER PtrName Parameter description .PARAMETER Type Parameter description .EXAMPLE Add-InfoBloxDNSRecord -Name 'Test' -IPv4Address '10.10.10.10' -Type 'A' .EXAMPLE Add-InfoBloxDNSRecord -Name 'Test' -IPv4Address '10.10.10.10' -Type 'HOST' .EXAMPLE Add-InfoBloxDNSRecord -Name 'Test' -CanonicalName 'test2.mcdonalds.com' -Type 'CNAME' .NOTES General notes #> [CmdletBinding(SupportsShouldProcess)] param( [string] $Name, [Alias('IPv4Address', 'IPv6Address')][string] $IPAddress, [string] $CanonicalName, [string] $PtrName, [string] $Text, [parameter(Mandatory)][ValidateSet( 'A', #'AAAA', 'CNAME', 'HOST', 'PTR' #'DName', #'DNSKEY', 'DS', 'Host', 'host_ipv4addr', 'host_ipv6addr', #'LBDN', 'MX', 'NAPTR', 'NS', 'NSEC', #'NSEC3', 'NSEC3PARAM', 'PTR', 'RRSIG', 'SRV', 'TXT' )] [string] $Type ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfoBloxDNSRecord - You must first connect to an Infoblox server using Connect-Infoblox' return } # Lets convert it to lowercase, since Infoblox is case sensitive $Type = $Type.ToLower() if ($Type -eq 'A') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with IPAddress: '$IPAddress'" if ($Name -and $IPAddress) { $Body = [ordered] @{ name = $Name.ToLower() ipv4addr = $IPAddress } } else { if ($ErrorActionPreference -eq 'Stop') { throw "Add-InfoBloxDNSRecord - 'Name' and 'IPAddress' are required for $Type record" } Write-Warning -Message "'Name' and 'IPAddress' are required for $Type record" return } } elseif ($Type -eq 'CNAME') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with IPAddress: '$IPAddress'" if ($Name -and $CanonicalName) { $Body = [ordered] @{ name = $Name.ToLower() canonical = $CanonicalName.ToLower() } } else { if ($ErrorActionPreference -eq 'Stop') { throw "'Name' and 'CanonicalName' are required for $Type record" } Write-Warning -Message "Add-InfoBloxDNSRecord - 'Name' and 'CanonicalName' are required for $Type record" return } } elseif ($Type -eq 'AAAA') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with IPAddress: '$IPAddress'" if ($Name -and $IPAddress) { $Body = [ordered] @{ name = $Name.ToLower() ipv6addr = $IPAddress } } else { if ($ErrorActionPreference -eq 'Stop') { throw "'Name' and 'IPAddress' are required for $Type record" } Write-Warning -Message "Add-InfoBloxDNSRecord - 'Name' and 'IPAddress' are required for $Type record" return } } elseif ($Type -eq 'HOST') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with IPAddress: '$IPAddress'" if ($Name -and $IPAddress) { $Body = [ordered] @{ name = $Name.ToLower() ipv4addrs = @( @{ ipv4addr = $IPAddress } ) } } else { if ($ErrorActionPreference -eq 'Stop') { throw "'Name' and 'IPAddress' are required for '$Type' record" } Write-Warning -Message "Add-InfoBloxDNSRecord - 'Name' and 'IPAddress' are required for '$Type' record" return } } elseif ($Type -eq 'PTR') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with IPAddress: '$IPAddress'" if ($Name -and $IPAddress -and $PtrName) { $Body = [ordered] @{ name = $Name.ToLower() ptrdname = $PtrName.ToLower() ipv4addr = $IPAddress } } else { if ($ErrorActionPreference -eq 'Stop') { throw "'Name' and 'IPAddress' and 'PtrName' are required for '$Type' record" } Write-Warning -Message "Add-InfoBloxDNSRecord - 'Name' and 'IPAddress' and 'PtrName' are required for '$Type' record" return } } elseif ($Type -eq 'TXT') { Write-Verbose -Message "Add-InfoBloxDNSRecord - Adding $Type record $Name with TEXT: '$Text'" if ($Name -and $IPAddress) { $Body = [ordered] @{ name = $Name.ToLower() text = $Text.ToLower() } } else { if ($ErrorActionPreference -eq 'Stop') { throw "'Name' and 'Text' are required for '$Type' record" } Write-Warning -Message "Add-InfoBloxDNSRecord - 'Name' and 'Text' are required for '$Type' record" return } } else { # won't trigger, but lets leave it like that if ($ErrorActionPreference -eq 'Stop') { throw "Add-InfoBloxDNSRecord - Type $Type not supported" } Write-Warning -Message "Add-InfoBloxDNSRecord - Type $Type not supported" return } $invokeInfobloxQuerySplat = @{ RelativeUri = "record:$Type" Method = 'POST' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat #-WarningAction SilentlyContinue -WarningVariable varWarning if ($Output) { Write-Verbose -Message "Add-InfoBloxDNSRecord - Added $Type / $Output" } #else { # if (-not $WhatIfPreference) { #Write-Warning -Message "Add-InfoBloxDNSRecord - Failed to add $Type, error: $varWarning" # } #} } function Add-InfobloxFixedAddress { <# .SYNOPSIS Add a fixed mac address to an IP address on an Infoblox server .DESCRIPTION Add a fixed mac address to an IP address on an Infoblox server A fixed address is a specific IP address that a DHCP server always assigns when a lease request comes from a particular MAC address of the client. For example, if you have a printer in your network, you can reserve a particular IP address to be assigned to it every time it is turned on. .PARAMETER IPv4Address IPv4 address to add the mac address to .PARAMETER MacAddress Mac address to add to the IPv4 address .PARAMETER Name Name of the fixed address .PARAMETER Comment Comment for the fixed address .PARAMETER MicrosoftServer Microsoft server to use for the fixed address .EXAMPLE Add-InfobloxFixedAddress -IPv4Address '10.2.2.18' -MacAddress '00:50:56:9A:00:01' .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [ValidateNotNullOrEmpty()][parameter(Mandatory)][string] $IPv4Address, [ValidatePattern("([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")][parameter(Mandatory)][string] $MacAddress, [string] $Name, [string] $Comment, [alias('ms_server')][string] $MicrosoftServer ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxFixedAddress - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Add-InfobloxFixedAddress - Adding IPv4Address $IPv4Address to MacAddress $MacAddress" $invokeInfobloxQuerySplat = @{ RelativeUri = 'fixedaddress' Method = 'POST' QueryParameter = @{ ipv4addr = $IPv4Address mac = $MacAddress.ToLower() } } if ($Name) { $invokeInfobloxQuerySplat.QueryParameter.name = $Name } if ($Comment) { $invokeInfobloxQuerySplat.QueryParameter.comment = $Comment } if ($MicrosoftServer) { $invokeInfobloxQuerySplat.QueryParameter.ms_server = $MicrosoftServer } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat #-WarningAction SilentlyContinue -WarningVariable varWarning if ($Output) { Write-Verbose -Message "Add-InfobloxFixedAddress - Added $($Output.ipv4addr) with mac address $($Output.mac) / $Output" } } function Add-InfobloxNetwork { <# .SYNOPSIS Adds a network to Infoblox. .DESCRIPTION This function adds a network to Infoblox. It requires a connection to an Infoblox server, which can be established using the Connect-Infoblox function. .PARAMETER Network The network to add. This parameter is mandatory. .PARAMETER Comment An optional comment for the network. .PARAMETER NetworkView The network view in which to add the network. Defaults to 'default'. .PARAMETER AutoCreateReverseZone A switch that, when present, indicates that a reverse zone should be automatically created for the network. .PARAMETER DHCPGateway The DHCP gateway for the network. .PARAMETER DHCPLeaseTime The DHCP lease time for the network. .PARAMETER DHCPDomainNameServers The DHCP domain name servers for the network. .PARAMETER Options An array of options to be added to the DHCP range. .PARAMETER MSOptions An array of Microsoft options to be added to the DHCP range. .PARAMETER ExtensibleAttributeName The name of an extensible attribute for the network. .PARAMETER ExtensibleAttributeSite The site associated with the network as an extensible attribute. .PARAMETER ExtensibleAttributeState The state associated with the network as an extensible attribute. .PARAMETER ExtensibleAttributeCountry The country associated with the network as an extensible attribute. .PARAMETER ExtensibleAttributeRegion The region associated with the network as an extensible attribute. .PARAMETER ExtensibleAttributeVLAN The VLAN associated with the network as an extensible attribute. .PARAMETER ExtensibleAttribute A hashtable of additional extensible attributes to associate with the network. .PARAMETER Members An array of DHCP members to associate with the network. .PARAMETER ReturnOutput A switch that, when present, indicates that the output of the command should be returned. .EXAMPLE Add-InfobloxNetwork -Network '192.168.1.0/24' -Comment 'Test network' -DHCPGateway '192.168.1.1' .EXAMPLE $addInfobloxSubnetSplat = @{ Subnet = '10.22.35.0/24' Comment = "Oki dokii" AutoCreateReverseZone = $true DHCPGateway = "10.22.35.1" DHCPLeaseTime = 5000 DHCPDomainNameServers = "192.168.4.56,192.168.4.57" ExtensinbleAttributeCountry = "Poland" ExtensinbleAttributeName = "Test" ExtensinbleAttributeRegion = "Europe" ExtensinbleAttributeSite = "Site1" ExtensinbleAttributeState = "Mazowieckie" ExtensinbleAttributeVLAN = "810" } Add-InfobloxNetwork @addInfobloxSubnetSplat .EXAMPLE $addInfobloxSubnetSplat = @{ Subnet = '10.22.36.0/24' Comment = "Oki dokii" AutoCreateReverseZone = $true DHCPGateway = "10.22.36.1" DHCPLeaseTime = 5000 DHCPDomainNameServers = "192.168.4.56,192.168.4.57" ExtensinbleAttribute = [ordered] @{ Name = 'Test' VLAN = '810' Country = 'Poland' Region = 'Europe' Site = 'Site1' } } Add-InfobloxNetwork @addInfobloxSubnetSplat .NOTES This function requires a connection to an Infoblox server, which can be established using the Connect-Infoblox function. #> [alias('Add-InfobloxSubnet')] [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][alias('Subnet')][string] $Network, [string] $Comment, [string] $NetworkView = 'default', [switch] $AutoCreateReverseZone, [string] $DHCPGateway, [string] $DHCPLeaseTime, [string] $DHCPDomainNameServers, [Array] $Options, [Alias('ms_options')][Array] $MSOptions, [string[]] $Members, [string] $ExtensinbleAttributeName, [string] $ExtensinbleAttributeSite, [string] $ExtensinbleAttributeState, [string] $ExtensinbleAttributeCountry, [string] $ExtensinbleAttributeRegion, [string] $ExtensinbleAttributeVLAN, [System.Collections.IDictionary] $ExtensinbleAttribute, [switch] $ReturnOutput ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxNetwork - You must first connect to an Infoblox server using Connect-Infoblox' return } $Body = [ordered] @{ "network" = $Network # "members" = @( # @{ # "_struct" = "msdhcpserver" # "ipv4addr" = "" # } # ) "comment" = $Comment "network_view" = $NetworkView "auto_create_reversezone" = $AutoCreateReverseZone.IsPresent } Remove-EmptyValue -Hashtable $Body if ($Members) { $Body["members"] = @( foreach ($DHCPMember in $Members) { [ordered] @{ "_struct" = "msdhcpserver" "ipv4addr" = $DHCPMember } } ) #"_struct": "dhcpmember", #"name": "ddi.example.com" } if ($MSOptions) { $Body["ms_options"] = @( foreach ($MSOption in $MSOptions) { $MSOption } ) } $DHCPOptions = @( if ($Options) { foreach ($Option in $Options) { $Option } } if ($DHCPLeaseTime) { [ordered] @{ "name" = "dhcp-lease-time" "num" = 51 "use_option" = $true "value" = $DHCPLeaseTime "vendor_class" = "DHCP" } } # DNS servers (we will use default ones if not provided) if ($DHCPDomainNameServers) { @{ "name" = "domain-name-servers" "num" = 6 "use_option" = $true "value" = $DHCPDomainNameServers "vendor_class" = "DHCP" } } # DHCP servers (we will use default ones if not provided) if ($DHCPGateway) { @{ "name" = "routers" "num" = 3 "use_option" = $true "value" = $DHCPGateway "vendor_class" = "DHCP" } } ) if ($DHCPOptions.Count -gt 0) { $Body["options"] = $DHCPOptions } # Lets add extensible attributes $ExtensibleAttributeExists = $false foreach ($Key in $PSBoundParameters.Keys) { if ($Key -like "ExtensinbleAttribute*") { $ExtensibleAttributeExists = $true break } } if ($ExtensibleAttributeExists) { $Body["extattrs"] = [ordered] @{} if ($ExtensinbleAttributeName) { $Body["extattrs"]["Name"] = @{ value = $ExtensinbleAttributeName } } if ($ExtensinbleAttributeSite) { $Body["extattrs"]["Site"] = @{ value = $ExtensinbleAttributeSite } } if ($ExtensinbleAttributeState) { $Body["extattrs"]["State"] = @{ value = $ExtensinbleAttributeState } } if ($ExtensinbleAttributeCountry) { $Body["extattrs"]["Country"] = @{ value = $ExtensinbleAttributeCountry } } if ($ExtensinbleAttributeRegion) { $Body["extattrs"]["Region"] = @{ value = $ExtensinbleAttributeRegion } } if ($ExtensinbleAttributeVLAN) { $Body["extattrs"]["VLAN"] = @{ value = $ExtensinbleAttributeVLAN } } foreach ($Key in $ExtensinbleAttribute.Keys) { if ($ExtensinbleAttribute[$Key] -is [System.Collections.IDictionary]) { $Body["extattrs"][$Key] = $ExtensinbleAttribute[$Key] } else { $Body["extattrs"][$Key] = @{ value = $ExtensinbleAttribute[$Key] } } } } $invokeInfobloxQuerySplat = @{ RelativeUri = "network" Method = 'POST' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Add-InfobloxNetwork - $Output" if ($ReturnOutput) { $Output } } } function Add-InfobloxNetworkExtensibleAttribute { <# .SYNOPSIS Adds an extensible attribute to a specified network in Infoblox. .DESCRIPTION This function adds an extensible attribute to a network in Infoblox. It requires an established connection to an Infoblox server, which can be done using the Connect-Infoblox function. The function checks if the specified network exists before attempting to add the extensible attribute. .PARAMETER Network The network to which the extensible attribute will be added. This parameter is mandatory. .PARAMETER Attribute The name of the extensible attribute to add. This parameter is mandatory. .PARAMETER Value The value of the extensible attribute to add. This parameter is mandatory. .EXAMPLE Add-InfobloxNetworkExtensibleAttribute -Network '192.168.1.0/24' -Attribute 'Location' -Value 'Data Center 1' Adds the 'Location' extensible attribute with the value 'Data Center 1' to the network '192.168.1.0/24'. .NOTES You must first connect to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][alias('Subnet')][string] $Network, [Parameter(Mandatory)][alias('ExtensinbleAttribute')][string] $Attribute, [Parameter(Mandatory)][alias('ExtensinbleAttributeValue')][string] $Value ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Add-InfobloxNetworkExtensibleAttribute - You must first connect to an Infoblox server using Connect-Infoblox' return } $NetworkInformation = Get-InfobloxNetwork -Network $Network if (-not $NetworkInformation._ref) { Write-Warning -Message "Add-InfobloxNetworkExtensibleAttribute - Network $Network not found" return } $Body = [ordered] @{ "extattrs+" = @{ $Attribute = @{ "value" = $Value } } } Remove-EmptyValue -Hashtable $Body $invokeInfobloxQuerySplat = @{ RelativeUri = $NetworkInformation._ref Method = 'PUT' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Add-InfobloxNetworkExtensibleAttribute - $Output" if ($ReturnOutput) { $Output } } } function Connect-Infoblox { [CmdletBinding()] param( [Parameter(Mandatory, ParameterSetName = 'UserName')] [Parameter(Mandatory, ParameterSetName = 'Credential')] [string] $Server, [Parameter(Mandatory, ParameterSetName = 'UserName')][string] $Username, [alias('SecurePassword')][Parameter(Mandatory, ParameterSetName = 'UserName')][string] $EncryptedPassword, [Parameter(Mandatory, ParameterSetName = 'Credential')][pscredential] $Credential, [Parameter(ParameterSetName = 'UserName')] [Parameter(ParameterSetName = 'Credential')] [string] $ApiVersion = '2.11', [Parameter(ParameterSetName = 'UserName')] [Parameter(ParameterSetName = 'Credential')] [switch] $EnableTLS12, [Parameter(ParameterSetName = 'UserName')] [Parameter(ParameterSetName = 'Credential')] [switch] $AllowSelfSignedCerts, [Parameter(ParameterSetName = 'UserName')] [Parameter(ParameterSetName = 'Credential')] [switch] $SkipInitialConnection, [switch] $ReturnObject ) if ($EnableTLS12) { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } # lets clear sessions if any exists Disconnect-Infoblox if ($Username -and $EncryptedPassword) { try { $Password = $EncryptedPassword | ConvertTo-SecureString -ErrorAction Stop $Credential = [pscredential]::new($Username, $Password) } catch { if ($ErrorActionPreference -eq 'Stop') { throw } Write-Warning -Message "Connect-Infoblox - Unable to convert password to secure string. Error: $($_.Exception.Message)" return } } $PSDefaultParameterValues['Invoke-InfobloxQuery:Credential'] = $Credential $PSDefaultParameterValues['Invoke-InfobloxQuery:Server'] = $Server $PSDefaultParameterValues['Invoke-InfobloxQuery:BaseUri'] = "https://$Server/wapi/v$apiVersion" $PSDefaultParameterValues['Invoke-InfobloxQuery:WebSession'] = [Microsoft.PowerShell.Commands.WebRequestSession]::new() # The infoblox configuration is not really used anywhere. It's just a placeholder # It's basecause we use $PSDefaultParameterValues to pass the parameters to Invoke-InfobloxQuery # But this placeholder is used to check if we're connected or not in other functions $Script:InfobloxConfiguration = [ordered] @{ ApiVersion = $ApiVersion Server = $Server BaseUri = "https://$Server/wapi/v$apiVersion" } if ($AllowSelfSignedCerts) { Hide-SelfSignedCerts } # we do inital query to make sure we're connected if (-not $SkipInitialConnection) { $Schema = Get-InfobloxSchema -WarningAction SilentlyContinue -WarningVariable SchemaWarning if (-not $Schema) { if ($SchemaWarning) { if ($ErrorActionPreference -eq 'Stop') { throw $SchemaWarning } else { Write-Warning -Message "Connect-Infoblox - Unable to retrieve schema. Connection failed. Error: $($SchemaWarning)" } } else { Write-Warning -Message "Connect-Infoblox - Unable to retrieve schema. Connection failed." } Disconnect-Infoblox return } } if ($ReturnObject) { $Script:InfobloxConfiguration } } function Disconnect-Infoblox { <# .SYNOPSIS Disconnects from an InfoBlox server .DESCRIPTION Disconnects from an InfoBlox server As this is a REST API it doesn't really disconnect, but it does clear the script variable to clear the credentials from memory .EXAMPLE Disconnect-Infoblox .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [switch] $ForceLogOut ) if ($ForceLogOut) { $invokeInfobloxQuerySplat = @{ RelativeUri = "logout" Method = 'POST' } Invoke-InfobloxQuery @invokeInfobloxQuerySplat } # lets remove the default parameters so that user has to connect again $Script:InfobloxConfiguration = $null $PSDefaultParameterValues.Remove('Invoke-InfobloxQuery:Credential') $PSDefaultParameterValues.Remove('Invoke-InfobloxQuery:Server') $PSDefaultParameterValues.Remove('Invoke-InfobloxQuery:BaseUri') $PSDefaultParameterValues.Remove('Invoke-InfobloxQuery:WebSession') } function Get-InfobloxDHCPLease { [alias('Get-InfobloxDHCPLeases')] [CmdletBinding()] param( [string] $Network, [string] $IPv4Address, [string] $Hostname, [switch] $PartialMatch, [switch] $FetchFromSchema, [int] $MaxResults = 1000000 ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDHCPLease - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Get-InfobloxDHCPLease - Requesting DHCP leases for Network [$Network] / IPv4Address [$IPv4Address] / Hostname [$Hostname] / PartialMatch [$($PartialMatch.IsPresent)]" if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "lease" } elseif ($ReturnFields) { $ReturnFields = ($ReturnFields | Sort-Object -Unique) -join ',' } else { $ReturnFields = 'binding_state,hardware,client_hostname,fingerprint,address,network_view' } $invokeInfobloxQuerySplat = @{ RelativeUri = 'lease' Method = 'GET' QueryParameter = @{ _return_fields = $ReturnFields _max_results = $MaxResults } } if ($Network) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."network~" = $Network.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.network = $Network.ToLower() } } if ($IPv4Address) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."ipv4addr~" = $IPv4Address.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.ipv4addr = $IPv4Address.ToLower() } } if ($Hostname) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."name~" = $Hostname.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.name = $Hostname.ToLower() } } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxDHCPRange { <# .SYNOPSIS Retrieves DHCP range configuration from an Infoblox server. .DESCRIPTION This function retrieves the DHCP range configuration from an Infoblox server. It allows filtering by ReferenceID, Network, and other parameters. .PARAMETER ReferenceID The unique identifier for the DHCP range to be retrieved. .PARAMETER Network The network for which to retrieve DHCP ranges. .PARAMETER PartialMatch Indicates whether to perform a partial match on the network. .PARAMETER FetchFromSchema Indicates whether to fetch return fields from the schema. .PARAMETER ReturnFields An array of fields to be returned in the response. .PARAMETER MaxResults The maximum number of results to return. Default is 1,000,000. .EXAMPLE Get-InfobloxDHCPRange -ReferenceID 'DHCPRange-1' .EXAMPLE Get-InfobloxDHCPRange -Network '192.168.1' -PartialMatch .EXAMPLE Get-InfobloxDHCPRange -Network '192.168.1.0/24' -FetchFromSchema .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding()] param( [string] $ReferenceID, [string] $Network, [switch] $PartialMatch, [switch] $FetchFromSchema, [string[]] $ReturnFields, [int] $MaxResults = 1000000 ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDHCPRange - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { Write-Verbose -Message "Get-InfobloxDHCPRange - Requesting DHCP ranges for Network [$Network] / PartialMatch [$($PartialMatch.IsPresent)]" } else { Write-Verbose -Message "Get-InfobloxDHCPRange - Requesting DHCP ranges for all networks" } if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "range" } elseif ($ReturnFields) { $ReturnFields = ($ReturnFields | Sort-Object -Unique) -join ',' } else { $ReturnFields = $Null } $invokeInfobloxQuerySplat = @{ RelativeUri = 'range' Method = 'GET' QueryParameter = @{ _max_results = $MaxResults _return_fields = $ReturnFields } } if ($ReferenceID) { $invokeInfobloxQuerySplat.RelativeUri = $ReferenceID } if ($Network) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."network~" = $Network.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.network = $Network.ToLower() } } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxDiscoveryTask { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDiscoveryTask - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "discoverytask" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'discoverytask' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxDNSAuthZone { [alias('Get-InfobloxDNSAuthZones')] [cmdletbinding()] param( [string] $FQDN, [string] $View ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSAuthZones - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = 'zone_auth' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = @( 'address' 'allow_active_dir' 'allow_fixed_rrset_order' 'allow_gss_tsig_for_underscore_zone' 'allow_gss_tsig_zone_updates' 'allow_query' 'allow_transfer' 'allow_update' 'allow_update_forwarding' 'aws_rte53_zone_info' 'cloud_info' 'comment' 'copy_xfer_to_notify' 'create_underscore_zones' 'ddns_force_creation_timestamp_update' 'ddns_principal_group' 'ddns_principal_tracking' 'ddns_restrict_patterns' 'ddns_restrict_patterns_list' 'ddns_restrict_protected' 'ddns_restrict_secure' 'ddns_restrict_static' 'disable' 'disable_forwarding' 'display_domain' 'dns_fqdn' 'dns_integrity_enable' 'dns_integrity_frequency' 'dns_integrity_member' 'dns_integrity_verbose_logging' 'dns_soa_email' 'dnssec_key_params' 'dnssec_keys' 'dnssec_ksk_rollover_date' 'dnssec_zsk_rollover_date' 'effective_check_names_policy' 'effective_record_name_policy' 'extattrs' 'external_primaries' 'external_secondaries' 'fqdn' 'grid_primary' 'grid_primary_shared_with_ms_parent_delegation' 'grid_secondaries' 'is_dnssec_enabled' 'is_dnssec_signed' 'is_multimaster' 'last_queried' 'locked' 'locked_by' 'mask_prefix' 'member_soa_mnames' 'member_soa_serials' 'ms_ad_integrated' 'ms_allow_transfer' 'ms_allow_transfer_mode' 'ms_dc_ns_record_creation' 'ms_ddns_mode' 'ms_managed' 'ms_primaries' 'ms_read_only' 'ms_secondaries' 'ms_sync_disabled' 'ms_sync_master_name' 'network_associations' 'network_view' 'notify_delay' 'ns_group' 'parent' 'prefix' 'primary_type' 'record_name_policy' 'records_monitored' 'rr_not_queried_enabled_time' 'scavenging_settings' 'soa_default_ttl' 'soa_email' 'soa_expire' 'soa_negative_ttl' 'soa_refresh' 'soa_retry' 'soa_serial_number' 'srgs' 'update_forwarding' 'use_allow_active_dir' 'use_allow_query' 'use_allow_transfer' 'use_allow_update' 'use_allow_update_forwarding' 'use_check_names_policy' 'use_copy_xfer_to_notify' 'use_ddns_force_creation_timestamp_update' 'use_ddns_patterns_restriction' 'use_ddns_principal_security' 'use_ddns_restrict_protected' 'use_ddns_restrict_static' 'use_dnssec_key_params' 'use_external_primary' 'use_grid_zone_timer' 'use_import_from' 'use_notify_delay' 'use_record_name_policy' 'use_scavenging_settings' 'use_soa_email' 'using_srg_associations' 'view' 'zone_format' 'zone_not_queried_enabled_time' ) -join ',' } } if ($View) { $invokeInfobloxQuerySplat.QueryParameter.view = $View.ToLower() } if ($FQDN) { $invokeInfobloxQuerySplat.QueryParameter.fqdn = $FQDN.ToLower() } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxDNSDelegatedZone { [cmdletbinding()] param( [string] $Name, [string] $View ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSDelgatedZone - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = 'zone_delegated' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = "address,comment,delegate_to,delegated_ttl,disable,display_domain,dns_fqdn,enable_rfc2317_exclusion,extattrs,fqdn,locked,locked_by,mask_prefix,ms_ad_integrated,ms_ddns_mode,ms_managed,ms_read_only,ms_sync_master_name,ns_group,parent,prefix,use_delegated_ttl,using_srg_associations,view,zone_format" } } if ($View) { $invokeInfobloxQuerySplat.QueryParameter.view = $View.ToLower() } if ($Name) { $invokeInfobloxQuerySplat.QueryParameter.fqdn = $Name.ToLower() } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxDNSForwardZone { [cmdletbinding()] param( [string] $Name, [string] $View ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSForwardZone - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = 'zone_forward' Method = 'GET' QueryParameter = @{ _max_results = 1000000 } } if ($View) { $invokeInfobloxQuerySplat.QueryParameter.view = $View.ToLower() } if ($Name) { $invokeInfobloxQuerySplat.QueryParameter.fqdn = $Name.ToLower() } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxDNSRecord { [alias('Get-InfobloxDNSRecords')] [cmdletbinding()] param( [string] $Name, [string] $Zone, [string] $View, [switch] $PartialMatch, [ValidateSet( 'A', 'AAAA', 'CName', 'DName', 'DNSKEY', 'DS', 'Host', 'host_ipv4addr', 'host_ipv6addr', 'LBDN', 'MX', 'NAPTR', 'NS', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'PTR', 'RRSIG', 'SRV', 'TXT' )] [string] $Type = 'Host', [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSRecord - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = "record:$($Type.ToLower())" Method = 'GET' QueryParameter = @{ _max_results = 1000000 } } if ($Type -eq 'Host') { $invokeInfobloxQuerySplat.QueryParameter._return_fields = 'name,dns_name,aliases,dns_aliases,ipv4addrs,configure_for_dns,view' } elseif ($Type -eq 'PTR') { $invokeInfobloxQuerySplat.QueryParameter._return_fields = 'aws_rte53_record_info,cloud_info,comment,creation_time,creator,ddns_principal,ddns_protected,disable,discovered_data,dns_name,dns_ptrdname,extattrs,forbid_reclamation,ipv4addr,ipv6addr,last_queried,ms_ad_user_data,name,ptrdname,reclaimable,shared_record_group,ttl,use_ttl,view,zone' } elseif ($Type -eq 'A') { $invokeInfobloxQuerySplat.QueryParameter._return_fields = 'ipv4addr,name,view,zone,cloud_info,comment,creation_time,creator,ddns_principal,ddns_protected,disable,discovered_data,dns_name,last_queried,ms_ad_user_data,reclaimable,shared_record_group,ttl,use_ttl' } if ($FetchFromSchema) { $invokeInfobloxQuerySplat.QueryParameter._return_fields = Get-FieldsFromSchema -SchemaObject "record:$Type" } if ($Zone) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."zone~" = $Zone.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.zone = $Zone.ToLower() } } if ($View) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."view~" = $View.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.view = $View.ToLower() } } if ($Name) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."name~" = $Name.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.name = $Name.ToLower() } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false if ($Type -eq 'A') { $Output | Select-ObjectByProperty -LastProperty '_ref' -FirstProperty 'name', 'ipv4addr', 'view', 'zone', 'cloud_info', 'comment', 'creation_time', 'creator', 'ddns_principal', 'ddns_protected', 'disable', 'discovered_data', 'dns_name', 'last_queried', 'ms_ad_user_data', 'reclaimable', 'shared_record_group', 'ttl', 'use_ttl' } elseif ($Type -eq 'HOST') { $Output | Select-ObjectByProperty -LastProperty '_ref' -FirstProperty 'name', 'dns_name', 'aliases', 'dns_aliases', 'view', 'configure_for_dns', 'configure_for_dhcp', 'host', 'ipv4addr', 'ipv4addr_ref' } else { $Output | Select-ObjectByProperty -LastProperty '_ref' } } function Get-InfobloxDNSRecordAll { [alias('Get-InfobloxDNSRecordsAll')] [cmdletbinding()] param( [string] $Name, [string] $Zone, [string] $View, [switch] $PartialMatch, [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSRecordAll - You must first connect to an Infoblox server using Connect-Infoblox' return } $invokeInfobloxQuerySplat = @{ RelativeUri = "allrecords" Method = 'GET' QueryParameter = @{ _max_results = 1000000 } } $invokeInfobloxQuerySplat.QueryParameter._return_fields = 'address,comment,creator,ddns_principal,ddns_protected,disable,dtc_obscured,name,reclaimable,record,ttl,type,view,zone' if ($FetchFromSchema) { <# if (-not $Script:InfobloxSchemaFields) { $Script:InfobloxSchemaFields = [ordered] @{} } if ($Script:InfobloxSchemaFields["allrecords"]) { $invokeInfobloxQuerySplat.QueryParameter._return_fields = ($Script:InfobloxSchemaFields["allrecords"]) } else { $Schema = Get-InfobloxSchema -Object "allrecords" if ($Schema -and $Schema.fields.name) { $invokeInfobloxQuerySplat.QueryParameter._return_fields = ($Schema.fields.Name -join ',') $Script:InfobloxSchemaFields["allrecords"] = ($Schema.fields.Name -join ',') } else { Write-Warning -Message "Get-InfobloxDNSRecordAll - Failed to fetch schema for record type 'allrecords'. Using defaults" } } #> $invokeInfobloxQuerySplat.QueryParameter._return_fields = Get-FieldsFromSchema -SchemaObject "allrecords" } if ($Zone) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."zone~" = $Zone.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.zone = $Zone.ToLower() } } if ($View) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."view~" = $View.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.view = $View.ToLower() } } if ($Name) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."name~" = $Name.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.name = $Name.ToLower() } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $AllProperties = Select-Properties -AllProperties -Object $Output $Output | Select-ObjectByProperty -LastProperty '_ref' -FirstProperty 'zone', 'type', 'name', 'address', 'disable', 'creator' -AllProperties $AllProperties } function Get-InfobloxDNSView { [cmdletbinding()] param( ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxDNSView - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Get-InfobloxDNSView - Requesting DNS View" $invokeInfobloxQuerySplat = @{ RelativeUri = 'view' Method = 'GET' QueryParameter = @{ _max_results = 1000000 # _return_fields = 'mac,ipv4addr,network_view' } } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxFixedAddress { [cmdletbinding()] param( [parameter(Mandatory)][string] $MacAddress, [switch] $PartialMatch, [switch] $FetchFromSchema, [string[]] $Properties ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxFixedAddress - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Get-InfobloxFixedAddress - Requesting MacAddress [$MacAddress] / PartialMatch [$($PartialMatch.IsPresent)]" $invokeInfobloxQuerySplat = @{ RelativeUri = 'fixedaddress' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = 'mac,ipv4addr,network_view' } } if ($FetchFromSchema) { $invokeInfobloxQuerySplat.QueryParameter._return_fields = Get-FieldsFromSchema -SchemaObject "fixedaddress" } elseif ($Properties) { $invokeInfobloxQuerySplat.QueryParameter._return_fields = $Properties -join ',' } if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."mac~" = $MacAddress.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.mac = $MacAddress.ToLower() } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxGrid { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxGrid - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields $ReturnFields = 'allow_recursive_deletion,audit_log_format,audit_to_syslog_enable,automated_traffic_capture_setting,consent_banner_setting,csp_api_config,csp_grid_setting,deny_mgm_snapshots,descendants_action,dns_resolver_setting,dscp,email_setting,enable_gui_api_for_lan_vip,enable_lom,enable_member_redirect,enable_recycle_bin,enable_rir_swip,external_syslog_backup_servers,external_syslog_server_enable,http_proxy_server_setting,informational_banner_setting,is_grid_visualization_visible,lockout_setting,lom_users,mgm_strict_delegate_mode,ms_setting,name,nat_groups,ntp_setting,objects_changes_tracking_setting,password_setting,restart_banner_setting,restart_status,rpz_hit_rate_interval,rpz_hit_rate_max_query,rpz_hit_rate_min_query,scheduled_backup,security_banner_setting,security_setting,service_status,snmp_setting,support_bundle_download_timeout,syslog_facility,syslog_servers,syslog_size,threshold_traps,time_zone,token_usage_delay,traffic_capture_auth_dns_setting,traffic_capture_chr_setting,traffic_capture_qps_setting,traffic_capture_rec_dns_setting,traffic_capture_rec_queries_setting,trap_notifications,updates_download_member_config,vpn_port' if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "grid" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'grid' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxIPAddress { <# .SYNOPSIS Get Infoblox IP Address information for given network or IP address .DESCRIPTION Get Infoblox IP Address information for given network or IP address .PARAMETER Network Find IP address information for a specific network .PARAMETER IPv4Address Find IP address information for a specific IP address .PARAMETER Status Get IP addresses with a specific status, either Used or Unused .PARAMETER Name Get IP addresses with a specific name .PARAMETER Count Limit the number of results returned .EXAMPLE Get-InfobloxIPAddress -Network '10.2.2.0/24' .EXAMPLE Get-InfobloxIPAddress -Network '10.2.2.0/24' -Status Used -Verbose | Format-Table .EXAMPLE Get-InfobloxIPAddress -Network '10.2.2.0' -Verbose | Format-Table .NOTES General notes #> [cmdletbinding()] param( [parameter(ParameterSetName = 'Network')][string] $Network, [parameter(ParameterSetName = 'IPv4')][string] $IPv4Address, [parameter(ParameterSetName = 'Network')] [parameter(ParameterSetName = 'IPv4')] [parameter()][ValidateSet('Used', 'Unused')][string] $Status, [parameter(ParameterSetName = 'Network')] [parameter(ParameterSetName = 'IPv4')] [parameter()][string] $Name, [parameter(ParameterSetName = 'Network')] [parameter(ParameterSetName = 'IPv4')] [alias('Quantity')][parameter()][int] $Count ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxIPAddress - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { Write-Verbose -Message "Get-InfobloxIPAddress - Requesting Network [$Network] Status [$Status]" } else { Write-Verbose -Message "Get-InfobloxIPAddress - Requesting IPv4Address [$IPv4Address] Status [$Status]" } $invokeInfobloxQuerySplat = [ordered]@{ RelativeUri = 'ipv4address' Method = 'GET' QueryParameter = [ordered]@{ _max_results = 1000000 } } if ($Network) { $invokeInfobloxQuerySplat.QueryParameter.network = $Network } if ($Status) { $invokeInfobloxQuerySplat.QueryParameter.status = $Status.ToUpper() } if ($Name) { $invokeInfobloxQuerySplat.QueryParameter.names = $Name } if ($IPv4Address) { $invokeInfobloxQuerySplat.QueryParameter.ip_address = $IPv4Address } if ($Count) { Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false | Select-Object -First $Count | Select-ObjectByProperty -LastProperty '_ref' } else { Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false | Select-ObjectByProperty -LastProperty '_ref' } } function Get-InfobloxMember { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxMember - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields $ReturnFields = 'config_addr_type,host_name,platform,service_type_configuration,vip_setting,node_info,service_status' if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "member" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'member' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -FirstProperty 'host_name' -LastProperty '_ref' } function Get-InfobloxNetwork { [OutputType([system.object[]])] [cmdletbinding()] param( [string] $Network, [string[]]$ReturnFields, [switch] $Partial, [switch] $All, [int] $MaxResults = 1000000, [switch] $FetchFromSchema, [switch] $Native ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxNetwork - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "network" } elseif ($ReturnFields) { $ReturnFields = ($ReturnFields | Sort-Object -Unique) -join ',' } else { if ($Native) { $ReturnFields = $Null } else { $ReturnFields = @( "authority", "bootfile", "bootserver", "cloud_info", "comment", "conflict_count", "ddns_domainname", "ddns_generate_hostname", "ddns_server_always_updates", "ddns_ttl", "ddns_update_fixed_addresses", "ddns_use_option81", "deny_bootp", "dhcp_utilization", "dhcp_utilization_status", "disable", "discover_now_status", "discovered_bgp_as", "discovered_bridge_domain", "discovered_tenant", "discovered_vlan_id", "discovered_vlan_name", "discovered_vrf_description", "discovered_vrf_name", "discovered_vrf_rd", "discovery_basic_poll_settings", "discovery_blackout_setting", "discovery_engine_type", "discovery_member", "dynamic_hosts", "email_list", "enable_ddns", "enable_dhcp_thresholds", "enable_discovery", "enable_email_warnings", "enable_ifmap_publishing", "enable_pxe_lease_time", "enable_snmp_warnings", "endpoint_sources", "extattrs", "high_water_mark", "high_water_mark_reset", "ignore_dhcp_option_list_request", "ignore_id", "ignore_mac_addresses", "ipam_email_addresses", "ipam_threshold_settings", "ipam_trap_settings", "ipv4addr", "last_rir_registration_update_sent", "last_rir_registration_update_status", "lease_scavenge_time", "logic_filter_rules", "low_water_mark", "low_water_mark_reset", "members", "mgm_private", "mgm_private_overridable", "ms_ad_user_data", "netmask", "network", "network_container", "network_view", "nextserver", "options", "port_control_blackout_setting", "pxe_lease_time", "recycle_leases", "rir", "rir_organization", "rir_registration_status", "same_port_control_discovery_blackout", "static_hosts", "subscribe_settings", "total_hosts", "unmanaged", "unmanaged_count", "update_dns_on_lease_renewal", "use_authority", "use_blackout_setting", "use_bootfile", "use_bootserver", "use_ddns_domainname", "use_ddns_generate_hostname", "use_ddns_ttl", "use_ddns_update_fixed_addresses", "use_ddns_use_option81", "use_deny_bootp", "use_discovery_basic_polling_settings", "use_email_list", "use_enable_ddns", "use_enable_dhcp_thresholds", "use_enable_discovery", "use_enable_ifmap_publishing", "use_ignore_dhcp_option_list_request", "use_ignore_id", "use_ipam_email_addresses", "use_ipam_threshold_settings", "use_ipam_trap_settings", "use_lease_scavenge_time", "use_logic_filter_rules", "use_mgm_private", "use_nextserver", "use_options", "use_pxe_lease_time", "use_recycle_leases", "use_subscribe_settings", "use_update_dns_on_lease_renewal", "use_zone_associations", "utilization", "utilization_update", "vlans", "zone_associations" ) -join ',' } } $QueryParameter = [ordered]@{ _return_fields = $ReturnFields } if ($All) { $QueryParameter["_max_results"] = $MaxResults } elseif ($Network -and $Partial.IsPresent) { $QueryParameter["_max_results"] = $MaxResults $QueryParameter."network~" = $Network } elseif ($Network) { $QueryParameter.network = $Network } else { Write-Warning -Message "Get-InfobloxNetwork - You must provide either -Network or -All switch" return } $ListNetworks = Invoke-InfobloxQuery -RelativeUri "network" -Method Get -QueryParameter $QueryParameter -WhatIf:$false foreach ($FoundNetwork in $ListNetworks) { if ($Native) { $FoundNetwork } else { $FullInformation = Get-IPAddressRangeInformation -Network $FoundNetwork.network $OutputData = [ordered] @{ Network = $FoundNetwork.network NetworkRef = $FoundNetwork._ref IP = $FullInformation.IP # : 10.2.10.0 NetworkLength = $FullInformation.NetworkLength # : 24 SubnetMask = $FullInformation.SubnetMask # : 255.255.255.0 NetworkAddress = $FullInformation.NetworkAddress # : 10.2.10.0 HostMin = $FullInformation.HostMin # : 10.2.10.1 HostMax = $FullInformation.HostMax # : 10.2.10.254 TotalHosts = $FullInformation.TotalHosts # : 256 UsableHosts = $FullInformation.UsableHosts # : 254 Broadcast = $FullInformation.Broadcast # : 10.2.10.255 authority = $FoundNetwork.authority #: False cloud_info = $FoundNetwork.cloud_info #: @{authority_type=GM; delegated_scope=NONE; mgmt_platform=; owned_by_adaptor=False} comment = $FoundNetwork.comment #: found in CMDB conflict_count = $FoundNetwork.conflict_count #: 0 ddns_generate_hostname = $FoundNetwork.ddns_generate_hostname #: False ddns_server_always_updates = $FoundNetwork.ddns_server_always_updates #: True ddns_ttl = $FoundNetwork.ddns_ttl #: 0 ddns_update_fixed_addresses = $FoundNetwork.ddns_update_fixed_addresses #: False ddns_use_option81 = $FoundNetwork.ddns_use_option81 #: False deny_bootp = $FoundNetwork.deny_bootp #: False dhcp_utilization = $FoundNetwork.dhcp_utilization #: 0 dhcp_utilization_status = $FoundNetwork.dhcp_utilization_status #: LOW disable = $FoundNetwork.disable #: False discover_now_status = $FoundNetwork.discover_now_status #: NONE discovered_bgp_as = $FoundNetwork.discovered_bgp_as #: discovered_bridge_domain = $FoundNetwork.discovered_bridge_domain #: discovered_tenant = $FoundNetwork.discovered_tenant #: discovered_vlan_id = $FoundNetwork.discovered_vlan_id #: discovered_vlan_name = $FoundNetwork.discovered_vlan_name #: discovered_vrf_description = $FoundNetwork.discovered_vrf_description #: discovered_vrf_name = $FoundNetwork.discovered_vrf_name #: discovered_vrf_rd = $FoundNetwork.discovered_vrf_rd #: discovery_basic_poll_settings = $FoundNetwork.discovery_basic_poll_settings #: @{auto_arp_refresh_before_switch_port_polling=True; cli_collection=True; complete_ping_sweep=False; # = $FoundNetwork. # credential_group=default; device_profile=False; netbios_scanning=False; port_scanning=False; # = $FoundNetwork. # smart_subnet_ping_sweep=False; snmp_collection=True; switch_port_data_collection_polling=PERIODIC; # = $FoundNetwork. # switch_port_data_collection_polling_interval=3600} discovery_blackout_setting = $FoundNetwork.discovery_blackout_setting #: @{enable_blackout=False} discovery_engine_type = $FoundNetwork.discovery_engine_type #: NONE dynamic_hosts = $FoundNetwork.dynamic_hosts #: 0 email_list = $FoundNetwork.email_list #: {} enable_ddns = $FoundNetwork.enable_ddns #: False enable_dhcp_thresholds = $FoundNetwork.enable_dhcp_thresholds #: False enable_discovery = $FoundNetwork.enable_discovery #: False enable_email_warnings = $FoundNetwork.enable_email_warnings #: False enable_ifmap_publishing = $FoundNetwork.enable_ifmap_publishing #: False enable_pxe_lease_time = $FoundNetwork.enable_pxe_lease_time #: False enable_snmp_warnings = $FoundNetwork.enable_snmp_warnings #: False #extattrs = $FoundNetwork.extattrs #: @{Country=; Name=; Region=} high_water_mark = $FoundNetwork.high_water_mark #: 95 high_water_mark_reset = $FoundNetwork.high_water_mark_reset #: 85 ignore_dhcp_option_list_request = $FoundNetwork.ignore_dhcp_option_list_request #: False ignore_id = $FoundNetwork.ignore_id #: NONE ignore_mac_addresses = $FoundNetwork.ignore_mac_addresses #: {} ipam_email_addresses = $FoundNetwork.ipam_email_addresses #: {} ipam_threshold_settings = $FoundNetwork.ipam_threshold_settings #: @{reset_value=85; trigger_value=95} ipam_trap_settings = $FoundNetwork.ipam_trap_settings #: @{enable_email_warnings=False; enable_snmp_warnings=True} ipv4addr = $FoundNetwork.ipv4addr #: 172.23.0.0 lease_scavenge_time = $FoundNetwork.lease_scavenge_time #: -1 logic_filter_rules = $FoundNetwork.logic_filter_rules #: {} low_water_mark = $FoundNetwork.low_water_mark #: 0 low_water_mark_reset = $FoundNetwork.low_water_mark_reset #: 10 members = $FoundNetwork.members #: {} mgm_private = $FoundNetwork.mgm_private #: False mgm_private_overridable = $FoundNetwork.mgm_private_overridable #: True netmask = $FoundNetwork.netmask #: 27 network_container = $FoundNetwork.network_container #: 172.23.0.0/16 network_view = $FoundNetwork.network_view #: default options = $FoundNetwork.options #: {@{name=dhcp-lease-time; num=51; use_option=False; value=43200; vendor_class=DHCP}} port_control_blackout_setting = $FoundNetwork.port_control_blackout_setting #: @{enable_blackout=False} recycle_leases = $FoundNetwork.recycle_leases #: True rir = $FoundNetwork.rir #: NONE rir_registration_status = $FoundNetwork.rir_registration_status #: NOT_REGISTERED same_port_control_discovery_blackout = $FoundNetwork.same_port_control_discovery_blackout #: False static_hosts = $FoundNetwork.static_hosts #: 0 subscribe_settings = $FoundNetwork.subscribe_settings #: total_hosts = $FoundNetwork.total_hosts #: 0 unmanaged = $FoundNetwork.unmanaged #: False unmanaged_count = $FoundNetwork.unmanaged_count #: 0 update_dns_on_lease_renewal = $FoundNetwork.update_dns_on_lease_renewal #: False use_authority = $FoundNetwork.use_authority #: False use_blackout_setting = $FoundNetwork.use_blackout_setting #: False use_bootfile = $FoundNetwork.use_bootfile #: False use_bootserver = $FoundNetwork.use_bootserver #: False use_ddns_domainname = $FoundNetwork.use_ddns_domainname #: False use_ddns_generate_hostname = $FoundNetwork.use_ddns_generate_hostname #: False use_ddns_ttl = $FoundNetwork.use_ddns_ttl #: False use_ddns_update_fixed_addresses = $FoundNetwork.use_ddns_update_fixed_addresses #: False use_ddns_use_option81 = $FoundNetwork.use_ddns_use_option81 #: False use_deny_bootp = $FoundNetwork.use_deny_bootp #: False use_discovery_basic_polling_settings = $FoundNetwork.use_discovery_basic_polling_settings #: False use_email_list = $FoundNetwork.use_email_list #: False use_enable_ddns = $FoundNetwork.use_enable_ddns #: False use_enable_dhcp_thresholds = $FoundNetwork.use_enable_dhcp_thresholds #: False use_enable_discovery = $FoundNetwork.use_enable_discovery #: False use_enable_ifmap_publishing = $FoundNetwork.use_enable_ifmap_publishing #: False use_ignore_dhcp_option_list_request = $FoundNetwork.use_ignore_dhcp_option_list_request #: False use_ignore_id = $FoundNetwork.use_ignore_id #: False use_ipam_email_addresses = $FoundNetwork.use_ipam_email_addresses #: False use_ipam_threshold_settings = $FoundNetwork.use_ipam_threshold_settings #: False use_ipam_trap_settings = $FoundNetwork.use_ipam_trap_settings #: False use_lease_scavenge_time = $FoundNetwork.use_lease_scavenge_time #: False use_logic_filter_rules = $FoundNetwork.use_logic_filter_rules #: False use_mgm_private = $FoundNetwork.use_mgm_private #: False use_nextserver = $FoundNetwork.use_nextserver #: False use_options = $FoundNetwork.use_options #: False use_pxe_lease_time = $FoundNetwork.use_pxe_lease_time #: False use_recycle_leases = $FoundNetwork.use_recycle_leases #: False use_subscribe_settings = $FoundNetwork.use_subscribe_settings #: False use_update_dns_on_lease_renewal = $FoundNetwork.use_update_dns_on_lease_renewal #: False use_zone_associations = $FoundNetwork.use_zone_associations #: False utilization = $FoundNetwork.utilization #: 0 utilization_update = $FoundNetwork.utilization_update #: 1707318915 vlans = $FoundNetwork.vlans #: {} zone_associations = $FoundNetwork.zone_associations #: {} _ref = $FoundNetwork._ref #: network/ZG } foreach ($Extra in $FoundNetwork.extattrs.psobject.properties) { $OutputData[$Extra.Name] = $Extra.Value.value } [PSCustomObject]$OutputData } } } function Get-InfobloxNetworkContainer { <# .SYNOPSIS Get Infoblox Network Containers .DESCRIPTION Get Infoblox Network Containers .PARAMETER Network Provide the network to search for network containers .PARAMETER PartialMatch Allow partial matches .PARAMETER FetchFromSchema Fetch fields from schema. By default, only the _ref field is returned .PARAMETER MaxResults Maximum number of results to return .EXAMPLE Get-InfoBloxNetworkContainer -Network '10.2.0.0/16' -Verbose | Format-Table .EXAMPLE Get-InfoBloxNetworkContainer -Network '10.2' -Verbose -PartialMatch | Format-Table .NOTES General notes #> [CmdletBinding()] param( [string] $Network, [switch] $PartialMatch, [switch] $FetchFromSchema, [int] $MaxResults = 1000000 ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxNetworkContainer - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { Write-Verbose -Message "Get-InfobloxNetworkContainer - Requesting Network Containers for Network [$Network] / PartialMatch [$($PartialMatch.IsPresent)]" } else { Write-Verbose -Message "Get-InfobloxNetworkContainer - Requesting Network Containers for all networks" } if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "networkcontainer" } else { $ReturnFields = $Null } $invokeInfobloxQuerySplat = @{ RelativeUri = 'networkcontainer' Method = 'GET' QueryParameter = @{ _max_results = $MaxResults _return_fields = $ReturnFields } } if ($Network) { if ($PartialMatch) { $invokeInfobloxQuerySplat.QueryParameter."network~" = $Network.ToLower() } else { $invokeInfobloxQuerySplat.QueryParameter.network = $Network.ToLower() } } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxNetworkNextAvailableIP { [cmdletbinding(DefaultParameterSetName = 'Network')] param( [Parameter(Mandatory, ParameterSetName = 'Network')][string] $Network, [Parameter(Mandatory, ParameterSetName = 'NetworkRef')][string] $NetworkRef, [alias('Count')][int] $Quantity = 1 ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxNetworkNextAvailableIP - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { $NetworkInformation = Get-InfobloxNetwork -Network $Network if ($NetworkInformation) { $NetworkRef = $NetworkInformation.NetworkRef } else { Write-Warning -Message "Get-InfobloxNetworkNextAvailableIP - No network found for [$Network]" return } } $invokeInfobloxQuerySplat = @{ RelativeUri = $NetworkRef QueryParameter = @{ _function = 'next_available_ip' num = $Quantity } Method = 'POST' } $Query = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WarningAction SilentlyContinue -WarningVariable varWarning -WhatIf:$false if ($Query) { $Query.ips } else { Write-Warning -Message "Get-InfobloxNetworkNextAvailableIP - No IP returned for network [$NetworkRef], error: $varWarning" } } function Get-InfobloxNetworkNextAvailableNetwork { <# .SYNOPSIS Get the next available network from a network container .DESCRIPTION Get the next available network from a network container .PARAMETER Network Provide the network container to search for the next available network .PARAMETER NetworkRef Provide the network container reference to search for the next available network (alternative to Network) .PARAMETER Quantity How many networks to return .PARAMETER Cidr The CIDR of the network to return .EXAMPLE Get-InfobloxNetworkNextAvailableNetwork -Network '10.2.0.0/16' -Quantity 5 -Cidr 27 -Verbose | Format-Table .NOTES General notes #> [cmdletbinding(DefaultParameterSetName = 'Network')] param( [Parameter(Mandatory, ParameterSetName = 'Network')][string] $Network, [Parameter(Mandatory, ParameterSetName = 'NetworkRef')][string] $NetworkRef, [Parameter()][alias('Count')][int] $Quantity = 1, [Parameter(Mandatory)][int] $Cidr ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxNetworkNextAvailableNetwork - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { $NetworkInformation = Get-InfobloxNetworkContainer -Network $Network if ($NetworkInformation) { $NetworkRef = $NetworkInformation._ref } else { Write-Warning -Message "Get-InfobloxNetworkNextAvailableNetwork - No network container found for [$Network]" return } } $invokeInfobloxQuerySplat = @{ RelativeUri = $NetworkRef QueryParameter = @{ _function = 'next_available_network' cidr = $Cidr num = $Quantity } Method = 'POST' } $Query = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WarningAction SilentlyContinue -WarningVariable varWarning -WhatIf:$false if ($Query) { $Query.networks } else { Write-Warning -Message "Get-InfobloxNetworkNextAvailableNetwork - No network returned for network container [$NetworkRef], error: $varWarning" } } function Get-InfobloxNetworkView { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxNetworkView - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Get-InfobloxNetworkView - Requesting Network View" if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "networkview" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'networkview' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxObjects { [CmdletBinding()] param( [Parameter(Mandatory, ParameterSetName = 'ReferenceID')] [string[]] $ReferenceID, [Parameter(Mandatory, ParameterSetName = 'Objects')] [ValidateSet( "ad_auth_service", "admingroup", "adminrole", "adminuser", "allendpoints", "allnsgroup", "allrecords", "allrpzrecords", "approvalworkflow", "authpolicy", "awsrte53taskgroup", "awsuser", "bfdtemplate", "bulkhost", "bulkhostnametemplate", "cacertificate", "capacityreport", "captiveportal", "certificate:authservice", "csvimporttask", "db_objects", "dbsnapshot", "ddns:principalcluster", "ddns:principalcluster:group", "deleted_objects", "dhcp:statistics", "dhcpfailover", "dhcpoptiondefinition", "dhcpoptionspace", "discovery", "discovery:credentialgroup", "discovery:device", "discovery:devicecomponent", "discovery:deviceinterface", "discovery:deviceneighbor", "discovery:devicesupportbundle", "discovery:diagnostictask", "discovery:gridproperties", "discovery:memberproperties", "discovery:sdnnetwork", "discovery:status", "discovery:vrf", "discoverytask", "distributionschedule", "dns64group", "dtc", "dtc:allrecords", "dtc:certificate", "dtc:lbdn", "dtc:monitor", "dtc:monitor:http", "dtc:monitor:icmp", "dtc:monitor:pdp", "dtc:monitor:sip", "dtc:monitor:snmp", "dtc:monitor:tcp", "dtc:object", "dtc:pool", "dtc:record:a", "dtc:record:aaaa", "dtc:record:cname", "dtc:record:naptr", "dtc:record:srv", "dtc:server", "dtc:topology", "dtc:topology:label", "dtc:topology:rule", "dxl:endpoint", "extensibleattributedef", "fileop", "filterfingerprint", "filtermac", "filternac", "filteroption", "filterrelayagent", "fingerprint", "fixedaddress", "fixedaddresstemplate", "ftpuser", "grid", "grid:cloudapi", "grid:cloudapi:cloudstatistics", "grid:cloudapi:tenant", "grid:cloudapi:vm", "grid:cloudapi:vmaddress", "grid:dashboard", "grid:dhcpproperties", "grid:dns", "grid:filedistribution", "grid:license_pool", "grid:license_pool_container", "grid:maxminddbinfo", "grid:member:cloudapi", "grid:servicerestart:group", "grid:servicerestart:group:order", "grid:servicerestart:request", "grid:servicerestart:request:changedobject", "grid:servicerestart:status", "grid:threatanalytics", "grid:threatprotection", "grid:x509certificate", "hostnamerewritepolicy", "hsm:allgroups", "hsm:safenetgroup", "hsm:thalesgroup", "ipam:statistics", "ipv4address", "ipv6address", "ipv6dhcpoptiondefinition", "ipv6dhcpoptionspace", "ipv6fixedaddress", "ipv6fixedaddresstemplate", "ipv6network", "ipv6networkcontainer", "ipv6networktemplate", "ipv6range", "ipv6rangetemplate", "ipv6sharednetwork", "kerberoskey", "ldap_auth_service", "lease", "license:gridwide", "localuser:authservice", "macfilteraddress", "mastergrid", "member", "member:dhcpproperties", "member:dns", "member:filedistribution", "member:license", "member:parentalcontrol", "member:threatanalytics", "member:threatprotection", "memberdfp", "msserver", "msserver:adsites:domain", "msserver:adsites:site", "msserver:dhcp", "msserver:dns", "mssuperscope", "namedacl", "natgroup", "network", "network_discovery", "networkcontainer", "networktemplate", "networkuser", "networkview", "notification:rest:endpoint", "notification:rest:template", "notification:rule", "nsgroup", "nsgroup:delegation", "nsgroup:forwardingmember", "nsgroup:forwardstubserver", "nsgroup:stubmember", "orderedranges", "orderedresponsepolicyzones", "outbound:cloudclient", "parentalcontrol:avp", "parentalcontrol:blockingpolicy", "parentalcontrol:subscriber", "parentalcontrol:subscriberrecord", "parentalcontrol:subscribersite", "permission", "pxgrid:endpoint", "radius:authservice", "range", "rangetemplate", "record:a", "record:aaaa", "record:alias", "record:caa", "record:cname", "record:dhcid", "record:dname", "record:dnskey", "record:ds", "record:dtclbdn", "record:host", "record:host_ipv4addr", "record:host_ipv6addr", "record:mx", "record:naptr", "record:ns", "record:nsec", "record:nsec3", "record:nsec3param", "record:ptr", "record:rpz:a", "record:rpz:a:ipaddress", "record:rpz:aaaa", "record:rpz:aaaa:ipaddress", "record:rpz:cname", "record:rpz:cname:clientipaddress", "record:rpz:cname:clientipaddressdn", "record:rpz:cname:ipaddress", "record:rpz:cname:ipaddressdn", "record:rpz:mx", "record:rpz:naptr", "record:rpz:ptr", "record:rpz:srv", "record:rpz:txt", "record:rrsig", "record:srv", "record:tlsa", "record:txt", "record:unknown", "recordnamepolicy", "request", "restartservicestatus", "rir", "rir:organization", "roaminghost", "ruleset", "saml:authservice", "scavengingtask", "scheduledtask", "search", "sharednetwork", "sharedrecord:a", "sharedrecord:aaaa", "sharedrecord:cname", "sharedrecord:mx", "sharedrecord:srv", "sharedrecord:txt", "sharedrecordgroup", "smartfolder:children", "smartfolder:global", "smartfolder:personal", "snmpuser", "superhost", "superhostchild", "syslog:endpoint", "tacacsplus:authservice", "taxii", "tftpfiledir", "threatanalytics:analytics_whitelist", "threatanalytics:moduleset", "threatanalytics:whitelist", "threatinsight:cloudclient", "threatprotection:grid:rule", "threatprotection:profile", "threatprotection:profile:rule", "threatprotection:rule", "threatprotection:rulecategory", "threatprotection:ruleset", "threatprotection:ruletemplate", "threatprotection:statistics", "upgradegroup", "upgradeschedule", "upgradestatus", "userprofile", "vdiscoverytask", "view", "vlan", "vlanrange", "vlanview", "zone_auth", "zone_auth_discrepancy", "zone_delegated", "zone_forward", "zone_rp", "zone_stub" )][string] $Object, [int] $MaxResults, [switch] $FetchFromSchema, [string[]] $ReturnFields ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxObjects - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Object) { Write-Verbose -Message "Get-InfobloxObjects - Requesting $Object" if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "$Object" } $invokeInfobloxQuerySplat = @{ RelativeUri = $Object.ToLower() Method = 'GET' QueryParameter = @{ _return_fields = $ReturnFields } } if ($MaxResults) { $invokeInfobloxQuerySplat.QueryParameter._max_results = $MaxResults } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } else { foreach ($Ref in $ReferenceID) { Write-Verbose -Message "Get-InfobloxObjects - Requesting $Ref" if ($FetchFromSchema) { $ObjectType = $Ref.Split('/')[0] $ReturnFields = Get-FieldsFromSchema -SchemaObject "$ObjectType" if ($ReturnFields) { Write-Verbose -Message "Get-InfobloxObjects - Requesting $ObjectType with fields $ReturnFields" } else { Write-Warning -Message "Get-InfobloxObjects - Failed to get fields for $ObjectType" } } $invokeInfobloxQuerySplat = @{ RelativeUri = $Ref Method = 'GET' QueryParameter = @{ _return_fields = $ReturnFields } } if ($MaxResults) { $invokeInfobloxQuerySplat.QueryParameter._max_results = $MaxResults } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } } } function Get-InfobloxPermission { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxPermissions - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "permission" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'permission' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxResponsePolicyZones { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxResponsePolicyZones - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "zone_rp" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'zone_rp' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Get-InfobloxSchema { <# .SYNOPSIS Get the schema for Infoblox as a whole or a specific object .DESCRIPTION Get the schema for Infoblox as a whole or a specific object .PARAMETER Object The object to get the schema for .PARAMETER ReturnReadOnlyFields Return only read-only fields in format suitable for use with Invoke-InfobloxQuery .PARAMETER ReturnWriteFields Return only write fields in format suitable for use with Invoke-InfobloxQuery .PARAMETER ReturnFields Return all fields in full objects .EXAMPLE Get-InfobloxSchema .EXAMPLE Get-InfobloxSchema -Object 'record:host' .NOTES General notes #> [CmdletBinding()] param( [string] $Object, [switch] $ReturnReadOnlyFields, [switch] $ReturnWriteFields, [switch] $ReturnFields ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxSchema - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Object) { $invokeInfobloxQuerySplat = @{ RelativeUri = "$($Object.ToLower())" Method = 'Get' Query = @{ _schema = $true } } } else { $invokeInfobloxQuerySplat = @{ RelativeUri = "?_schema" Method = 'Get' } } $Query = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false if ($Query) { if ($ReturnReadOnlyFields) { Get-FieldsFromSchema -Schema $Query -SchemaObject $Object } elseif ($ReturnWriteFields) { $Fields = ((Get-InfobloxSchema -Object $Object).Fields | Where-Object { $_.supports -like "*r*" }).Name $Fields -join ',' } elseif ($ReturnFields) { (Get-InfobloxSchema -Object $Object).Fields } else { $Query } } else { Write-Warning -Message 'Get-InfobloxSchema - No schema returned' } } function Get-InfoBloxSearch { [CmdletBinding()] param( [parameter(ParameterSetName = 'IPv4')][string] $IPv4Address ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfoBloxSearch - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Get-InfoBloxSearch - Requesting IPv4Address [$IPv4Address]" $invokeInfobloxQuerySplat = [ordered]@{ RelativeUri = 'search' Method = 'GET' QueryParameter = [ordered]@{ _max_results = 1000000 } } if ($IPv4Address) { $invokeInfobloxQuerySplat.QueryParameter.address = $IPv4Address } Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false } function Get-InfobloxVDiscoveryTask { [cmdletbinding()] param( [switch] $FetchFromSchema ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Get-InfobloxVDiscoveryTask - You must first connect to an Infoblox server using Connect-Infoblox' return } # defalt return fields if ($FetchFromSchema) { $ReturnFields = Get-FieldsFromSchema -SchemaObject "vdiscoverytask" } $invokeInfobloxQuerySplat = @{ RelativeUri = 'vdiscoverytask' Method = 'GET' QueryParameter = @{ _max_results = 1000000 _return_fields = $ReturnFields } } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat -WhatIf:$false $Output | Select-ObjectByProperty -LastProperty '_ref' } function Invoke-InfobloxQuery { [CmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)][string] $BaseUri, [parameter(Mandatory)][string] $RelativeUri, [parameter()][pscredential] $Credential, [Parameter()][Microsoft.PowerShell.Commands.WebRequestSession] $WebSession, [parameter()][System.Collections.IDictionary] $QueryParameter, [parameter()][string] $Method = 'GET', [parameter()][System.Collections.IDictionary] $Body ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Invoke-InfobloxQuery - You must first connect to an Infoblox server using Connect-Infoblox' return } if (-not $Credential -and -not $WebSession) { if ($ErrorActionPreference -eq 'Stop') { throw 'Invoke-InfobloxQuery - You must provide either a Credential or a WebSession with a cookie from Connect-Infoblox' } Write-Warning -Message 'Invoke-InfobloxQuery - You must provide either a Credential or a WebSession with a cookie from Connect-Infoblox' return } $joinUriQuerySplat = @{ BaseUri = $BaseUri RelativeOrAbsoluteUri = $RelativeUri } if ($QueryParameter) { $joinUriQuerySplat['QueryParameter'] = $QueryParameter } $Url = Join-UriQuery @joinUriQuerySplat if ($Body) { $JSONBody = $Body | ConvertTo-Json -Depth 10 Write-Debug -Message "Invoke-InfobloxQuery - Body: $JSONBody" } if ($PSCmdlet.ShouldProcess($Url, "Invoke-InfobloxQuery - $Method")) { Write-Verbose -Message "Invoke-InfobloxQuery - Querying $Url with $Method" try { $invokeRestMethodSplat = @{ Uri = $Url Method = $Method Credential = $Credential ContentType = 'application/json' ErrorAction = 'Stop' Verbose = $false WebSession = $WebSession TimeoutSec = 600 } if ($Body) { $invokeRestMethodSplat.Body = $JSONBody } if ($Script:InfobloxConfiguration['SkipCertificateValidation'] -eq $true) { $invokeRestMethodSplat.SkipCertificateCheck = $true } Remove-EmptyValue -Hashtable $invokeRestMethodSplat -Recursive -Rerun 2 Invoke-RestMethod @invokeRestMethodSplat # we connected to the server, so we can reset the default Credentials value $PSDefaultParameterValues['Invoke-InfobloxQuery:Credential'] = $null } catch { if ($PSVersionTable.PSVersion.Major -gt 5) { $OriginalError = $_.Exception.Message if ($_.ErrorDetails.Message) { try { $JSONError = ConvertFrom-Json -InputObject $_.ErrorDetails.Message -ErrorAction Stop } catch { if ($ErrorActionPreference -eq 'Stop') { throw $OriginalError } Write-Warning -Message "Invoke-InfobloxQuery - Querying $Url failed. Error: $OriginalError" return } if ($JSONError -and $JSONError.text) { if ($ErrorActionPreference -eq 'Stop') { throw $JSONError.text } Write-Warning -Message "Invoke-InfobloxQuery - Querying $Url failed. $($JSONError.text)" return } else { if ($ErrorActionPreference -eq 'Stop') { throw $OriginalError } Write-Warning -Message "Invoke-InfobloxQuery - Querying $Url failed. Error: $OriginalError" } } else { if ($ErrorActionPreference -eq 'Stop') { throw } Write-Warning -Message "Invoke-InfobloxQuery - Querying $Url failed. Error: $OriginalError" } } else { if ($ErrorActionPreference -eq 'Stop') { throw } Write-Warning -Message "Invoke-InfobloxQuery - Querying $Url failed. Error: $($_.Exception.Message)" } } } } function New-InfobloxOption { <# .SYNOPSIS Creates a dummy Infoblox option to use within other cmdlets .DESCRIPTION This function creates a new Infoblox option. It's just syntactic sugar to make it easier to create options to use within other cmdlets. .PARAMETER Name The name of the Infoblox option. This parameter is mandatory. .PARAMETER Number The number of the Infoblox option. This parameter is mandatory. .PARAMETER UseOption A switch indicating whether to use the option. This parameter is mandatory. .PARAMETER Value The value of the Infoblox option. This parameter is mandatory. .PARAMETER VendorClass The vendor class of the Infoblox option. This parameter is mandatory. .EXAMPLE $addInfobloxDHCPRangeSplat = @{ StartAddress = '10.10.12.5' EndAddress = '10.10.12.10' Options = @( New-InfobloxOption -Name "dhcp-lease-time" -Number 51 -UseOption -Value '86400' -VendorClass 'DHCP' New-InfobloxOption -Name "domain-name-servers" -Number 6 -UseOption -Value '192.168.0.15' -VendorClass 'DHCP' New-InfobloxOption -Name 'routers' -Number 3 -UseOption -Value '192.168.11.12' -VendorClass 'DHCP' New-InfobloxOption -Name 'time-servers' -Number 4 -UseOption -Value '11' -VendorClass 'DHCP' ) MsOptions = @( New-InfobloxOption -Name "dhcp-lease-time" -Number 51 -UseOption -Value '86400' -VendorClass 'DHCP' New-InfobloxOption -Name "domain-name-servers" -Number 6 -UseOption -Value '192.168.0.15' -VendorClass 'DHCP' New-InfobloxOption -Name 'routers' -Number 3 -UseOption -Value '192.168.11.12' -VendorClass 'DHCP' New-InfobloxOption -Name 'time-servers' -Number 4 -UseOption -Value '11' -VendorClass 'DHCP' ) Verbose = $true } Add-InfobloxDHCPRange @addInfobloxDHCPRangeSplat .NOTES This function is used to create a dummy Infoblox option to use within other cmdlets. #> [CmdletBinding()] param( [Parameter(Mandatory)][string] $Name, [Parameter(Mandatory)][alias('Num')][int] $Number, [Parameter()][switch] $UseOption, [Parameter(Mandatory)][string] $Value, [Parameter(Mandatory)][string] $VendorClass ) $Object = [ordered] @{ "name" = $Name "num" = $Number "use_option" = if ($PSBoundParameters.ContainsKey('UseOption')) { $UseOption.IsPresent } else { $null } "value" = $Value "vendor_class" = $VendorClass } Remove-EmptyValue -Hashtable $Object $Object } function Remove-InfobloxDHCPRangeOptions { <# .SYNOPSIS Removes DHCP range options from an Infoblox server. .DESCRIPTION This function removes specified DHCP range options from an Infoblox server. It allows removing options and Microsoft-specific options for a given network or reference ID. .PARAMETER Type Specifies the type of options to remove. Valid values are 'Options' and 'MsOptions'. .PARAMETER Network The network for which to remove DHCP options. .PARAMETER ReferenceID The unique identifier for the DHCP range to be modified. .PARAMETER Name The name of the DHCP option to be removed. .EXAMPLE Remove-InfobloxDHCPRangeOptions -Type 'Options' -Network '192.168.1.0/24' -Name 'domain-name-servers' .EXAMPLE Remove-InfobloxDHCPRangeOptions -Type 'MsOptions' -ReferenceID 'DHCPRange-1' -Name 'time-servers' .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)] [ValidateSet('Options', 'MsOptions')] [string] $Type, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [string] $Network, [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $ReferenceID, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $Name ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Remove-InfobloxDHCPRangeOptions - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Network) { $DHCPRange = Get-InfobloxDHCPRange -Network $Network -ReturnFields 'options', 'ms_options' } elseif ($ReferenceID) { $DHCPRange = Get-InfobloxDHCPRange -ReferenceID $ReferenceID -ReturnFields 'options', 'ms_options' } else { Write-Warning -Message 'You must specify either a Network or a ReferenceID' return } if (-not $DHCPRange -or $null -eq $DHCPRange._ref) { Write-Warning -Message 'Remove-InfobloxDHCPRangeOptions - No DHCP Range found' return } $OptionFound = $false [Array] $NewOptions = @( if ($Type -eq 'options') { $Options = $DHCPRange.options | Select-Object -Property name, num, use_option, value, vendor_class foreach ($Option in $Options) { if ($Option.name -eq $Name) { Write-Verbose -Message "Remove-InfobloxDHCPRangeOptions - Changes required for $Name. Removal required!" $OptionFound = $true } else { $Option } } } else { $MSOptions = $DHCPRange.ms_options | Select-Object -Property name, num, value, vendor_class foreach ($MSOption in $MSOptions) { if ($MSOption.name -eq $Name) { Write-Verbose -Message "Remove-InfobloxDHCPRangeOptions - Changes required for $Name. Removal required!" $OptionFound = $true } else { $MSOption } } } ) if (-not $OptionFound) { Write-Verbose -Message "Remove-InfobloxDHCPRangeOptions - Change not required. Option $Name not found" } else { if ($Type -eq 'options') { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -Options $NewOptions } else { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -MSOptions $NewOptions } } } function Remove-InfobloxDnsRecord { <# .SYNOPSIS Remove Infoblox DNS records .DESCRIPTION Remove Infoblox DNS records .PARAMETER Name Name of the record to remove .PARAMETER Type Type of the record to remove .PARAMETER SkipPTR Skip PTR record removal, when removing A record .PARAMETER LogPath Path to log file. Changes are logged to this file .EXAMPLE Remove-InfobloxDnsRecord -Name 'test.example.com' -Type 'A' -WhatIf .EXAMPLE Remove-InfobloxDnsRecord -Name 'test.example.com' -Type 'A' -SkipPTR -WhatIf .NOTES General notes #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][string[]] $Name, [ValidateSet( 'A', 'CNAME', 'AAAA', 'PTR' )] [Parameter(Mandatory)][string] $Type, [switch] $SkipPTR, [string] $LogPath ) [Array] $ToBeDeleted = foreach ($Record in $Name) { $FoundRecord = Get-InfobloxDNSRecord -Name $Record -Type $Type -Verbose:$false if ($FoundRecord) { $FoundRecord if ($LogPath) { Write-Color -Text "Found $($FoundRecord.name) with type $Type to be removed" -LogFile $LogPath -NoConsoleOutput } } else { Write-Verbose -Message "Remove-InfobloxDnsRecord - No record for $Record were found. Skipping" if ($LogPath) { Write-Color -Text "No record for $Record were found. Skipping" -LogFile $LogPath -NoConsoleOutput } } } Write-Verbose -Message "Remove-InfobloxDnsRecord - Found $($ToBeDeleted.Count) records to delete" [Array] $ToBeDeletedPTR = @( if ($Type -eq 'A' -and -not $SkipPTR) { foreach ($Record in $ToBeDeleted) { if ($null -eq $Record.ipv4addr) { continue } try { $PTRAddress = Convert-IpAddressToPtrString -IPAddress $Record.ipv4addr -ErrorAction Stop } catch { Write-Warning -Message "Remove-InfobloxDnsRecord - Failed to convert $($Record.ipv4addr) to PTR" if ($LogPath) { Write-Color -Text "Failed to convert $($Record.ipv4addr) to PTR" -NoConsoleOutput -LogFile $LogPath } } if ($PTRAddress) { $PTRRecord = Get-InfobloxDNSRecord -Type PTR -Name $PTRAddress -Verbose:$false if ($PTRRecord) { $PTRRecord if ($LogPath) { Write-Color -Text "Found $($PTRRecord.name) with type PTR to be removed" -NoConsoleOutput -LogFile $LogPath } } else { Write-Verbose -Message "Remove-InfobloxDnsRecord - No PTR record for $($Record.name) were found. Skipping" if ($LogPath) { Write-Color -Text "No PTR record for $($Record.name) were found. Skipping" -NoConsoleOutput -LogFile $LogPath } } } } } ) if ($ToBeDeletedPTR.Count -gt 0) { Write-Verbose -Message "Remove-InfobloxDnsRecord - Found $($ToBeDeletedPTR.Count) PTR records to delete" } foreach ($Record in $ToBeDeleted) { if (-not $Record._ref) { Write-Warning -Message "Remove-InfobloxDnsRecord - Record does not have a reference ID, skipping" if ($LogPath) { Write-Color -Text "Record does not have a reference ID, skipping" -NoConsoleOutput -LogFile $LogPath } continue } Write-Verbose -Message "Remove-InfobloxDnsRecord - Removing $($Record.name) with type $Type / WhatIf:$WhatIfPreference" if ($LogPath) { Write-Color -Text "Removing $($Record.name) with type $Type" -NoConsoleOutput -LogFile $LogPath } try { $Success = Remove-InfobloxObject -ReferenceID $Record._ref -WhatIf:$WhatIfPreference -ErrorAction Stop -ReturnSuccess -Verbose:$false if ($Success -eq $true -or $WhatIfPreference) { Write-Verbose -Message "Remove-InfobloxDnsRecord - Removed $($Record.name) with type $Type / WhatIf: $WhatIfPreference" if ($LogPath) { Write-Color -Text "Removed $($Record.name) with type $Type" -NoConsoleOutput -LogFile $LogPath } } else { # this shouldn't really happen as the error action is set to stop Write-Warning -Message "Remove-InfobloxDnsRecord - Failed to remove $($Record.name) with type $Type / WhatIf: $WhatIfPreference" if ($LogPath) { Write-Color -Text "Failed to remove $($Record.name) with type $Type / WhatIf: $WhatIfPreference" -NoConsoleOutput -LogFile $LogPath } } } catch { Write-Warning -Message "Remove-InfobloxDnsRecord - Failed to remove $($Record.name) with type $Type, error: $($_.Exception.Message)" if ($LogPath) { Write-Color -Text "Failed to remove $($Record.name) with type $Type, error: $($_.Exception.Message)" -NoConsoleOutput -LogFile $LogPath } } } foreach ($Record in $ToBeDeletedPTR) { if (-not $Record._ref) { Write-Warning -Message "Remove-InfobloxDnsRecord - PTR record does not have a reference ID, skipping" if ($LogPath) { Write-Color -Text "PTR record does not have a reference ID, skipping" -NoConsoleOutput -LogFile $LogPath } continue } Write-Verbose -Message "Remove-InfobloxDnsRecord - Removing $($Record.name) with type PTR / WhatIf:$WhatIfPreference" if ($LogPath) { Write-Color -Text "Removing $($Record.name) with type PTR / WhatIf: $WhatIfPreference" -NoConsoleOutput -LogFile $LogPath } try { $Success = Remove-InfobloxObject -ReferenceID $Record._ref -WhatIf:$WhatIfPreference -ErrorAction Stop -ReturnSuccess -Verbose:$false if ($Success -eq $true -or $WhatIfPreference) { Write-Verbose -Message "Remove-InfobloxDnsRecord - Removed $($Record.name) with type PTR / WhatIf: $WhatIfPreference" if ($LogPath) { Write-Color -Text "Removed $($Record.name) with type PTR / WhatIf: $WhatIfPreference" -NoConsoleOutput -LogFile $LogPath } } else { # this shouldn't really happen as the error action is set to stop Write-Warning -Message "Remove-InfobloxDnsRecord - Failed to remove $($Record.name) with type PTR / WhatIf: $WhatIfPreference" if ($LogPath) { Write-Color -Text "Failed to remove $($Record.name) with type PTR / WhatIf: $WhatIfPreference" -NoConsoleOutput -LogFile $LogPath } } } catch { Write-Warning -Message "Remove-InfobloxDnsRecord - Failed to remove $($Record.name) with type PTR, error: $($_.Exception.Message)" if ($LogPath) { Write-Color -Text "Failed to remove $($Record.name) with type PTR, error: $($_.Exception.Message)" -NoConsoleOutput -LogFile $LogPath } } } } function Remove-InfobloxFixedAddress { [cmdletbinding(SupportsShouldProcess)] param( [parameter(Mandatory)][string] $MacAddress, [parameter()][string] $IPv4Address ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Remove-InfobloxFixedAddress - You must first connect to an Infoblox server using Connect-Infoblox' return } if (-not $IPv4Address) { Write-Verbose -Message "Remove-InfobloxFixedAddress - Removing $MacAddress" } else { Write-Verbose -Message "Remove-InfobloxFixedAddress - Removing $MacAddress from $IPv4Address" } $ListMacaddresses = Get-InfobloxFixedAddress -MacAddress $MacAddress if ($IPv4Address) { $ListMacaddresses = $ListMacaddresses | Where-Object -Property ipv4addr -EQ -Value $IPv4Address } foreach ($Mac in $ListMacaddresses) { $invokeInfobloxQuerySplat = @{ RelativeUri = "$($Mac._ref)" Method = 'DELETE' } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat #-WarningAction SilentlyContinue -WarningVariable varWarning if ($Output) { Write-Verbose -Message "Remove-InfobloxFixedAddress - Removed $($Mac.ipv4addr) with mac address $($Mac.mac) / $Output" } #else { #if (-not $WhatIfPreference) { # Write-Warning -Message "Remove-InfobloxFixedAddress - Failed to remove $($Mac.ipv4addr) with mac address $($Mac.mac), error: $varWarning" #} #} } } function Remove-InfobloxIPAddress { <# .SYNOPSIS Removes an IP address from Infoblox. .DESCRIPTION This function removes an IP address from Infoblox. It checks for an existing connection to an Infoblox server, established via Connect-Infoblox, before attempting the removal. The function supports verbose output for detailed operation insights. .PARAMETER IPv4Address The IPv4 address to be removed from Infoblox. This parameter is mandatory. .EXAMPLE Remove-InfobloxIPAddress -IPv4Address '192.168.1.100' Removes the IP address 192.168.1.100 from Infoblox. .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before executing this function. The function uses Write-Verbose for detailed operation output, which can be enabled by setting $VerbosePreference or using the -Verbose switch. #> [cmdletbinding(SupportsShouldProcess)] param( [parameter()][string] $IPv4Address ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Remove-InfobloxIPAddress - You must first connect to an Infoblox server using Connect-Infoblox' return } Write-Verbose -Message "Remove-InfobloxIPAddress - Removing $IPv4Address" $ListIP = Get-InfobloxIPAddress -IPv4Address $IPv4Address foreach ($IP in $ListIP) { $invokeInfobloxQuerySplat = @{ RelativeUri = "$($IP._ref)" Method = 'DELETE' } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Remove-InfobloxIPAddress - Removed $($IP.ip_address) from network $($IP.network) / $Output" } } } function Remove-InfobloxNetworkExtensibleAttribute { <# .SYNOPSIS Removes an extensible attribute from a specified network in Infoblox. .DESCRIPTION This function removes an extensible attribute from a network in Infoblox. It requires an established connection to an Infoblox server, which can be done using the Connect-Infoblox function. The function checks if the specified network exists before attempting to remove the extensible attribute. .PARAMETER Network The network from which the extensible attribute will be removed. This parameter is mandatory. .PARAMETER Attribute The name of the extensible attribute to remove. This parameter is mandatory. .EXAMPLE Remove-InfobloxNetworkExtensibleAttribute -Network '192.168.1.0/24' -Attribute 'Location' Removes the 'Location' extensible attribute from the network '192.168.1.0/24'. .NOTES You must first connect to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][alias('Subnet')][string] $Network, [Parameter(Mandatory)][alias('ExtensibleAttribute')][string] $Attribute ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Remove-InfobloxNetworkExtensibleAttribute - You must first connect to an Infoblox server using Connect-Infoblox' return } $NetworkInformation = Get-InfobloxNetwork -Network $Network if (-not $NetworkInformation._ref) { Write-Warning -Message "Remove-InfobloxNetworkExtensibleAttribute - Network $Network not found" return } $Body = [ordered] @{ "extattrs-" = @{ $Attribute = @{} } } Remove-EmptyValue -Hashtable $Body $invokeInfobloxQuerySplat = @{ RelativeUri = $NetworkInformation._ref Method = 'PUT' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Remove-InfobloxNetworkExtensibleAttribute - $Output" if ($ReturnOutput) { $Output } } } function Remove-InfobloxObject { <# .SYNOPSIS Remove an Infoblox object by reference ID .DESCRIPTION Remove an Infoblox object by reference ID It can be used to remove any object type, but it is recommended to use the more specific cmdlets .PARAMETER Objects An array of objects to remove .PARAMETER ReferenceID The reference ID of the object to remove .EXAMPLE Remove-InfobloxObject -ReferenceID 'record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5pbmZvLmhvc3Q6MTcyLjI2LjEuMjAu:' .NOTES General notes #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ReferenceID')] param( [Parameter(Mandatory, ParameterSetName = 'Array')][Array] $Objects, [parameter(Mandatory, ParameterSetName = 'ReferenceID')][string] $ReferenceID, [switch] $ReturnSuccess ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Remove-InfobloxObject - You must first connect to an Infoblox server using Connect-Infoblox' return } if ($Objects) { $Objects | ForEach-Object { if ($_._ref) { $ReferenceID = $_._ref Remove-InfobloxObject -ReferenceID $ReferenceID } else { Write-Warning -Message "Remove-InfobloxObject - Object does not have a reference ID: $_" } } } else { $invokeInfobloxQuerySplat = @{ RelativeUri = $ReferenceID Method = 'DELETE' } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat #-WarningAction SilentlyContinue -WarningVariable varWarning if ($Output) { Write-Verbose -Message "Remove-InfobloxObject - Removed $($ReferenceID) / $Output" if ($ReturnSuccess) { $true } } else { if ($ReturnSuccess) { $false } } } } function Set-InfobloxDHCPRange { <# .SYNOPSIS Sets the DHCP range configuration on an Infoblox server. .DESCRIPTION This function modifies the DHCP range configuration on an Infoblox server. It allows setting comments, Microsoft options, and other DHCP options. .PARAMETER ReferenceID The unique identifier for the DHCP range to be modified. .PARAMETER Comment A comment to associate with the DHCP range. .PARAMETER MSServer The Microsoft DHCP server associated with the range. .PARAMETER ExtensinbleAttribute A hashtable of extensible attributes to associate with the DHCP range. .PARAMETER Options An array of general DHCP options. .PARAMETER MSOptions An array of Microsoft-specific DHCP options. .PARAMETER FailoverAssociation The failover association for the DHCP range. .PARAMETER ServerAssociationType The type of server association. Valid values are 'MEMBER', 'MS_FAILOVER', 'NONE', 'MS_SERVER', 'FAILOVER'. .PARAMETER Exclude An array of IP addresses or address ranges to exclude from the DHCP range. .PARAMETER AlwaysUpdateDns Indicates whether to always update DNS. .PARAMETER Disable Indicates whether to disable the DHCP range. .EXAMPLE Set-InfobloxDHCPRange -ReferenceID 'DHCPRange-1' -Comment 'This is a DHCP range.' .EXAMPLE Set-InfobloxDHCPRange -ReferenceID 'DHCPRange-1' -Options @( New-InfobloxOption -Name "dhcp-lease-time" -Number 51 -UseOption -Value '86400' -VendorClass 'DHCP' New-InfobloxOption -Name "domain-name-servers" -Number 6 -UseOption -Value '192.168.0.15' -VendorClass 'DHCP' New-InfobloxOption -Name 'routers' -Number 3 -UseOption -Value '192.168.11.12' -VendorClass 'DHCP' New-InfobloxOption -Name 'time-servers' -Number 4 -UseOption -Value '11' -VendorClass 'DHCP' ) .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [parameter(ParameterSetName = 'ReferenceID', Mandatory)][string] $ReferenceID, [string] $Comment, [string] $MSServer, [System.Collections.IDictionary] $ExtensinbleAttribute, [Array] $Options, [Alias('ms_options')][Array] $MSOptions, [alias('failover_association')][string] $FailoverAssociation, [ValidateSet('MEMBER', 'MS_FAILOVER', 'NONE', 'MS_SERVER', 'FAILOVER')] [string] $ServerAssociationType, [Array] $Exclude, [switch] $AlwaysUpdateDns, [switch] $Disable ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Set-InfobloxDHCPRange - You must first connect to an Infoblox server using Connect-Infoblox' return } $Body = [ordered] @{} if ($Comment) { $Body["comment"] = $Comment } if ($ServerAssociationType) { $Body["server_association_type"] = $ServerAssociationType } if ($MSServer) { $Body["ms_server"] = [PSCustomObject] @{ "_struct" = "msdhcpserver" "ipv4addr" = $MSServer } } if ($ExtensinbleAttribute) { $Body["extattrs"] = [ordered] @{} foreach ($Key in $ExtensinbleAttribute.Keys) { if ($ExtensinbleAttribute[$Key] -is [System.Collections.IDictionary]) { $Body["extattrs"][$Key] = $ExtensinbleAttribute[$Key] } else { $Body["extattrs"][$Key] = @{ value = $ExtensinbleAttribute[$Key] } } } } if ($Options) { $Body["options"] = @( foreach ($Option in $Options) { $Option | Select-Object -Property name, num, use_option, value, vendor_class } ) } if ($MSOptions) { $Body["ms_options"] = @( foreach ($MSOption in $MSOptions) { $MSOption | Select-Object -Property name, num, value, vendor_class } ) } if ($FailoverAssociation) { $Body["failover_association"] = $FailoverAssociation } if ($Exclude) { $Body["exclude"] = @( foreach ($ExcludeItem in $Exclude) { if ($ExcludeItem -is [string]) { if ($ExcludeItem -like "*-*") { $ExcludeItem = $ExcludeItem -split '-' $ExcludeItem = @{ StartAddress = $ExcludeItem[0] EndAddress = $ExcludeItem[1] } } else { $ExcludeItem = @{ StartAddress = $ExcludeItem EndAddress = $ExcludeItem } } } [ordered] @{ "start_address" = $ExcludeItem.StartAddress "end_address" = $ExcludeItem.EndAddress } } ) } if ($PSBoundParameters.ContainsKey('AlwaysUpdateDns')) { $Body["always_update_dns"] = $AlwaysUpdateDns.IsPresent } if ($PSBoundParameters.ContainsKey('Disable')) { $Body["disable"] = $Disable.IsPresent } if ($Body.Count -eq 0) { Write-Warning -Message 'Set-InfobloxDHCPRange - No changes requested' return } $invokeInfobloxQuerySplat = @{ RelativeUri = $ReferenceID Method = 'PUT' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Set-InfobloxDHCPRange - Modified $Output" } } function Set-InfobloxDHCPRangeOptions { <# .SYNOPSIS Sets DHCP range options on an Infoblox server. .DESCRIPTION This function modifies the DHCP range options on an Infoblox server. It allows setting options and Microsoft-specific options for a given network or reference ID. .PARAMETER Type Specifies the type of options to set. Valid values are 'Options' and 'MsOptions'. .PARAMETER Network The network for which to set DHCP options. .PARAMETER ReferenceID The unique identifier for the DHCP range to be modified. .PARAMETER Name The name of the DHCP option. .PARAMETER Number The number of the DHCP option. .PARAMETER Value The value of the DHCP option. .PARAMETER VendorClass The vendor class of the DHCP option. .PARAMETER UseOption Indicates whether to use the option. .EXAMPLE Set-InfobloxDHCPRangeOptions -Type 'Options' -Network '192.168.1.0/24' -Name 'domain-name-servers' -Number 6 -Value '192.168.0.15' -VendorClass 'DHCP' -UseOption .EXAMPLE Set-InfobloxDHCPRangeOptions -Type 'MsOptions' -ReferenceID 'DHCPRange-1' -Name 'time-servers' -Number 4 -Value '11' -VendorClass 'DHCP' .NOTES Ensure you are connected to an Infoblox server using Connect-Infoblox before running this function. #> [CmdletBinding(SupportsShouldProcess)] param( [parameter(Mandatory)] [ValidateSet('Options', 'MsOptions')] [string] $Type, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [string] $Network, [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $ReferenceID, [parameter(ParameterSetName = 'NetworkOption', Mandatory)] [parameter(ParameterSetName = 'ReferenceOption', Mandatory)] [string] $Name, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [alias('Num')][System.Nullable[int]] $Number, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [string] $Value, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [string] $VendorClass, [parameter(ParameterSetName = 'NetworkOption')] [parameter(ParameterSetName = 'ReferenceOption')] [switch] $UseOption ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Set-InfobloxDHCPRangeOptions - You must first connect to an Infoblox server using Connect-Infoblox' return } $Object = [ordered] @{ "name" = $Name "num" = $Number "use_option" = if ($PSBoundParameters.ContainsKey('UseOption')) { $UseOption.IsPresent } else { $null } "value" = $Value "vendor_class" = $VendorClass } if ($Type -eq 'options') { } else { if ($UseOption.IsPresent) { Write-Warning -Message 'Set-InfobloxDHCPRangeOptions - use_option is not a valid parameter for MSOptions' $Object.Remove('use_option') } } Remove-EmptyValue -Hashtable $Object if ($Network) { $DHCPRange = Get-InfobloxDHCPRange -Network $Network -ReturnFields 'options', 'ms_options' } elseif ($ReferenceID) { $DHCPRange = Get-InfobloxDHCPRange -ReferenceID $ReferenceID -ReturnFields 'options', 'ms_options' } else { Write-Warning -Message 'You must specify either a Network or a ReferenceID' return } if (-not $DHCPRange -or $null -eq $DHCPRange._ref) { Write-Warning -Message 'Set-InfobloxDHCPRangeOptions - No DHCP Range found' return } $ChangeRequired = $false $OptionFound = $false [Array] $NewOptions = @( if ($Type -eq 'options') { $Options = $DHCPRange.options | Select-Object -Property name, num, use_option, value, vendor_class foreach ($Option in $Options) { if ($Option.name -eq $Name) { $OptionFound = $true foreach ($Key in $Object.Keys) { if ($Object.$Key -ne $Option.$Key) { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - Preparing overwrite $Name for $Key to $($Object.$Key)" $Option.$Key = $Object.$Key $ChangeRequired = $true } else { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - No changes required $Name for $Key, as it already exists with the same values" } } if ($ChangeRequired) { $Option } } else { $Option } } if (-not $OptionFound) { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - Changes required for $Name. Does not exist yet!" $Object $ChangeRequired = $true } } else { $MSOptions = $DHCPRange.ms_options | Select-Object -Property name, num, value, vendor_class foreach ($MSOption in $MSOptions) { if ($MSOption.name -eq $Name) { $OptionFound = $true foreach ($Key in $Object.Keys) { if ($Object.$Key -ne $MSOption.$Key) { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - Preparing overwrite $Name for $Key to $($Object.$Key)" $MSOption.$Key = $Object.$Key $ChangeRequired = $true } else { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - No changes required $Name for $Key, as it already exists with the same values" } } if ($ChangeRequired) { $MSOption } } else { $MSOption } } if (-not $OptionFound) { Write-Verbose -Message "Set-InfobloxDHCPRangeOptions - Changes required for $Name. Does not exist yet!" $Object $ChangeRequired = $true } } ) if ($ChangeRequired) { if ($Type -eq 'options') { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -Options $NewOptions } else { Set-InfobloxDHCPRange -ReferenceID $DHCPRange._ref -MSOptions $NewOptions } } else { Write-Warning -Message 'Set-InfobloxDHCPRangeOptions - No changes required' } } function Set-InfobloxDNSRecord { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ReferenceID Parameter description .PARAMETER Object Parameter description .PARAMETER Type Parameter description .EXAMPLE Set-InfobloxDNSRecord -ReferenceID 'record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5teW5ldC5jb20kMTAuMTAuMTAuMTA=' -Name 'xyz' -Type 'A' .EXAMPLE Set-InfobloxDNSRecord -ReferenceID 'record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5teW5ldC5jb20kMTAuMTAuMTAuMTA=' -PTRName 'xyz -Type 'PTR' .EXAMPLE Set-InfobloxDNSRecord -ReferenceID 'record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5teW5ldC5jb20kMTAuMTAuMTAuMTA=' -Name 'test2.mcdonalds.com' -Type 'CNAME' .NOTES General notes #># [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ReferenceID')] param( [parameter(ParameterSetName = 'ReferenceID', Mandatory)][string] $ReferenceID, [Alias("Name", 'PtrName', 'PTR', 'NameServer', 'Text')][parameter(ParameterSetName = 'Object', Mandatory)][string] $Object, [parameter(Mandatory)][ValidateSet( 'A', 'AAAA', 'CNAME', 'HOST', 'PTR', 'MX', 'NS', 'TXT' )][string] $Type ) if (-not $Script:InfobloxConfiguration) { if ($ErrorActionPreference -eq 'Stop') { throw 'You must first connect to an Infoblox server using Connect-Infoblox' } Write-Warning -Message 'Set-InfobloxDNSRecord - You must first connect to an Infoblox server using Connect-Infoblox' return } # Lets convert it to lowercase, since Infoblox is case sensitive $Type = $Type.ToLower() if ($Type -in 'A', 'AAAA', 'HOST', 'CNAME', 'MX') { $Body = [ordered] @{ name = $Object.ToLower() } } elseif ($Type -eq 'PTR') { $Body = [ordered] @{ ptrdname = $Object.ToLower() } } elseif ($Type -eq 'NS') { $Body = [ordered] @{ nameserver = $Object.ToLower() } } elseif ($Type -eq 'TXT') { $Body = [ordered] @{ text = $Object.ToLower() } } else { if ($ErrorActionPreference -eq 'Stop') { throw "Set-InfobloxDNSRecord - Unsupported type: $Type" } Write-Warning -Message "Set-InfobloxDNSRecord - Unsupported type: $Type" return } $invokeInfobloxQuerySplat = @{ RelativeUri = $ReferenceID Method = 'PUT' Body = $Body } $Output = Invoke-InfobloxQuery @invokeInfobloxQuerySplat if ($Output) { Write-Verbose -Message "Set-InfobloxDNSRecord - Modified $Type / $Output" } } # Export functions and aliases as required Export-ModuleMember -Function @('Add-InfobloxDHCPRange', 'Add-InfobloxDHCPRangeOptions', 'Add-InfobloxDHCPReservation', 'Add-InfoBloxDNSRecord', 'Add-InfobloxFixedAddress', 'Add-InfobloxNetwork', 'Add-InfobloxNetworkExtensibleAttribute', 'Connect-Infoblox', 'Disconnect-Infoblox', 'Get-InfobloxDHCPLease', 'Get-InfobloxDHCPRange', 'Get-InfobloxDiscoveryTask', 'Get-InfobloxDNSAuthZone', 'Get-InfobloxDNSDelegatedZone', 'Get-InfobloxDNSForwardZone', 'Get-InfobloxDNSRecord', 'Get-InfobloxDNSRecordAll', 'Get-InfobloxDNSView', 'Get-InfobloxFixedAddress', 'Get-InfobloxGrid', 'Get-InfobloxIPAddress', 'Get-InfobloxMember', 'Get-InfobloxNetwork', 'Get-InfobloxNetworkContainer', 'Get-InfobloxNetworkNextAvailableIP', 'Get-InfobloxNetworkNextAvailableNetwork', 'Get-InfobloxNetworkView', 'Get-InfobloxObjects', 'Get-InfobloxPermission', 'Get-InfobloxResponsePolicyZones', 'Get-InfobloxSchema', 'Get-InfoBloxSearch', 'Get-InfobloxVDiscoveryTask', 'Invoke-InfobloxQuery', 'New-InfobloxOption', 'Remove-InfobloxDHCPRangeOptions', 'Remove-InfobloxDnsRecord', 'Remove-InfobloxFixedAddress', 'Remove-InfobloxIPAddress', 'Remove-InfobloxNetworkExtensibleAttribute', 'Remove-InfobloxObject', 'Set-InfobloxDHCPRange', 'Set-InfobloxDHCPRangeOptions', 'Set-InfobloxDNSRecord') -Alias @('Add-InfobloxSubnet', 'Get-InfobloxDHCPLeases', 'Get-InfobloxDNSAuthZones', 'Get-InfobloxDNSRecords', 'Get-InfobloxDNSRecordsAll') # SIG # Begin signature block # MIItqwYJKoZIhvcNAQcCoIItnDCCLZgCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCKPs7yViAqoozH # uJM0jQ/5SJoihfVcxQGPiSG0u6Zq8KCCJq4wggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggWQMIIDeKADAgECAhAFmxtXno4hMuI5B72nd3VcMA0GCSqG # SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIw # aTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLK # EdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4Tm # dDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembu # d8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnD # eMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1 # XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVld # QnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTS # YW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSm # M9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzT # QRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6Kx # fgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD # VR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzANBgkq # hkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNkaA9Wz3eucPn9mkqZucl4 # XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjSPMFDQK4dUPVS/JA7u5iZ # aWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK7VB6fWIhCoDIc2bRoAVg # X+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eBcg3AFDLvMFkuruBx8lbk # apdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp5aPNoiBB19GcZNnqJqGL # FNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msgdDDS4Dk0EIUhFQEI6FUy # 3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vriRbgjU2wGb2dVf0a1TD9u # KFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ79ARj6e/CVABRoIoqyc54 # zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5nLGbsQAe79APT0JsyQq8 # 7kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3i0objwG2J5VT6LaJbVu8 # aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0HEEcRrYc9B9F1vM/zZn4w # ggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbS # g9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9 # /UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXn # HwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0 # VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4f # sbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40Nj # gHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0 # QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvv # mz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T # /jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk # 42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5r # mQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E # FgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5n # P+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcG # CCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu # Y29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln # aUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNV # HSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIB # AH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxp # wc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIl # zpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQ # cAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfe # Kuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+j # Sbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJsh # IUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6 # OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDw # N7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR # 81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2 # VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIGsDCCBJigAwIBAgIQ # CK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEV # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t # MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAw # MDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBT # aWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+k # jmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9 # NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9 # URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegY # E2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS # 4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJa # wv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+w # c86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eR # Gv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF2 # 3r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCK # ZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhEC # AwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2 # O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P # MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcB # AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr # BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAH # BgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6 # mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/ # SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzY # gBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9 # kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ # 9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAew # Q3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5Lm # Tl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HA # SIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xr # y7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhR # ILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFu # v2jiJmCG6sivqf6UHedjGzqGVnhOMIIGvDCCBKSgAwIBAgIQC65mvFq6f5WHxvnp # BOMzBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5 # NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTI0MDkyNjAwMDAwMFoXDTM1MTEy # NTIzNTk1OVowQjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERpZ2lDZXJ0MSAwHgYD # VQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyNDCCAiIwDQYJKoZIhvcNAQEBBQAD # ggIPADCCAgoCggIBAL5qc5/2lSGrljC6W23mWaO16P2RHxjEiDtqmeOlwf0KMCBD # Er4IxHRGd7+L660x5XltSVhhK64zi9CeC9B6lUdXM0s71EOcRe8+CEJp+3R2O8oo # 76EO7o5tLuslxdr9Qq82aKcpA9O//X6QE+AcaU/byaCagLD/GLoUb35SfWHh43rO # H3bpLEx7pZ7avVnpUVmPvkxT8c2a2yC0WMp8hMu60tZR0ChaV76Nhnj37DEYTX9R # eNZ8hIOYe4jl7/r419CvEYVIrH6sN00yx49boUuumF9i2T8UuKGn9966fR5X6kgX # j3o5WHhHVO+NBikDO0mlUh902wS/Eeh8F/UFaRp1z5SnROHwSJ+QQRZ1fisD8UTV # DSupWJNstVkiqLq+ISTdEjJKGjVfIcsgA4l9cbk8Smlzddh4EfvFrpVNnes4c16J # idj5XiPVdsn5n10jxmGpxoMc6iPkoaDhi6JjHd5ibfdp5uzIXp4P0wXkgNs+CO/C # acBqU0R4k+8h6gYldp4FCMgrXdKWfM4N0u25OEAuEa3JyidxW48jwBqIJqImd93N # Rxvd1aepSeNeREXAu2xUDEW8aqzFQDYmr9ZONuc2MhTMizchNULpUEoA6Vva7b1X # CB+1rxvbKmLqfY/M/SdV6mwWTyeVy5Z/JkvMFpnQy5wR14GJcv6dQ4aEKOX5AgMB # AAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUB # Af8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1s # BwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFJ9X # LAN3DigVkGalY17uT5IfdqBbMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1l # U3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhho # dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNl # cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZU # aW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAD2tHh92mVvjOIQS # R9lDkfYR25tOCB3RKE/P09x7gUsmXqt40ouRl3lj+8QioVYq3igpwrPvBmZdrlWB # b0HvqT00nFSXgmUrDKNSQqGTdpjHsPy+LaalTW0qVjvUBhcHzBMutB6HzeledbDC # zFzUy34VarPnvIWrqVogK0qM8gJhh/+qDEAIdO/KkYesLyTVOoJ4eTq7gj9UFAL1 # UruJKlTnCVaM2UeUUW/8z3fvjxhN6hdT98Vr2FYlCS7Mbb4Hv5swO+aAXxWUm3Wp # ByXtgVQxiBlTVYzqfLDbe9PpBKDBfk+rabTFDZXoUke7zPgtd7/fvWTlCs30VAGE # sshJmLbJ6ZbQ/xll/HjO9JbNVekBv2Tgem+mLptR7yIrpaidRJXrI+UzB6vAlk/8 # a1u7cIqV0yef4uaZFORNekUgQHTqddmsPCEIYQP7xGxZBIhdmm4bhYsVA6G2WgNF # YagLDBzpmk9104WQzYuVNsxyoVLObhx3RugaEGru+SojW4dHPoWrUhftNpFC5H7Q # EY7MhKRyrBe7ucykW7eaCuWBsBb4HOKRFVDcrZgdwaSIqMDiCLg4D+TPVgKx2EgE # deoHNHT9l3ZDBD+XgbF+23/zBjeCtxz+dL/9NWR6P2eZRi7zcEO1xwcdcqJsyz/J # ceENc2Sg8h3KeFUCS7tpFk7CrDqkMIIHXzCCBUegAwIBAgIQB8JSdCgUotar/iTq # F+XdLjANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBT # aWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTIzMDQxNjAwMDAwMFoX # DTI2MDcwNjIzNTk1OVowZzELMAkGA1UEBhMCUEwxEjAQBgNVBAcMCU1pa2/FgsOz # dzEhMB8GA1UECgwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMSEwHwYDVQQDDBhQ # cnplbXlzxYJhdyBLxYJ5cyBFVk9URUMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw # ggIKAoICAQCUmgeXMQtIaKaSkKvbAt8GFZJ1ywOH8SwxlTus4McyrWmVOrRBVRQA # 8ApF9FaeobwmkZxvkxQTFLHKm+8knwomEUslca8CqSOI0YwELv5EwTVEh0C/Daeh # vxo6tkmNPF9/SP1KC3c0l1vO+M7vdNVGKQIQrhxq7EG0iezBZOAiukNdGVXRYOLn # 47V3qL5PwG/ou2alJ/vifIDad81qFb+QkUh02Jo24SMjWdKDytdrMXi0235CN4Rr # W+8gjfRJ+fKKjgMImbuceCsi9Iv1a66bUc9anAemObT4mF5U/yQBgAuAo3+jVB8w # iUd87kUQO0zJCF8vq2YrVOz8OJmMX8ggIsEEUZ3CZKD0hVc3dm7cWSAw8/FNzGNP # lAaIxzXX9qeD0EgaCLRkItA3t3eQW+IAXyS/9ZnnpFUoDvQGbK+Q4/bP0ib98XLf # QpxVGRu0cCV0Ng77DIkRF+IyR1PcwVAq+OzVU3vKeo25v/rntiXCmCxiW4oHYO28 # eSQ/eIAcnii+3uKDNZrI15P7VxDrkUIc6FtiSvOhwc3AzY+vEfivUkFKRqwvSSr4 # fCrrkk7z2Qe72Zwlw2EDRVHyy0fUVGO9QMuh6E3RwnJL96ip0alcmhKABGoIqSW0 # 5nXdCUbkXmhPCTT5naQDuZ1UkAXbZPShKjbPwzdXP2b8I9nQ89VSgQIDAQABo4IC # AzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYE # FHrxaiVZuDJxxEk15bLoMuFI5233MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK # BggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEz # ODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5j # cmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3 # dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmlu # Z1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEB # CwUAA4ICAQC3EeHXUPhpe31K2DL43Hfh6qkvBHyR1RlD9lVIklcRCR50ZHzoWs6E # BlTFyohvkpclVCuRdQW33tS6vtKPOucpDDv4wsA+6zkJYI8fHouW6Tqa1W47YSrc # 5AOShIcJ9+NpNbKNGih3doSlcio2mUKCX5I/ZrzJBkQpJ0kYha/pUST2CbE3JroJ # f2vQWGUiI+J3LdiPNHmhO1l+zaQkSxv0cVDETMfQGZKKRVESZ6Fg61b0djvQSx51 # 0MdbxtKMjvS3ZtAytqnQHk1ipP+Rg+M5lFHrSkUlnpGa+f3nuQhxDb7N9E8hUVev # xALTrFifg8zhslVRH5/Df/CxlMKXC7op30/AyQsOQxHW1uNx3tG1DMgizpwBasrx # h6wa7iaA+Lp07q1I92eLhrYbtw3xC2vNIGdMdN7nd76yMIjdYnAn7r38wwtaJ3KY # D0QTl77EB8u/5cCs3ShZdDdyg4K7NoJl8iEHrbqtooAHOMLiJpiL2i9Yn8kQMB6/ # Q6RMO3IUPLuycB9o6DNiwQHf6Jt5oW7P09k5NxxBEmksxwNbmZvNQ65Zn3exUAKq # G+x31Egz5IZ4U/jPzRalElEIpS0rgrVg8R8pEOhd95mEzp5WERKFyXhe6nB6bSYH # v8clLAV0iMku308rpfjMiQkqS3LLzfUJ5OHqtKKQNMLxz9z185UCszGCBlMwggZP # AgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw # PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2 # IFNIQTM4NCAyMDIxIENBMQIQB8JSdCgUotar/iTqF+XdLjANBglghkgBZQMEAgEF # AKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgor # BgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3 # DQEJBDEiBCAg/q14L0ykB1QiC8TniJV4zfuhMrRQbtL4uy4oGLWSlDANBgkqhkiG # 9w0BAQEFAASCAgABSsKP7p64HPv7A/F0h1ejElT4/Lk+frdqcbM/kwN5kMYGv2hh # L1bHEW11dR5/hP53ykorFofM2DbFATzMnM0Z5+BcIXFrgK1tBPxvtfLKxDVXlOXO # hHvvlzpKEGckTAWoTPBuqS9UxprCU4PXMzCurXBdjGX03hOy3Dz39Gys+FiZwDBW # IPNKrCXDUPsGwCQK9oDz2bgsjYpQ42SNZ37/FMh5O9jTIcWfbOvfEqrp8Oo+Az1m # 8+6FuVScjb3+Aynf8bz0rnYp0M3G39FhuCqIdXDBWxB9UlSFX0MYCcvgABqLmtB1 # RC0tWt6VkmiVHK5EcYjxw7qTzN/RM0SWxynPB/cbQMeNDZ7dZUsE3NtZjoMxTMIQ # TUDZZf+QeyNCLT5SdeYiOgp43DCnDNPoaM5treW0hixMWYY3g7oVAEeHUIwRE5oP # zfKNqyj00vodwHDUvnBizCmqCqA8hLNSCzPFjeTQ4om9PG/O4M0GQtCxJmbpNkwZ # FeSH+7x/autZc6NN6zHiHeUaXw4uqtJKJpOmukVb/rmI07uWNrHmlu1hPp8/wEcu # IdskWzlFv1Q2//ASpyo+UWZfXsr3ZnjE4NAEd0Om87Is3mfWqi3NXw+hxeTs66uo # ojDNfehXSf84dybYgmEckpgr5wAi626NDkJymbvuawv8VdlACDvkjpNE4qGCAyAw # ggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYD # VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBH # NCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAuuZrxaun+Vh8b56QTj # MwQwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG # CSqGSIb3DQEJBTEPFw0yNDEwMDkxMDQwNDVaMC8GCSqGSIb3DQEJBDEiBCA6E6Uk # R9r2/9cz6b0/lkpDDlbbS0QXt6IKlk6oFs6QcDANBgkqhkiG9w0BAQEFAASCAgBm # nPdiLZw6mifir4EvQS+icPSXDr5Iws3tPlUmNTYLyT4SC1KjRzixgmxAeRS2Gone # lhFwWC8wwn+EGc9LrEABxe9Mqrx+j65QTy5y3yMoZ8uBl/3b4d1kZXbv5pnk47Fv # +GuJYJIwVuX0KFFH7A7GLaBAsmLce1Bet55DCKAApE9Sh8k6PlXQHMptGINHRz0s # orlt0wVqYQ3Fn02wrThRyad3Z/ZTBbeq+vmjTEoRMtmHaLcAMocUewF0BRIpV1Xn # Boab99Xd1berIEIaKjB6XPjnz7GOM9PvetW2XufVB3IsKRnVXh+cV1QRnNmZbb0v # hmSdGdhSz5d3vtXUnWo5sGXR/x2VnnA7iyNOktT5YrWswHUS1qVAN37P89t4DMx/ # B+/pqj5E8jjjSGovdNPpt2OsHYnN5HjtPp2THygJd6n5w+UUIFKUD5/EgmSMDTX6 # HYmSF5c6mQcXQY3+weyXPEAkE8esdWR/8gGg1rsf2UZFQbhcB/2fr+diplFLsiVM # kD/IURoiOcEB+XMY5fD7G2nioGRggMywd/+BCILpzQ3lgC69EBnrV/PdyJdOV8HG # 0fNHKOoWkJJh0pJJSF7McDdMYVyViujfIWo1GtRzU2VJs+uBWsXAR65QVKdiiivc # AN0VQr7jtcUYQ9RP2gShOj5BeJAwWZ8fTHWGV0ElXQ== # SIG # End signature block |