diff --git a/Functions/Circuits/Circuits.ps1 b/Functions/Circuits/Circuits.ps1 new file mode 100644 index 0000000..2235cc3 --- /dev/null +++ b/Functions/Circuits/Circuits.ps1 @@ -0,0 +1,106 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 4:06 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Circuits.ps1 + =========================================================================== + .DESCRIPTION + Circuit object functions +#> + +function Get-NetboxCircuitsChoices { +<# + .SYNOPSIS + Gets the choices associated with circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuitsChoices function. + + .EXAMPLE + PS C:\> Get-NetboxCircuitsChoices + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('circuits', '_choices')) + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri +} + +function Get-NetboxCircuit { +<# + .SYNOPSIS + Gets one or more circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuit function. + + .PARAMETER CID + Circuit ID + + .PARAMETER InstallDate + Date of installation + + .PARAMETER CommitRate + Committed rate in Kbps + + .PARAMETER Query + A raw search query... As if you were searching the web site + + .PARAMETER Provider + The name or ID of the provider. Provide either [string] or [int]. String will search provider names, integer will search database IDs + + .PARAMETER Type + Type of circuit. Provide either [string] or [int]. String will search provider type names, integer will search database IDs + + .PARAMETER Site + Location/site of circuit. Provide either [string] or [int]. String will search site names, integer will search database IDs + + .PARAMETER Tenant + Tenant assigned to circuit. Provide either [string] or [int]. String will search tenant names, integer will search database IDs + + .PARAMETER Id + Database ID of circuit. This will query for exactly the IDs provided + + .PARAMETER ID__IN + Multiple unique DB IDs to retrieve + + .EXAMPLE + PS C:\> Get-NetboxCircuit + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [string]$CID, + + [datetime]$InstallDate, + + [uint32]$CommitRate, + + [string]$Query, + + [object]$Provider, + + [object]$Type, + + [string]$Site, + + [string]$Tenant, + + [uint16[]]$Id + ) + + #TODO: Place script here +} diff --git a/Functions/Extras/Extras.ps1 b/Functions/Extras/Extras.ps1 new file mode 100644 index 0000000..ecf8b30 --- /dev/null +++ b/Functions/Extras/Extras.ps1 @@ -0,0 +1,23 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:43 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Extras.ps1 + =========================================================================== + .DESCRIPTION + Extras objects functions +#> + +function Get-NetboxExtrasChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri +} diff --git a/Functions/Helpers.ps1 b/Functions/Helpers.ps1 new file mode 100644 index 0000000..cb95ebf --- /dev/null +++ b/Functions/Helpers.ps1 @@ -0,0 +1,256 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.ps1 + =========================================================================== + .DESCRIPTION + These function are internal functions and generally are not + exposed to the end user +#> + +function CheckNetboxIsConnected { + [CmdletBinding()] + param () + + Write-Verbose "Checking connection status" + if (-not $script:NetboxConfig.Connected) { + throw "Not connected to a Netbox API! Please run 'Connect-NetboxAPI'" + } +} + +function BuildNewURI { +<# + .SYNOPSIS + Create a new URI for Netbox + + .DESCRIPTION + A detailed description of the BuildNewURI function. + + .PARAMETER Hostname + Hostname of the Netbox API + + .PARAMETER Segments + Array of strings for each segment in the URL path + + .PARAMETER Parameters + Hashtable of query parameters to include + + .PARAMETER HTTPS + Whether to use HTTPS or HTTP + + .PARAMETER Port + A description of the Port parameter. + + .PARAMETER APIInfo + A description of the APIInfo parameter. + + .EXAMPLE + PS C:\> BuildNewURI + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + [OutputType([System.UriBuilder])] + param + ( + [Parameter(Mandatory = $false)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [string[]]$Segments, + + [Parameter(Mandatory = $false)] + [hashtable]$Parameters, + + [Parameter(Mandatory = $false)] + [boolean]$HTTPS = $true, + + [ValidateRange(1, 65535)] + [uint16]$Port = 443, + + [switch]$SkipConnectedCheck + ) + + Write-Verbose "Building URI" + + if (-not $SkipConnectedCheck) { + # There is no point in continuing if we have not successfully connected to an API + $null = CheckNetboxIsConnected + } + + if (-not $Hostname) { + $Hostname = Get-NetboxHostname + } + + if ($HTTPS) { + Write-Verbose "Setting scheme to HTTPS" + $Scheme = 'https' + } else { + Write-Warning "Connecting via non-secure HTTP is not-recommended" + + Write-Verbose "Setting scheme to HTTP" + $Scheme = 'http' + + if (-not $PSBoundParameters.ContainsKey('Port')) { + # Set the port to 80 if the user did not supply it + Write-Verbose "Setting port to 80 as default because it was not supplied by the user" + $Port = 80 + } + } + + # Begin a URI builder with HTTP/HTTPS and the provided hostname + $uriBuilder = [System.UriBuilder]::new($Scheme, $Hostname, $Port) + + # Generate the path by trimming excess slashes and whitespace from the $segments[] and joining together + $uriBuilder.Path = "api/{0}/" -f ($Segments.ForEach({$_.trim('/').trim()}) -join '/') + + Write-Verbose "URIPath: $($uriBuilder.Path)" + + if ($parameters) { + # Loop through the parameters and use the HttpUtility to create a Query string + [System.Collections.Specialized.NameValueCollection]$URIParams = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + + foreach ($param in $Parameters.GetEnumerator()) { + Write-Verbose "Adding URI parameter $($param.Key):$($param.Value)" + $URIParams[$param.Key] = $param.Value + } + + $uriBuilder.Query = $URIParams.ToString() + } + + Write-Verbose "Completed building URIBuilder" + # Return the entire UriBuilder object + $uriBuilder +} + +function GetNetboxAPIErrorBody { + param + ( + [Parameter(Mandatory = $true)] + [System.Net.HttpWebResponse]$Response + ) + + # This takes the $Response stream and turns it into a useable object... generally a string. + # If the body is JSON, you should be able to use ConvertFrom-Json + + $reader = New-Object System.IO.StreamReader($Response.GetResponseStream()) + $reader.BaseStream.Position = 0 + $reader.DiscardBufferedData() + $reader.ReadToEnd() +} + +function InvokeNetboxRequest { + [CmdletBinding(SupportsShouldProcess = $true)] + param + ( + [Parameter(Mandatory = $true)] + [System.UriBuilder]$URI, + + [Hashtable]$Headers = @{}, + + [pscustomobject]$Body = $null, + + [ValidateRange(0, 60)] + [uint16]$Timeout = 5, + + [ValidateSet('GET', 'PATCH', 'PUT', 'POST', 'DELETE', IgnoreCase = $true)] + [string]$Method = 'GET', + + [switch]$Raw + ) + + $creds = Get-NetboxCredentials + + $Headers.Authorization = "Token {0}" -f $creds.GetNetworkCredential().Password + + $splat = @{ + 'Method' = $Method + 'Uri' = $URI.Uri.AbsoluteUri # This property auto generates the scheme, hostname, path, and query + 'Headers' = $Headers + 'TimeoutSec' = $Timeout + 'ContentType' = 'application/json' + 'ErrorAction' = 'Stop' + 'Verbose' = $VerbosePreference + } + + if ($Body) { + Write-Verbose "BODY: $($Body | ConvertTo-Json -Compress)" + $null = $splat.Add('Body', ($Body | ConvertTo-Json -Compress)) + } + + $result = Invoke-RestMethod @splat + + #region TODO: Handle errors a little more gracefully... + + <# + try { + Write-Verbose "Sending request..." + $result = Invoke-RestMethod @splat + Write-Verbose $result + } catch { + Write-Verbose "Caught exception" + if ($_.Exception.psobject.properties.Name.contains('Response')) { + Write-Verbose "Exception contains a response property" + if ($Raw) { + Write-Verbose "RAW provided...throwing raw exception" + throw $_ + } + + Write-Verbose "Converting response to object" + $myError = GetNetboxAPIErrorBody -Response $_.Exception.Response | ConvertFrom-Json + } else { + Write-Verbose "No response property found" + $myError = $_ + } + } + + Write-Verbose "MyError is $($myError.GetType().FullName)" + + if ($myError -is [Exception]) { + throw $_ + } elseif ($myError -is [pscustomobject]) { + throw $myError.detail + } + #> + + #endregion TODO: Handle errors a little more gracefully... + + # If the user wants the raw value from the API... otherwise return only the actual result + if ($Raw) { + Write-Verbose "Returning raw result" + return $result + } else { + if ($result.psobject.Properties.Name.Contains('results')) { + Write-Verbose "Found Results property on data, returning results directly" + return $result.Results + } else { + Write-Verbose "Did NOT find results property on data, returning raw result" + return $result + } + } +} + +function ThrowNetboxRESTError { + $uriSegments = [System.Collections.ArrayList]::new(@('fake', 'url')) + + $URIParameters = @{} + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw +} + + + + + + + + + diff --git a/Functions/IPAM/IPAM.ps1 b/Functions/IPAM/IPAM.ps1 new file mode 100644 index 0000000..34c354a --- /dev/null +++ b/Functions/IPAM/IPAM.ps1 @@ -0,0 +1,423 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.ps1 + =========================================================================== + .DESCRIPTION + IPAM Object functions +#> + +function Get-NetboxIPAMChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri +} + +function VerifyIPAMChoices { +<# + .SYNOPSIS + Internal function to verify provided values for static choices + + .DESCRIPTION + When users connect to the API, choices for each major object are cached to the config variable. + These values are then utilized to verify if the provided value from a user is valid. + + .PARAMETER ProvidedValue + The value to validate against static choices + + .PARAMETER AggregateFamily + Verify against aggregate family values + + .PARAMETER PrefixFamily + Verify against prefix family values + + .PARAMETER PrefixStatus + Verify against prefix status values + + .PARAMETER IPAddressFamily + Verify against ip-address family values + + .PARAMETER IPAddressStatus + Verify against ip-address status values + + .PARAMETER IPAddressRole + Verify against ip-address role values + + .PARAMETER VLANStatus + Verify against VLAN status values + + .PARAMETER ServiceProtocol + Verify against service protocol values + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'loopback' -IPAddressRole + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'Loopback' -IPAddressFamily + >> Invalid value Loopback for ip-address:family. Must be one of: 4, 6, IPv4, IPv6 + + .FUNCTIONALITY + This cmdlet is intended to be used internally and not exposed to the user + + .OUTPUT + This function returns nothing if the value is valid. Otherwise, it will throw an error. +#> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [object]$ProvidedValue, + + [Parameter(ParameterSetName = 'aggregate:family', + Mandatory = $true)] + [switch]$AggregateFamily, + + [Parameter(ParameterSetName = 'prefix:family', + Mandatory = $true)] + [switch]$PrefixFamily, + + [Parameter(ParameterSetName = 'prefix:status', + Mandatory = $true)] + [switch]$PrefixStatus, + + [Parameter(ParameterSetName = 'ip-address:family', + Mandatory = $true)] + [switch]$IPAddressFamily, + + [Parameter(ParameterSetName = 'ip-address:status', + Mandatory = $true)] + [switch]$IPAddressStatus, + + [Parameter(ParameterSetName = 'ip-address:role', + Mandatory = $true)] + [switch]$IPAddressRole, + + [Parameter(ParameterSetName = 'vlan:status', + Mandatory = $true)] + [switch]$VLANStatus, + + [Parameter(ParameterSetName = 'service:protocol', + Mandatory = $true)] + [switch]$ServiceProtocol + ) + + $ValidValues = New-Object System.Collections.ArrayList + + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).value) + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).label) + + if ($ValidValues.Count -eq 0) { + throw "Missing valid values for $($PSCmdlet.ParameterSetName)" + } + + if ($ValidValues -inotcontains $ProvidedValue) { + throw "Invalid value '$ProvidedValue' for '$($PSCmdlet.ParameterSetName)'. Must be one of: $($ValidValues -join ', ')" + } + + # Convert the ProvidedValue to the integer value + try { + $intVal = [uint16]"$ProvidedValue" + } catch { + # It must not be a number, get the value from the label + $intVal = [uint16]$script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).Where({$_.Label -eq $ProvidedValue}).Value + } + + return $intVal +} + + +function Get-NetboxIPAMAggregate { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Family, + + [datetime]$Date_Added, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$RIR_Id, + + [string]$RIR, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'aggregates')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxIPAMAddress { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$Parent, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Device, + + [uint16]$Device_ID, + + [string]$Virtual_Machine, + + [uint16]$Virtual_Machine_Id, + + [uint16]$Interface_Id, + + [object]$Status, + + [object]$Role, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -IPAddressFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -IPAddressStatus + } + + if ($Role) { + $PSBoundParameters.Role = VerifyIPAMChoices -ProvidedValue $Role -IPAddressRole + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'ip-addresses')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxIPAMAvaiableIP { +<# + .SYNOPSIS + A convenience method for returning available IP addresses within a prefix + + .DESCRIPTION + By default, the number of IPs returned will be equivalent to PAGINATE_COUNT. An arbitrary limit + (up to MAX_PAGE_SIZE, if set) may be passed, however results will not be paginated + + .PARAMETER Prefix_ID + A description of the Prefix_ID parameter. + + .PARAMETER NumberOfIPs + A description of the NumberOfIPs parameter. + + .EXAMPLE + PS C:\> Get-NetboxIPAMAvaiableIP -Prefix_ID $value1 + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [uint16]$Prefix_ID, + + [uint16]$NumberOfIPs, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes', $Prefix_ID, 'available-ips')) + + $uriParameters = @{} + + if ($NumberOfIPs) { + [void]$uriParameters.Add('limit', $NumberOfIPs) + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $uriParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxIPAMPrefix { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + #[string]$Within, + + #[string]$Within_Include, + + [string]$Contains, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Vlan_VId, + + [uint16]$Vlan_Id, + + [object]$Status, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -PrefixFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -PrefixStatus + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + + + + + + + + + + + + + + + + + diff --git a/Functions/Setup.ps1 b/Functions/Setup.ps1 new file mode 100644 index 0000000..1701844 --- /dev/null +++ b/Functions/Setup.ps1 @@ -0,0 +1,204 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Setup.ps1 + =========================================================================== + .DESCRIPTION + These are the function used to setup the environment for connecting + to a Netbox API +#> + +function SetupNetboxConfigVariable { + [CmdletBinding()] + param + ( + [switch]$Overwrite + ) + + Write-Verbose "Checking for NetboxConfig hashtable" + if ((-not ($script:NetboxConfig)) -or $Overwrite) { + Write-Verbose "Creating NetboxConfig hashtable" + $script:NetboxConfig = @{ + 'Connected' = $false + 'Choices' = @{ + 'Circuits' = $null + 'DCIM' = $null + 'Extras' = $null + 'IPAM' = $null + 'Secrets' = $null + 'Tenancy' = $null + 'Virtualization' = $null + } + } + } + + Write-Verbose "NetboxConfig hashtable already exists" +} + +function GetNetboxConfigVariable { + return $script:NetboxConfig +} + +function Set-NetboxHostName { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname + ) + + $script:NetboxConfig.Hostname = $Hostname.Trim() + $script:NetboxConfig.Hostname +} + +function Get-NetboxHostname { + [CmdletBinding()] + param () + + Write-Verbose "Getting Netbox hostname" + if ($script:NetboxConfig.Hostname -eq $null) { + throw "Netbox Hostname is not set! You may set it with Set-NetboxHostname -Hostname 'hostname.domain.tld'" + } + + $script:NetboxConfig.Hostname +} + +function Set-NetboxCredentials { + [CmdletBinding(DefaultParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'UserPass')] + param + ( + [Parameter(ParameterSetName = 'CredsObject', + Mandatory = $true)] + [pscredential]$Credentials, + + [Parameter(ParameterSetName = 'UserPass', + Mandatory = $true)] + [string]$Token + ) + + switch ($PsCmdlet.ParameterSetName) { + 'CredsObject' { + $script:NetboxConfig.Credentials = $Credentials + break + } + + 'UserPass' { + $securePW = ConvertTo-SecureString $Token -AsPlainText -Force + $script:NetboxConfig.Credentials = [System.Management.Automation.PSCredential]::new('notapplicable', $securePW) + break + } + } + + $script:NetboxConfig.Credentials +} + +function Get-NetboxCredentials { + [CmdletBinding()] + [OutputType([pscredential])] + param () + + if (-not $script:NetboxConfig.Credentials) { + throw "Netbox Credentials not set! You may set with Set-NetboxCredentials" + } + + $script:NetboxConfig.Credentials +} + +function VerifyAPIConnectivity { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -SkipConnectedCheck + + InvokeNetboxRequest -URI $uri +} + +function Connect-NetboxAPI { +<# + .SYNOPSIS + Connects to the Netbox API and ensures credentials work properly + + .DESCRIPTION + A detailed description of the Connect-NetboxAPI function. + + .PARAMETER Hostname + A description of the Hostname parameter. + + .PARAMETER Credentials + A description of the Credentials parameter. + + .EXAMPLE + PS C:\> Connect-NetboxAPI -Hostname "netbox.domain.com" + + This will prompt for credentials, then proceed to attempt a connection to Netbox + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [pscredential]$Credentials + ) + + if (-not $Credentials) { + try { + $Credentials = Get-NetboxCredentials -ErrorAction Stop + } catch { + # Credentials are not set... Try to obtain from the user + if (-not ($Credentials = Get-Credential -UserName 'username-not-applicable' -Message "Enter token for Netbox")) { + throw "Token is necessary to connect to a Netbox API." + } + } + } + + $null = Set-NetboxHostName -Hostname $Hostname + $null = Set-NetboxCredentials -Credentials $Credentials + + try { + Write-Verbose "Verifying API connectivity..." + $APIInfo = VerifyAPIConnectivity + $script:NetboxConfig.Connected = $true + Write-Verbose "Successfully connected!" + } catch { + Write-Verbose "Failed to connect. Generating error" + Write-Verbose $_.Exception.Message + if (($_.Exception.Response) -and ($_.Exception.Response.StatusCode -eq 403)) { + throw "Invalid token" + } else { + throw $_ + } + } + + $script:NetboxConfig.Choices.Circuits = Get-NetboxCircuitsChoices + #$script:NetboxConfig.Choices.DCIM = Get-NetboxDCIMChoices + $script:NetboxConfig.Choices.Extras = Get-NetboxExtrasChoices + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + #$script:NetboxConfig.Choices.Secrets = Get-NetboxSecretsChoices + #$script:NetboxConfig.Choices.Tenancy = Get-NetboxTenancyChoices + $script:NetboxConfig.Choices.Virtualization = Get-NetboxVirtualizationChoices + +} + + + + + + + + + + diff --git a/Functions/Virtualization/Virtualization.ps1 b/Functions/Virtualization/Virtualization.ps1 new file mode 100644 index 0000000..c306285 --- /dev/null +++ b/Functions/Virtualization/Virtualization.ps1 @@ -0,0 +1,552 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 3:59 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.ps1 + =========================================================================== + .DESCRIPTION + Virtualization object functions +#> + +#region GET commands + +function Get-NetboxVirtualizationChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri +} + +function Get-NetboxVirtualMachine { +<# + .SYNOPSIS + Obtains virtual machines from Netbox. + + .DESCRIPTION + Obtains one or more virtual machines based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a VM + + .PARAMETER Name + Name of the VM + + .PARAMETER Id + Database ID of the VM + + .PARAMETER Status + Status of the VM + + .PARAMETER Tenant + String value of tenant + + .PARAMETER Tenant_ID + Database ID of the tenant. + + .PARAMETER Platform + String value of the platform + + .PARAMETER Platform_ID + Database ID of the platform + + .PARAMETER Cluster_Group + String value of the cluster group. + + .PARAMETER Cluster_Group_Id + Database ID of the cluster group. + + .PARAMETER Cluster_Type + String value of the Cluster type. + + .PARAMETER Cluster_Type_Id + Database ID of the cluster type. + + .PARAMETER Cluster_Id + Database ID of the cluster. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Role + String value of the role. + + .PARAMETER Role_Id + Database ID of the role. + + .PARAMETER Raw + A description of the Raw parameter. + + .PARAMETER TenantID + Database ID of tenant + + .PARAMETER PlatformID + Database ID of the platform + + .PARAMETER id__in + Database IDs of VMs + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachine + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [NetboxVirtualMachineStatus]$Status, + + [string]$Tenant, + + [uint16]$Tenant_ID, + + [string]$Platform, + + [uint16]$Platform_ID, + + [string]$Cluster_Group, + + [uint16]$Cluster_Group_Id, + + [string]$Cluster_Type, + + [uint16]$Cluster_Type_Id, + + [uint16]$Cluster_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } elseif ($CmdletParameterName -eq 'Status') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxVirtualMachineInterface { +<# + .SYNOPSIS + Gets VM interfaces + + .DESCRIPTION + Obtains the interface objects for one or more VMs + + .PARAMETER Limit + Number of results to return per page. + + .PARAMETER Offset + The initial index from which to return the results. + + .PARAMETER Id + Database ID of the interface + + .PARAMETER Name + Name of the interface + + .PARAMETER Enabled + True/False if the interface is enabled + + .PARAMETER MTU + Maximum Transmission Unit size. Generally 1500 or 9000 + + .PARAMETER Virtual_Machine_Id + ID of the virtual machine to which the interface(s) are assigned. + + .PARAMETER Virtual_Machine + Name of the virtual machine to get interfaces + + .PARAMETER MAC_Address + MAC address assigned to the interface + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachineInterface + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Limit, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Offset, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Name, + + [Parameter(ValueFromPipeline = $true)] + [boolean]$Enabled, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$MTU, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Virtual_Machine_Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Virtual_Machine, + + [Parameter(ValueFromPipeline = $true)] + [string]$MAC_Address, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } elseif ($CmdletParameterName -eq 'Enabled') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].ToString().ToLower() + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxVirtualizationCluster { +<# + .SYNOPSIS + Obtains virtualization clusters from Netbox. + + .DESCRIPTION + Obtains one or more virtualization clusters based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a cluster + + .PARAMETER Name + Name of the cluster + + .PARAMETER Id + Database ID(s) of the cluster + + .PARAMETER Group + String value of the cluster group. + + .PARAMETER Group_Id + Database ID of the cluster group. + + .PARAMETER Type + String value of the Cluster type. + + .PARAMETER Type_Id + Database ID of the cluster type. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualizationCluster + + .NOTES + Additional information about the function. +#> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [string]$Group, + + [uint16]$Group_Id, + + [string]$Type, + + [uint16]$Type_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'clusters')) + + $URIParameters = @{ + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +function Get-NetboxVirtualizationClusterGroup { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Name, + + [string]$Slug, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'cluster-groups')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw +} + +#endregion GET commands + + +#region ADD commands + +function Add-NetboxVirtualMachine { + [CmdletBinding()] + [OutputType([pscustomobject])] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Cluster, + + [uint16]$Tenant, + + [NetboxVirtualMachineStatus]$Status = 'Active', + + [uint16]$Role, + + [uint16]$Platform, + + [uint16]$vCPUs, + + [uint16]$Memory, + + [uint16]$Disk, + + [hashtable]$Custom_Fields, + + [string]$Comments + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Status')) { + [void]$PSBoundParameters.Add('Status', $Status) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Status') { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body +} + +function Add-NetboxVirtualInterface { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Virtual_Machine, + + [boolean]$Enabled = $true, + + [string]$MAC_Address, + + [uint16]$MTU, + + [string]$Description, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Enabled')) { + [void]$PSBoundParameters.Add('enabled', $Enabled) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body +} + + + +#endregion ADD commands + + diff --git a/NetboxPS.psd1 b/NetboxPS.psd1 new file mode 100644 index 0000000..580df7b --- /dev/null +++ b/NetboxPS.psd1 @@ -0,0 +1,127 @@ +<# + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 11:04 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: NetboxPS.psd1 + ------------------------------------------------------------------------- + Module Manifest + ------------------------------------------------------------------------- + Module Name: NetboxPS + =========================================================================== +#> + + +@{ + + # Script module or binary module file associated with this manifest + ModuleToProcess = 'NetboxPS.psm1' + + # Version number of this module. + ModuleVersion = '1.0.0.0' + + # ID used to uniquely identify this module + GUID = 'bba9b06c-49c8-47cf-8358-aca7c4e78896' + + # Author of this module + Author = ' Ben Claussen' + + # Company or vendor of this module + CompanyName = 'NEOnet' + + # Copyright statement for this module + Copyright = '(c) 2018. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'Module description' + + # Minimum version of the Windows PowerShell engine required by this module + PowerShellVersion = '2.0' + + # Name of the Windows PowerShell host required by this module + PowerShellHostName = '' + + # Minimum version of the Windows PowerShell host required by this module + PowerShellHostVersion = '' + + # Minimum version of the .NET Framework required by this module + DotNetFrameworkVersion = '2.0' + + # Minimum version of the common language runtime (CLR) required by this module + CLRVersion = '2.0.50727' + + # Processor architecture (None, X86, Amd64, IA64) required by this module + ProcessorArchitecture = 'None' + + # Modules that must be imported into the global environment prior to importing + # this module + RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + RequiredAssemblies = @('System.Web') + + # Script files (.ps1) that are run in the caller's environment prior to + # importing this module + ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in + # ModuleToProcess + NestedModules = @() + + # Functions to export from this module + FunctionsToExport = '*' #For performanace, list functions explicity + + # Cmdlets to export from this module + CmdletsToExport = '*' + + # Variables to export from this module + VariablesToExport = '*' + + # Aliases to export from this module + AliasesToExport = '*' #For performanace, list alias explicity + + # List of all modules packaged with this module + ModuleList = @() + + # List of all files packaged with this module + FileList = @() + + # Private data to pass to the module specified in ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + #Support for PowerShellGet galleries. + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + + } # End of PrivateData hashtable +} + + + + + + + diff --git a/NetboxPS.psm1 b/NetboxPS.psm1 new file mode 100644 index 0000000..2c338e4 --- /dev/null +++ b/NetboxPS.psm1 @@ -0,0 +1,22 @@ +# Build a list of common paramters so we can omit them to build URI parameters +$script:CommonParameterNames = New-Object System.Collections.ArrayList +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::CommonParameters)) +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)) +[void]$script:CommonParameterNames.Add('Raw') + +SetupNetboxConfigVariable + +if (-not ([System.Management.Automation.PSTypeName]'NetboxVirtualMachineStatus').Type) { + Add-Type -TypeDefinition @" +public enum NetboxVirtualMachineStatus +{ + Offline = 0, + Active = 1, + Staged = 3 +} +"@ +} + + +Export-ModuleMember -Function * +#Export-ModuleMember -Function *-* \ No newline at end of file diff --git a/NetboxPS.psproj b/NetboxPS.psproj new file mode 100644 index 0000000..ee2d4b8 --- /dev/null +++ b/NetboxPS.psproj @@ -0,0 +1,31 @@ + + 2.0 + bba9b06c-49c8-47cf-8358-aca7c4e78896 + 1 + + Functions + Functions\DCIM + Functions\Extras + Functions\Circuits + Tests + Functions\Virtualization + Functions\IPAM + + + NetboxPS.psd1 + NetboxPS.psm1 + Test-Module.ps1 + .gitignore + Functions\Helpers.ps1 + Functions\Setup.ps1 + Functions\Extras\Extras.ps1 + Functions\Circuits\Circuits.ps1 + Tests\Setup.Tests.ps1 + Tests\Helpers.Tests.ps1 + Functions\Virtualization\Virtualization.ps1 + Tests\Virtualization.Tests.ps1 + Tests\IPAM.Tests.ps1 + Functions\IPAM\IPAM.ps1 + + R:\Netbox\NetboxPS\Test-Module.ps1 + \ No newline at end of file diff --git a/Staging/NetboxPS.psd1 b/Staging/NetboxPS.psd1 new file mode 100644 index 0000000..580df7b --- /dev/null +++ b/Staging/NetboxPS.psd1 @@ -0,0 +1,127 @@ +<# + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 11:04 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: NetboxPS.psd1 + ------------------------------------------------------------------------- + Module Manifest + ------------------------------------------------------------------------- + Module Name: NetboxPS + =========================================================================== +#> + + +@{ + + # Script module or binary module file associated with this manifest + ModuleToProcess = 'NetboxPS.psm1' + + # Version number of this module. + ModuleVersion = '1.0.0.0' + + # ID used to uniquely identify this module + GUID = 'bba9b06c-49c8-47cf-8358-aca7c4e78896' + + # Author of this module + Author = ' Ben Claussen' + + # Company or vendor of this module + CompanyName = 'NEOnet' + + # Copyright statement for this module + Copyright = '(c) 2018. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'Module description' + + # Minimum version of the Windows PowerShell engine required by this module + PowerShellVersion = '2.0' + + # Name of the Windows PowerShell host required by this module + PowerShellHostName = '' + + # Minimum version of the Windows PowerShell host required by this module + PowerShellHostVersion = '' + + # Minimum version of the .NET Framework required by this module + DotNetFrameworkVersion = '2.0' + + # Minimum version of the common language runtime (CLR) required by this module + CLRVersion = '2.0.50727' + + # Processor architecture (None, X86, Amd64, IA64) required by this module + ProcessorArchitecture = 'None' + + # Modules that must be imported into the global environment prior to importing + # this module + RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + RequiredAssemblies = @('System.Web') + + # Script files (.ps1) that are run in the caller's environment prior to + # importing this module + ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in + # ModuleToProcess + NestedModules = @() + + # Functions to export from this module + FunctionsToExport = '*' #For performanace, list functions explicity + + # Cmdlets to export from this module + CmdletsToExport = '*' + + # Variables to export from this module + VariablesToExport = '*' + + # Aliases to export from this module + AliasesToExport = '*' #For performanace, list alias explicity + + # List of all modules packaged with this module + ModuleList = @() + + # List of all files packaged with this module + FileList = @() + + # Private data to pass to the module specified in ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + #Support for PowerShellGet galleries. + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + + } # End of PrivateData hashtable +} + + + + + + + diff --git a/Staging/NetboxPS.psm1 b/Staging/NetboxPS.psm1 new file mode 100644 index 0000000..2787b1c --- /dev/null +++ b/Staging/NetboxPS.psm1 @@ -0,0 +1,1618 @@ +<# + .NOTES + -------------------------------------------------------------------------------- + Code generated by: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Generated on: 5/11/2018 3:48 PM + Generated by: Ben Claussen + Organization: NEOnet + -------------------------------------------------------------------------------- + .DESCRIPTION + Script generated by PowerShell Studio 2018 +#> + + +#region Invoke-Helpers_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.ps1 + =========================================================================== + .DESCRIPTION + These function are internal functions and generally are not + exposed to the end user + #> + + function CheckNetboxIsConnected { + [CmdletBinding()] + param () + + Write-Verbose "Checking connection status" + if (-not $script:NetboxConfig.Connected) { + throw "Not connected to a Netbox API! Please run 'Connect-NetboxAPI'" + } + } + + function BuildNewURI { + <# + .SYNOPSIS + Create a new URI for Netbox + + .DESCRIPTION + A detailed description of the BuildNewURI function. + + .PARAMETER Hostname + Hostname of the Netbox API + + .PARAMETER Segments + Array of strings for each segment in the URL path + + .PARAMETER Parameters + Hashtable of query parameters to include + + .PARAMETER HTTPS + Whether to use HTTPS or HTTP + + .PARAMETER Port + A description of the Port parameter. + + .PARAMETER APIInfo + A description of the APIInfo parameter. + + .EXAMPLE + PS C:\> BuildNewURI + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + [OutputType([System.UriBuilder])] + param + ( + [Parameter(Mandatory = $false)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [string[]]$Segments, + + [Parameter(Mandatory = $false)] + [hashtable]$Parameters, + + [Parameter(Mandatory = $false)] + [boolean]$HTTPS = $true, + + [ValidateRange(1, 65535)] + [uint16]$Port = 443, + + [switch]$SkipConnectedCheck + ) + + Write-Verbose "Building URI" + + if (-not $SkipConnectedCheck) { + # There is no point in continuing if we have not successfully connected to an API + $null = CheckNetboxIsConnected + } + + if (-not $Hostname) { + $Hostname = Get-NetboxHostname + } + + if ($HTTPS) { + Write-Verbose "Setting scheme to HTTPS" + $Scheme = 'https' + } else { + Write-Warning "Connecting via non-secure HTTP is not-recommended" + + Write-Verbose "Setting scheme to HTTP" + $Scheme = 'http' + + if (-not $PSBoundParameters.ContainsKey('Port')) { + # Set the port to 80 if the user did not supply it + Write-Verbose "Setting port to 80 as default because it was not supplied by the user" + $Port = 80 + } + } + + # Begin a URI builder with HTTP/HTTPS and the provided hostname + $uriBuilder = [System.UriBuilder]::new($Scheme, $Hostname, $Port) + + # Generate the path by trimming excess slashes and whitespace from the $segments[] and joining together + $uriBuilder.Path = "api/{0}/" -f ($Segments.ForEach({$_.trim('/').trim()}) -join '/') + + Write-Verbose "URIPath: $($uriBuilder.Path)" + + if ($parameters) { + # Loop through the parameters and use the HttpUtility to create a Query string + [System.Collections.Specialized.NameValueCollection]$URIParams = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + + foreach ($param in $Parameters.GetEnumerator()) { + Write-Verbose "Adding URI parameter $($param.Key):$($param.Value)" + $URIParams[$param.Key] = $param.Value + } + + $uriBuilder.Query = $URIParams.ToString() + } + + Write-Verbose "Completed building URIBuilder" + # Return the entire UriBuilder object + $uriBuilder + } + + function GetNetboxAPIErrorBody { + param + ( + [Parameter(Mandatory = $true)] + [System.Net.HttpWebResponse]$Response + ) + + # This takes the $Response stream and turns it into a useable object... generally a string. + # If the body is JSON, you should be able to use ConvertFrom-Json + + $reader = New-Object System.IO.StreamReader($Response.GetResponseStream()) + $reader.BaseStream.Position = 0 + $reader.DiscardBufferedData() + $reader.ReadToEnd() + } + + function InvokeNetboxRequest { + [CmdletBinding(SupportsShouldProcess = $true)] + param + ( + [Parameter(Mandatory = $true)] + [System.UriBuilder]$URI, + + [Hashtable]$Headers = @{}, + + [pscustomobject]$Body = $null, + + [ValidateRange(0, 60)] + [uint16]$Timeout = 5, + + [ValidateSet('GET', 'PATCH', 'PUT', 'POST', 'DELETE', IgnoreCase = $true)] + [string]$Method = 'GET', + + [switch]$Raw + ) + + $creds = Get-NetboxCredentials + + $Headers.Authorization = "Token {0}" -f $creds.GetNetworkCredential().Password + + $splat = @{ + 'Method' = $Method + 'Uri' = $URI.Uri.AbsoluteUri # This property auto generates the scheme, hostname, path, and query + 'Headers' = $Headers + 'TimeoutSec' = $Timeout + 'ContentType' = 'application/json' + 'ErrorAction' = 'Stop' + 'Verbose' = $VerbosePreference + } + + if ($Body) { + Write-Verbose "BODY: $($Body | ConvertTo-Json -Compress)" + $null = $splat.Add('Body', ($Body | ConvertTo-Json -Compress)) + } + + $result = Invoke-RestMethod @splat + + #region TODO: Handle errors a little more gracefully... + + <# + try { + Write-Verbose "Sending request..." + $result = Invoke-RestMethod @splat + Write-Verbose $result + } catch { + Write-Verbose "Caught exception" + if ($_.Exception.psobject.properties.Name.contains('Response')) { + Write-Verbose "Exception contains a response property" + if ($Raw) { + Write-Verbose "RAW provided...throwing raw exception" + throw $_ + } + + Write-Verbose "Converting response to object" + $myError = GetNetboxAPIErrorBody -Response $_.Exception.Response | ConvertFrom-Json + } else { + Write-Verbose "No response property found" + $myError = $_ + } + } + + Write-Verbose "MyError is $($myError.GetType().FullName)" + + if ($myError -is [Exception]) { + throw $_ + } elseif ($myError -is [pscustomobject]) { + throw $myError.detail + } + #> + + #endregion TODO: Handle errors a little more gracefully... + + # If the user wants the raw value from the API... otherwise return only the actual result + if ($Raw) { + Write-Verbose "Returning raw result" + return $result + } else { + if ($result.psobject.Properties.Name.Contains('results')) { + Write-Verbose "Found Results property on data, returning results directly" + return $result.Results + } else { + Write-Verbose "Did NOT find results property on data, returning raw result" + return $result + } + } + } + + function ThrowNetboxRESTError { + $uriSegments = [System.Collections.ArrayList]::new(@('fake', 'url')) + + $URIParameters = @{} + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw + } + + + + + + + + + + #endregion + +#region Invoke-Setup_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Setup.ps1 + =========================================================================== + .DESCRIPTION + These are the function used to setup the environment for connecting + to a Netbox API + #> + + function SetupNetboxConfigVariable { + [CmdletBinding()] + param + ( + [switch]$Overwrite + ) + + Write-Verbose "Checking for NetboxConfig hashtable" + if ((-not ($script:NetboxConfig)) -or $Overwrite) { + Write-Verbose "Creating NetboxConfig hashtable" + $script:NetboxConfig = @{ + 'Connected' = $false + 'Choices' = @{ + 'Circuits' = $null + 'DCIM' = $null + 'Extras' = $null + 'IPAM' = $null + 'Secrets' = $null + 'Tenancy' = $null + 'Virtualization' = $null + } + } + } + + Write-Verbose "NetboxConfig hashtable already exists" + } + + function GetNetboxConfigVariable { + return $script:NetboxConfig + } + + function Set-NetboxHostName { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname + ) + + $script:NetboxConfig.Hostname = $Hostname.Trim() + $script:NetboxConfig.Hostname + } + + function Get-NetboxHostname { + [CmdletBinding()] + param () + + Write-Verbose "Getting Netbox hostname" + if ($script:NetboxConfig.Hostname -eq $null) { + throw "Netbox Hostname is not set! You may set it with Set-NetboxHostname -Hostname 'hostname.domain.tld'" + } + + $script:NetboxConfig.Hostname + } + + function Set-NetboxCredentials { + [CmdletBinding(DefaultParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'UserPass')] + param + ( + [Parameter(ParameterSetName = 'CredsObject', + Mandatory = $true)] + [pscredential]$Credentials, + + [Parameter(ParameterSetName = 'UserPass', + Mandatory = $true)] + [string]$Token + ) + + switch ($PsCmdlet.ParameterSetName) { + 'CredsObject' { + $script:NetboxConfig.Credentials = $Credentials + break + } + + 'UserPass' { + $securePW = ConvertTo-SecureString $Token -AsPlainText -Force + $script:NetboxConfig.Credentials = [System.Management.Automation.PSCredential]::new('notapplicable', $securePW) + break + } + } + + $script:NetboxConfig.Credentials + } + + function Get-NetboxCredentials { + [CmdletBinding()] + [OutputType([pscredential])] + param () + + if (-not $script:NetboxConfig.Credentials) { + throw "Netbox Credentials not set! You may set with Set-NetboxCredentials" + } + + $script:NetboxConfig.Credentials + } + + function VerifyAPIConnectivity { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -SkipConnectedCheck + + InvokeNetboxRequest -URI $uri + } + + function Connect-NetboxAPI { + <# + .SYNOPSIS + Connects to the Netbox API and ensures credentials work properly + + .DESCRIPTION + A detailed description of the Connect-NetboxAPI function. + + .PARAMETER Hostname + A description of the Hostname parameter. + + .PARAMETER Credentials + A description of the Credentials parameter. + + .EXAMPLE + PS C:\> Connect-NetboxAPI -Hostname "netbox.domain.com" + + This will prompt for credentials, then proceed to attempt a connection to Netbox + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [pscredential]$Credentials + ) + + if (-not $Credentials) { + try { + $Credentials = Get-NetboxCredentials -ErrorAction Stop + } catch { + # Credentials are not set... Try to obtain from the user + if (-not ($Credentials = Get-Credential -UserName 'username-not-applicable' -Message "Enter token for Netbox")) { + throw "Token is necessary to connect to a Netbox API." + } + } + } + + $null = Set-NetboxHostName -Hostname $Hostname + $null = Set-NetboxCredentials -Credentials $Credentials + + try { + Write-Verbose "Verifying API connectivity..." + $APIInfo = VerifyAPIConnectivity + $script:NetboxConfig.Connected = $true + Write-Verbose "Successfully connected!" + } catch { + Write-Verbose "Failed to connect. Generating error" + Write-Verbose $_.Exception.Message + if (($_.Exception.Response) -and ($_.Exception.Response.StatusCode -eq 403)) { + throw "Invalid token" + } else { + throw $_ + } + } + + $script:NetboxConfig.Choices.Circuits = Get-NetboxCircuitsChoices + #$script:NetboxConfig.Choices.DCIM = Get-NetboxDCIMChoices + $script:NetboxConfig.Choices.Extras = Get-NetboxExtrasChoices + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + #$script:NetboxConfig.Choices.Secrets = Get-NetboxSecretsChoices + #$script:NetboxConfig.Choices.Tenancy = Get-NetboxTenancyChoices + $script:NetboxConfig.Choices.Virtualization = Get-NetboxVirtualizationChoices + + } + + + + + + + + + + + #endregion + +#region Invoke-Extras_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:43 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Extras.ps1 + =========================================================================== + .DESCRIPTION + Extras objects functions + #> + + function Get-NetboxExtrasChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri + } + #endregion + +#region Invoke-Circuits_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 4:06 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Circuits.ps1 + =========================================================================== + .DESCRIPTION + Circuit object functions + #> + + function Get-NetboxCircuitsChoices { + <# + .SYNOPSIS + Gets the choices associated with circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuitsChoices function. + + .EXAMPLE + PS C:\> Get-NetboxCircuitsChoices + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('circuits', '_choices')) + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri + } + + function Get-NetboxCircuit { + <# + .SYNOPSIS + Gets one or more circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuit function. + + .PARAMETER CID + Circuit ID + + .PARAMETER InstallDate + Date of installation + + .PARAMETER CommitRate + Committed rate in Kbps + + .PARAMETER Query + A raw search query... As if you were searching the web site + + .PARAMETER Provider + The name or ID of the provider. Provide either [string] or [int]. String will search provider names, integer will search database IDs + + .PARAMETER Type + Type of circuit. Provide either [string] or [int]. String will search provider type names, integer will search database IDs + + .PARAMETER Site + Location/site of circuit. Provide either [string] or [int]. String will search site names, integer will search database IDs + + .PARAMETER Tenant + Tenant assigned to circuit. Provide either [string] or [int]. String will search tenant names, integer will search database IDs + + .PARAMETER Id + Database ID of circuit. This will query for exactly the IDs provided + + .PARAMETER ID__IN + Multiple unique DB IDs to retrieve + + .EXAMPLE + PS C:\> Get-NetboxCircuit + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [string]$CID, + + [datetime]$InstallDate, + + [uint32]$CommitRate, + + [string]$Query, + + [object]$Provider, + + [object]$Type, + + [string]$Site, + + [string]$Tenant, + + [uint16[]]$Id + ) + + #TODO: Place script here + } + #endregion + +#region Invoke-Virtualization_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 3:59 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.ps1 + =========================================================================== + .DESCRIPTION + Virtualization object functions + #> + + #region GET commands + + function Get-NetboxVirtualizationChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri + } + + function Get-NetboxVirtualMachine { + <# + .SYNOPSIS + Obtains virtual machines from Netbox. + + .DESCRIPTION + Obtains one or more virtual machines based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a VM + + .PARAMETER Name + Name of the VM + + .PARAMETER Id + Database ID of the VM + + .PARAMETER Status + Status of the VM + + .PARAMETER Tenant + String value of tenant + + .PARAMETER Tenant_ID + Database ID of the tenant. + + .PARAMETER Platform + String value of the platform + + .PARAMETER Platform_ID + Database ID of the platform + + .PARAMETER Cluster_Group + String value of the cluster group. + + .PARAMETER Cluster_Group_Id + Database ID of the cluster group. + + .PARAMETER Cluster_Type + String value of the Cluster type. + + .PARAMETER Cluster_Type_Id + Database ID of the cluster type. + + .PARAMETER Cluster_Id + Database ID of the cluster. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Role + String value of the role. + + .PARAMETER Role_Id + Database ID of the role. + + .PARAMETER Raw + A description of the Raw parameter. + + .PARAMETER TenantID + Database ID of tenant + + .PARAMETER PlatformID + Database ID of the platform + + .PARAMETER id__in + Database IDs of VMs + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachine + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [NetboxVirtualMachineStatus]$Status, + + [string]$Tenant, + + [uint16]$Tenant_ID, + + [string]$Platform, + + [uint16]$Platform_ID, + + [string]$Cluster_Group, + + [uint16]$Cluster_Group_Id, + + [string]$Cluster_Type, + + [uint16]$Cluster_Type_Id, + + [uint16]$Cluster_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } elseif ($CmdletParameterName -eq 'Status') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualMachineInterface { + <# + .SYNOPSIS + Gets VM interfaces + + .DESCRIPTION + Obtains the interface objects for one or more VMs + + .PARAMETER Limit + Number of results to return per page. + + .PARAMETER Offset + The initial index from which to return the results. + + .PARAMETER Id + Database ID of the interface + + .PARAMETER Name + Name of the interface + + .PARAMETER Enabled + True/False if the interface is enabled + + .PARAMETER MTU + Maximum Transmission Unit size. Generally 1500 or 9000 + + .PARAMETER Virtual_Machine_Id + ID of the virtual machine to which the interface(s) are assigned. + + .PARAMETER Virtual_Machine + Name of the virtual machine to get interfaces + + .PARAMETER MAC_Address + MAC address assigned to the interface + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachineInterface + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Limit, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Offset, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Name, + + [Parameter(ValueFromPipeline = $true)] + [boolean]$Enabled, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$MTU, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Virtual_Machine_Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Virtual_Machine, + + [Parameter(ValueFromPipeline = $true)] + [string]$MAC_Address, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $URIParameters = @{ + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } elseif ($CmdletParameterName -eq 'Enabled') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].ToString().ToLower() + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualizationCluster { + <# + .SYNOPSIS + Obtains virtualization clusters from Netbox. + + .DESCRIPTION + Obtains one or more virtualization clusters based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a cluster + + .PARAMETER Name + Name of the cluster + + .PARAMETER Id + Database ID(s) of the cluster + + .PARAMETER Group + String value of the cluster group. + + .PARAMETER Group_Id + Database ID of the cluster group. + + .PARAMETER Type + String value of the Cluster type. + + .PARAMETER Type_Id + Database ID of the cluster type. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualizationCluster + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [string]$Group, + + [uint16]$Group_Id, + + [string]$Type, + + [uint16]$Type_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'clusters')) + + $URIParameters = @{ + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualizationClusterGroup { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Name, + + [string]$Slug, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'cluster-groups')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + #endregion GET commands + + + #region ADD commands + + function Add-NetboxVirtualMachine { + [CmdletBinding()] + [OutputType([pscustomobject])] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Cluster, + + [uint16]$Tenant, + + [NetboxVirtualMachineStatus]$Status = 'Active', + + [uint16]$Role, + + [uint16]$Platform, + + [uint16]$vCPUs, + + [uint16]$Memory, + + [uint16]$Disk, + + [hashtable]$Custom_Fields, + + [string]$Comments + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Status')) { + [void]$PSBoundParameters.Add('Status', $Status) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Status') { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body + } + + function Add-NetboxVirtualInterface { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Virtual_Machine, + + [boolean]$Enabled = $true, + + [string]$MAC_Address, + + [uint16]$MTU, + + [string]$Description, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Enabled')) { + [void]$PSBoundParameters.Add('enabled', $Enabled) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body + } + + + + #endregion ADD commands + + + #endregion + +#region Invoke-IPAM_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.ps1 + =========================================================================== + .DESCRIPTION + IPAM Object functions + #> + + function Get-NetboxIPAMChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri + } + + function VerifyIPAMChoices { + <# + .SYNOPSIS + Internal function to verify provided values for static choices + + .DESCRIPTION + When users connect to the API, choices for each major object are cached to the config variable. + These values are then utilized to verify if the provided value from a user is valid. + + .PARAMETER ProvidedValue + The value to validate against static choices + + .PARAMETER AggregateFamily + Verify against aggregate family values + + .PARAMETER PrefixFamily + Verify against prefix family values + + .PARAMETER PrefixStatus + Verify against prefix status values + + .PARAMETER IPAddressFamily + Verify against ip-address family values + + .PARAMETER IPAddressStatus + Verify against ip-address status values + + .PARAMETER IPAddressRole + Verify against ip-address role values + + .PARAMETER VLANStatus + Verify against VLAN status values + + .PARAMETER ServiceProtocol + Verify against service protocol values + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'loopback' -IPAddressRole + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'Loopback' -IPAddressFamily + >> Invalid value Loopback for ip-address:family. Must be one of: 4, 6, IPv4, IPv6 + + .FUNCTIONALITY + This cmdlet is intended to be used internally and not exposed to the user + + .OUTPUT + This function returns nothing if the value is valid. Otherwise, it will throw an error. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [object]$ProvidedValue, + + [Parameter(ParameterSetName = 'aggregate:family', + Mandatory = $true)] + [switch]$AggregateFamily, + + [Parameter(ParameterSetName = 'prefix:family', + Mandatory = $true)] + [switch]$PrefixFamily, + + [Parameter(ParameterSetName = 'prefix:status', + Mandatory = $true)] + [switch]$PrefixStatus, + + [Parameter(ParameterSetName = 'ip-address:family', + Mandatory = $true)] + [switch]$IPAddressFamily, + + [Parameter(ParameterSetName = 'ip-address:status', + Mandatory = $true)] + [switch]$IPAddressStatus, + + [Parameter(ParameterSetName = 'ip-address:role', + Mandatory = $true)] + [switch]$IPAddressRole, + + [Parameter(ParameterSetName = 'vlan:status', + Mandatory = $true)] + [switch]$VLANStatus, + + [Parameter(ParameterSetName = 'service:protocol', + Mandatory = $true)] + [switch]$ServiceProtocol + ) + + $ValidValues = New-Object System.Collections.ArrayList + + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).value) + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).label) + + if ($ValidValues.Count -eq 0) { + throw "Missing valid values for $($PSCmdlet.ParameterSetName)" + } + + if ($ValidValues -inotcontains $ProvidedValue) { + throw "Invalid value '$ProvidedValue' for '$($PSCmdlet.ParameterSetName)'. Must be one of: $($ValidValues -join ', ')" + } + + # Convert the ProvidedValue to the integer value + try { + $intVal = [uint16]"$ProvidedValue" + } catch { + # It must not be a number, get the value from the label + $intVal = [uint16]$script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).Where({$_.Label -eq $ProvidedValue}).Value + } + + return $intVal + } + + + function Get-NetboxIPAMAggregate { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Family, + + [datetime]$Date_Added, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$RIR_Id, + + [string]$RIR, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'aggregates')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMAddress { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$Parent, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Device, + + [uint16]$Device_ID, + + [string]$Virtual_Machine, + + [uint16]$Virtual_Machine_Id, + + [uint16]$Interface_Id, + + [object]$Status, + + [object]$Role, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -IPAddressFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -IPAddressStatus + } + + if ($Role) { + $PSBoundParameters.Role = VerifyIPAMChoices -ProvidedValue $Role -IPAddressRole + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'ip-addresses')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMAvaiableIP { + <# + .SYNOPSIS + A convenience method for returning available IP addresses within a prefix + + .DESCRIPTION + By default, the number of IPs returned will be equivalent to PAGINATE_COUNT. An arbitrary limit + (up to MAX_PAGE_SIZE, if set) may be passed, however results will not be paginated + + .PARAMETER Prefix_ID + A description of the Prefix_ID parameter. + + .PARAMETER NumberOfIPs + A description of the NumberOfIPs parameter. + + .EXAMPLE + PS C:\> Get-NetboxIPAMAvaiableIP -Prefix_ID $value1 + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [uint16]$Prefix_ID, + + [uint16]$NumberOfIPs, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes', $Prefix_ID, 'available-ips')) + + $uriParameters = @{} + + if ($NumberOfIPs) { + [void]$uriParameters.Add('limit', $NumberOfIPs) + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $uriParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMPrefix { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + #[string]$Within, + + #[string]$Within_Include, + + [string]$Contains, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Vlan_VId, + + [uint16]$Vlan_Id, + + [object]$Status, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -PrefixFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -PrefixStatus + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + + + + + + + + + + + + + + + + + #endregion + +# Build a list of common paramters so we can omit them to build URI parameters +$script:CommonParameterNames = New-Object System.Collections.ArrayList +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::CommonParameters)) +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)) +[void]$script:CommonParameterNames.Add('Raw') + +SetupNetboxConfigVariable + +if (-not ([System.Management.Automation.PSTypeName]'NetboxVirtualMachineStatus').Type) { + Add-Type -TypeDefinition @" +public enum NetboxVirtualMachineStatus +{ + Offline = 0, + Active = 1, + Staged = 3 +} +"@ +} + + +Export-ModuleMember -Function * +#Export-ModuleMember -Function *-* \ No newline at end of file diff --git a/Staging/Tests/Helpers.Tests.ps1 b/Staging/Tests/Helpers.Tests.ps1 new file mode 100644 index 0000000..395c666 --- /dev/null +++ b/Staging/Tests/Helpers.Tests.ps1 @@ -0,0 +1,189 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 11:36 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.Tests.ps1 + =========================================================================== + .DESCRIPTION + Helper functions Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe "Helpers tests" -Tag 'Core', 'Helpers' -Fixture { + It "Should throw because we are not connected" { + { + Check-NetboxIsConnected + } | Should -Throw + } + + Mock -CommandName 'CheckNetboxIsConnected' -MockWith { + return $true + } -ModuleName 'NetboxPS' + + Context "Building URI tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + It "Should give a basic URI object" { + BuildNewURI -HostName 'netbox.domain.com' | Should -BeOfType [System.UriBuilder] + } + + It "Should generate a URI using only a supplied hostname" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api//' + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 443 + $URIBuilder.URI.AbsoluteUri | Should -Be 'https://netbox.domain.com/api//' + } + + It "Should generate a URI using a hostname and segments" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api/seg1/seg2/' + $URIBuilder.URI.AbsoluteUri | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using insecure HTTP and default to port 80" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 80 + $URIBuilder.URI.AbsoluteURI | Should -Be 'http://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using HTTPS on port 1234" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Port 1234 + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 1234 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com:1234/api/seg1/seg2/' + } + + It "Should generate a URI using HTTP on port 4321" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -Port 4321 -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 4321 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'http://netbox.domain.com:4321/api/seg1/seg2/' + } + + It "Should generate a URI with parameters" { + $URIParameters = @{ + 'param1' = 'paramval1' + 'param2' = 'paramval2' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Parameters $URIParameters + $URIBuilder.Query | Should -BeExactly '?param1=paramval1¶m2=paramval2' + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/?param1=paramval1¶m2=paramval2' + } + } + } + + Context "Invoking request tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Mock -CommandName 'Invoke-RestMethod' -Verifiable -MockWith { + # Return an object of the items we would normally pass to Invoke-RestMethod + return [pscustomobject]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + 'results' = 'Only results' + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + It "Should return direct results instead of the raw request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder + + Assert-VerifiableMock + + $Result | Should -BeOfType [string] + $Result | Should -BeExactly "Only results" + } + + It "Should generate a basic request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be $URIBuilder.Uri.AbsoluteUri + $Result.Headers | Should -BeOfType [System.Collections.HashTable] + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Timeout | Should -Be 5 + $Result.ContentType | Should -Be 'application/json' + $Result.Body | Should -Be $null # We did not supply a body + } + + It "Should generate a POST request with body" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body @{'bodyparam1' = 'val1'} -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + } + + It "Should generate a POST request with an extra header" { + $Headers = @{ + 'Connection' = 'keep-alive' + } + + $Body = @{ + 'bodyparam1' = 'val1' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body $Body -Headers $Headers -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Headers.Connection | Should -Be "keep-alive" + } + + It "Should throw because of an invalid method" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Method 'Fake' + } | Should -Throw + } + + It "Should throw because of an out-of-range timeout" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Timeout 61 + } | Should -Throw + } + } + } +} + + + + + + diff --git a/Staging/Tests/IPAM.Tests.ps1 b/Staging/Tests/IPAM.Tests.ps1 new file mode 100644 index 0000000..ddcf174 --- /dev/null +++ b/Staging/Tests/IPAM.Tests.ps1 @@ -0,0 +1,214 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.Tests.ps1 + =========================================================================== + .DESCRIPTION + IPAM Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + + +Describe -Name "IPAM tests" -Tag 'Ipam' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxIPAMAggregate" -Fixture { + It "Should request the default number of aggregates" { + $Result = Get-NetboxIPAMAggregate + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAggregate -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAggregate -Query '10.10.0.0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=10.10.0.0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAggregate -Query 'my aggregate' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=my+aggregate' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAggregate -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAggregate -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-NetboxIPAMAddress" -Fixture { + It "Should request the default number of addresses" { + $Result = Get-NetboxIPAMAddress + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAddress -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAddress -Query '10.10.10.10' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=10.10.10.10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAddress -Query 'my ip address' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=my+ip+address' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAddress -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAddress -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + #region TODO: Figure out how to mock/test Verification appropriately... + <# + It "Should request with a family number" { + Mock -CommandName 'Get-NetboxIPAMChoices' -ModuleName 'NetboxPS' -MockWith { + return @" +{"aggregate:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:status":[{"label":"Container","value":0},{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"ip-address:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"ip-address:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3},{"label":"DHCP","value":5}],"ip-address:role":[{"label":"Loopback","value":10},{"label":"Secondary","value":20},{"label":"Anycast","value":30},{"label":"VIP","value":40},{"label":"VRRP","value":41},{"label":"HSRP","value":42},{"label":"GLBP","value":43},{"label":"CARP","value":44}],"vlan:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"service:protocol":[{"label":"TCP","value":6},{"label":"UDP","value":17}]} +"@ | ConvertFrom-Json + } + + Mock -CommandName 'Connect-NetboxAPI' -ModuleName 'NetboxPS' -MockWith { + $script:NetboxConfig.Connected = $true + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + } + Connect-NetboxAPI + $Result = Get-NetboxIPAMAddress -Role 4 + + Assert-VerifiableMock + Assert-MockCalled -CommandName "Get-NetboxIPAMChoices" + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?role=4' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + #> + #endregion + } + + Context -Name "Get-NetboxIPAMPrefix" { + + } + } +} + + + + + + + + + + diff --git a/Staging/Tests/Virtualization.Tests.ps1 b/Staging/Tests/Virtualization.Tests.ps1 new file mode 100644 index 0000000..8174020 --- /dev/null +++ b/Staging/Tests/Virtualization.Tests.ps1 @@ -0,0 +1,365 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 4:01 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.Tests.ps1 + =========================================================================== + .DESCRIPTION + Virtualization Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe -Name "Virtualization tests" -Tag 'Virtualization' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxVirtualMachine" -Fixture { + It "Should request the default number of VMs" { + $Result = Get-NetboxVirtualMachine + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualMachine -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualMachine -Query 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualMachine -Query 'test vm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=test+vm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualMachine -Name 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?name=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualMachine -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualMachine -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a status" { + $Result = Get-NetboxVirtualMachine -Status 'Active' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?status=1' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineInterface" -Fixture { + It "Should request the default number of interfaces" { + $Result = Get-NetboxVirtualMachineInterface + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a limit and offset" { + $Result = Get-NetboxVirtualMachineInterface -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a interface with a specific ID" { + $Result = Get-NetboxVirtualMachineInterface -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a name" { + $Result = Get-NetboxVirtualMachineInterface -Name 'Ethernet0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?name=Ethernet0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a VM ID" { + $Result = Get-NetboxVirtualMachineInterface -Virtual_Machine_Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?virtual_machine_id=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with Enabled" { + $Result = Get-NetboxVirtualMachineInterface -Enabled $true + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?enabled=true' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineCluster" -Fixture { + It "Should request the default number of clusters" { + $Result = Get-NetboxVirtualizationCluster + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationCluster -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualizationCluster -Query 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualizationCluster -Query 'test cluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=test+cluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationCluster -Name 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?name=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualizationCluster -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualizationCluster -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineClusterGroup" -Fixture { + It "Should request the default number of cluster groups" { + $Result = Get-NetboxVirtualizationClusterGroup + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationClusterGroup -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationClusterGroup -Name 'testclustergroup' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?name=testclustergroup' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a slug" { + $Result = Get-NetboxVirtualizationClusterGroup -Slug 'test-cluster-group' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?slug=test-cluster-group' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Add-NetboxVirtualMachine" -Fixture { + It "Should add a basic VM" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"cluster":1,"name":"testvm","status":1}' + } + + It "Should add a VM with CPUs, Memory, Disk, tenancy, and comments" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 -Status Active -vCPUs 4 -Memory 4096 -Tenant 11 -Disk 50 -Comments "these are comments" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"tenant":11,"comments":"these are comments","disk":50,"memory":4096,"name":"testvm","cluster":1,"status":1,"vcpus":4}' + } + } + + Context -Name "Add-NetboxVirtualInterface" -Fixture { + It "Should add a basic interface" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"virtual_machine":10,"name":"Ethernet0","enabled":true}' + } + + It "Should add an interface with a MAC, MTU, and Description" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 -Mac_Address '11:22:33:44:55:66' -MTU 1500 -Description "Test description" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"mtu":1500,"description":"Test description","enabled":true,"virtual_machine":10,"name":"Ethernet0","mac_address":"11:22:33:44:55:66"}' + } + } + } +} + + + + + + + + + + diff --git a/Tests/Helpers.Tests.ps1 b/Tests/Helpers.Tests.ps1 new file mode 100644 index 0000000..395c666 --- /dev/null +++ b/Tests/Helpers.Tests.ps1 @@ -0,0 +1,189 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 11:36 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.Tests.ps1 + =========================================================================== + .DESCRIPTION + Helper functions Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe "Helpers tests" -Tag 'Core', 'Helpers' -Fixture { + It "Should throw because we are not connected" { + { + Check-NetboxIsConnected + } | Should -Throw + } + + Mock -CommandName 'CheckNetboxIsConnected' -MockWith { + return $true + } -ModuleName 'NetboxPS' + + Context "Building URI tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + It "Should give a basic URI object" { + BuildNewURI -HostName 'netbox.domain.com' | Should -BeOfType [System.UriBuilder] + } + + It "Should generate a URI using only a supplied hostname" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api//' + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 443 + $URIBuilder.URI.AbsoluteUri | Should -Be 'https://netbox.domain.com/api//' + } + + It "Should generate a URI using a hostname and segments" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api/seg1/seg2/' + $URIBuilder.URI.AbsoluteUri | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using insecure HTTP and default to port 80" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 80 + $URIBuilder.URI.AbsoluteURI | Should -Be 'http://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using HTTPS on port 1234" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Port 1234 + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 1234 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com:1234/api/seg1/seg2/' + } + + It "Should generate a URI using HTTP on port 4321" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -Port 4321 -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 4321 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'http://netbox.domain.com:4321/api/seg1/seg2/' + } + + It "Should generate a URI with parameters" { + $URIParameters = @{ + 'param1' = 'paramval1' + 'param2' = 'paramval2' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Parameters $URIParameters + $URIBuilder.Query | Should -BeExactly '?param1=paramval1¶m2=paramval2' + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/?param1=paramval1¶m2=paramval2' + } + } + } + + Context "Invoking request tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Mock -CommandName 'Invoke-RestMethod' -Verifiable -MockWith { + # Return an object of the items we would normally pass to Invoke-RestMethod + return [pscustomobject]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + 'results' = 'Only results' + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + It "Should return direct results instead of the raw request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder + + Assert-VerifiableMock + + $Result | Should -BeOfType [string] + $Result | Should -BeExactly "Only results" + } + + It "Should generate a basic request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be $URIBuilder.Uri.AbsoluteUri + $Result.Headers | Should -BeOfType [System.Collections.HashTable] + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Timeout | Should -Be 5 + $Result.ContentType | Should -Be 'application/json' + $Result.Body | Should -Be $null # We did not supply a body + } + + It "Should generate a POST request with body" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body @{'bodyparam1' = 'val1'} -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + } + + It "Should generate a POST request with an extra header" { + $Headers = @{ + 'Connection' = 'keep-alive' + } + + $Body = @{ + 'bodyparam1' = 'val1' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body $Body -Headers $Headers -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Headers.Connection | Should -Be "keep-alive" + } + + It "Should throw because of an invalid method" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Method 'Fake' + } | Should -Throw + } + + It "Should throw because of an out-of-range timeout" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Timeout 61 + } | Should -Throw + } + } + } +} + + + + + + diff --git a/Tests/IPAM.Tests.ps1 b/Tests/IPAM.Tests.ps1 new file mode 100644 index 0000000..ddcf174 --- /dev/null +++ b/Tests/IPAM.Tests.ps1 @@ -0,0 +1,214 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.Tests.ps1 + =========================================================================== + .DESCRIPTION + IPAM Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + + +Describe -Name "IPAM tests" -Tag 'Ipam' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxIPAMAggregate" -Fixture { + It "Should request the default number of aggregates" { + $Result = Get-NetboxIPAMAggregate + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAggregate -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAggregate -Query '10.10.0.0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=10.10.0.0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAggregate -Query 'my aggregate' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=my+aggregate' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAggregate -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAggregate -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-NetboxIPAMAddress" -Fixture { + It "Should request the default number of addresses" { + $Result = Get-NetboxIPAMAddress + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAddress -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAddress -Query '10.10.10.10' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=10.10.10.10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAddress -Query 'my ip address' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=my+ip+address' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAddress -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAddress -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + #region TODO: Figure out how to mock/test Verification appropriately... + <# + It "Should request with a family number" { + Mock -CommandName 'Get-NetboxIPAMChoices' -ModuleName 'NetboxPS' -MockWith { + return @" +{"aggregate:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:status":[{"label":"Container","value":0},{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"ip-address:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"ip-address:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3},{"label":"DHCP","value":5}],"ip-address:role":[{"label":"Loopback","value":10},{"label":"Secondary","value":20},{"label":"Anycast","value":30},{"label":"VIP","value":40},{"label":"VRRP","value":41},{"label":"HSRP","value":42},{"label":"GLBP","value":43},{"label":"CARP","value":44}],"vlan:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"service:protocol":[{"label":"TCP","value":6},{"label":"UDP","value":17}]} +"@ | ConvertFrom-Json + } + + Mock -CommandName 'Connect-NetboxAPI' -ModuleName 'NetboxPS' -MockWith { + $script:NetboxConfig.Connected = $true + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + } + Connect-NetboxAPI + $Result = Get-NetboxIPAMAddress -Role 4 + + Assert-VerifiableMock + Assert-MockCalled -CommandName "Get-NetboxIPAMChoices" + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?role=4' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + #> + #endregion + } + + Context -Name "Get-NetboxIPAMPrefix" { + + } + } +} + + + + + + + + + + diff --git a/Tests/Setup.Tests.ps1 b/Tests/Setup.Tests.ps1 new file mode 100644 index 0000000..72143b3 --- /dev/null +++ b/Tests/Setup.Tests.ps1 @@ -0,0 +1,93 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 10:33 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: Setup.Tests.ps1 + =========================================================================== + .DESCRIPTION + Setup function Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe "Setup tests" -Tag 'Core', 'Setup' -Fixture { + It "Throws an error for an empty hostname" { + { Get-NetboxHostname } | Should -Throw + } + + It "Sets the hostname" { + Set-NetboxHostName -HostName 'netbox.domain.com' | Should -Be 'netbox.domain.com' + } + + It "Gets the hostname from the variable" { + Get-NetboxHostName | Should -Be 'netbox.domain.com' + } + + It "Throws an error for empty credentials" { + { Get-NetboxCredentials } | Should -Throw + } + + Context "Plain text credentials" { + It "Sets the credentials using plain text" { + $Creds = Set-NetboxCredentials -Token "faketoken" | Should -BeOfType [pscredential] + } + + It "Checks the set credentials" { + $Creds = Set-NetboxCredentials -Token "faketoken" + (Get-NetboxCredentials).GetNetworkCredential().Password | Should -BeExactly "faketoken" + } + } + + Context "Credentials object" { + $Creds = [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + + It "Sets the credentials using [pscredential]" { + Set-NetboxCredentials -Credentials $Creds | Should -BeOfType [pscredential] + } + + It "Checks the set credentials" { + (Get-NetboxCredentials).GetNetworkCredential().Password | Should -BeExactly 'faketoken' + } + } + + <# + Context "Connecting to the API" { + Mock Get-NetboxCircuitsChoices { + return $true + } -ModuleName NetboxPS -Verifiable + + $Creds = [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + + It "Connects using supplied hostname and obtained credentials" { + #$null = Set-NetboxCredentials -Credentials $Creds + Connect-NetboxAPI -Hostname "fake.org" | Should -Be $true + } + + It "Connects using supplied hostname and credentials" { + Connect-NetboxAPI -Hostname 'fake.org' -Credentials $Creds | Should -Be $true + } + + + + Assert-MockCalled -CommandName Get-NetboxCircuitsChoices -ModuleName NetboxPS + } + #> +} + + + + + + + + diff --git a/Tests/Virtualization.Tests.ps1 b/Tests/Virtualization.Tests.ps1 new file mode 100644 index 0000000..8174020 --- /dev/null +++ b/Tests/Virtualization.Tests.ps1 @@ -0,0 +1,365 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 4:01 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.Tests.ps1 + =========================================================================== + .DESCRIPTION + Virtualization Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe -Name "Virtualization tests" -Tag 'Virtualization' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxVirtualMachine" -Fixture { + It "Should request the default number of VMs" { + $Result = Get-NetboxVirtualMachine + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualMachine -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualMachine -Query 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualMachine -Query 'test vm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=test+vm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualMachine -Name 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?name=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualMachine -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualMachine -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a status" { + $Result = Get-NetboxVirtualMachine -Status 'Active' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?status=1' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineInterface" -Fixture { + It "Should request the default number of interfaces" { + $Result = Get-NetboxVirtualMachineInterface + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a limit and offset" { + $Result = Get-NetboxVirtualMachineInterface -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a interface with a specific ID" { + $Result = Get-NetboxVirtualMachineInterface -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a name" { + $Result = Get-NetboxVirtualMachineInterface -Name 'Ethernet0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?name=Ethernet0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a VM ID" { + $Result = Get-NetboxVirtualMachineInterface -Virtual_Machine_Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?virtual_machine_id=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with Enabled" { + $Result = Get-NetboxVirtualMachineInterface -Enabled $true + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?enabled=true' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineCluster" -Fixture { + It "Should request the default number of clusters" { + $Result = Get-NetboxVirtualizationCluster + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationCluster -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualizationCluster -Query 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualizationCluster -Query 'test cluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=test+cluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationCluster -Name 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?name=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualizationCluster -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualizationCluster -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineClusterGroup" -Fixture { + It "Should request the default number of cluster groups" { + $Result = Get-NetboxVirtualizationClusterGroup + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationClusterGroup -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationClusterGroup -Name 'testclustergroup' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?name=testclustergroup' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a slug" { + $Result = Get-NetboxVirtualizationClusterGroup -Slug 'test-cluster-group' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?slug=test-cluster-group' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Add-NetboxVirtualMachine" -Fixture { + It "Should add a basic VM" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"cluster":1,"name":"testvm","status":1}' + } + + It "Should add a VM with CPUs, Memory, Disk, tenancy, and comments" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 -Status Active -vCPUs 4 -Memory 4096 -Tenant 11 -Disk 50 -Comments "these are comments" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"tenant":11,"comments":"these are comments","disk":50,"memory":4096,"name":"testvm","cluster":1,"status":1,"vcpus":4}' + } + } + + Context -Name "Add-NetboxVirtualInterface" -Fixture { + It "Should add a basic interface" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"virtual_machine":10,"name":"Ethernet0","enabled":true}' + } + + It "Should add an interface with a MAC, MTU, and Description" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 -Mac_Address '11:22:33:44:55:66' -MTU 1500 -Description "Test description" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"mtu":1500,"description":"Test description","enabled":true,"virtual_machine":10,"name":"Ethernet0","mac_address":"11:22:33:44:55:66"}' + } + } + } +} + + + + + + + + + + diff --git a/dist/NetboxPS.psd1 b/dist/NetboxPS.psd1 new file mode 100644 index 0000000..580df7b --- /dev/null +++ b/dist/NetboxPS.psd1 @@ -0,0 +1,127 @@ +<# + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 11:04 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: NetboxPS.psd1 + ------------------------------------------------------------------------- + Module Manifest + ------------------------------------------------------------------------- + Module Name: NetboxPS + =========================================================================== +#> + + +@{ + + # Script module or binary module file associated with this manifest + ModuleToProcess = 'NetboxPS.psm1' + + # Version number of this module. + ModuleVersion = '1.0.0.0' + + # ID used to uniquely identify this module + GUID = 'bba9b06c-49c8-47cf-8358-aca7c4e78896' + + # Author of this module + Author = ' Ben Claussen' + + # Company or vendor of this module + CompanyName = 'NEOnet' + + # Copyright statement for this module + Copyright = '(c) 2018. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'Module description' + + # Minimum version of the Windows PowerShell engine required by this module + PowerShellVersion = '2.0' + + # Name of the Windows PowerShell host required by this module + PowerShellHostName = '' + + # Minimum version of the Windows PowerShell host required by this module + PowerShellHostVersion = '' + + # Minimum version of the .NET Framework required by this module + DotNetFrameworkVersion = '2.0' + + # Minimum version of the common language runtime (CLR) required by this module + CLRVersion = '2.0.50727' + + # Processor architecture (None, X86, Amd64, IA64) required by this module + ProcessorArchitecture = 'None' + + # Modules that must be imported into the global environment prior to importing + # this module + RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + RequiredAssemblies = @('System.Web') + + # Script files (.ps1) that are run in the caller's environment prior to + # importing this module + ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in + # ModuleToProcess + NestedModules = @() + + # Functions to export from this module + FunctionsToExport = '*' #For performanace, list functions explicity + + # Cmdlets to export from this module + CmdletsToExport = '*' + + # Variables to export from this module + VariablesToExport = '*' + + # Aliases to export from this module + AliasesToExport = '*' #For performanace, list alias explicity + + # List of all modules packaged with this module + ModuleList = @() + + # List of all files packaged with this module + FileList = @() + + # Private data to pass to the module specified in ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + #Support for PowerShellGet galleries. + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + + } # End of PrivateData hashtable +} + + + + + + + diff --git a/dist/NetboxPS.psm1 b/dist/NetboxPS.psm1 new file mode 100644 index 0000000..2787b1c --- /dev/null +++ b/dist/NetboxPS.psm1 @@ -0,0 +1,1618 @@ +<# + .NOTES + -------------------------------------------------------------------------------- + Code generated by: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Generated on: 5/11/2018 3:48 PM + Generated by: Ben Claussen + Organization: NEOnet + -------------------------------------------------------------------------------- + .DESCRIPTION + Script generated by PowerShell Studio 2018 +#> + + +#region Invoke-Helpers_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.ps1 + =========================================================================== + .DESCRIPTION + These function are internal functions and generally are not + exposed to the end user + #> + + function CheckNetboxIsConnected { + [CmdletBinding()] + param () + + Write-Verbose "Checking connection status" + if (-not $script:NetboxConfig.Connected) { + throw "Not connected to a Netbox API! Please run 'Connect-NetboxAPI'" + } + } + + function BuildNewURI { + <# + .SYNOPSIS + Create a new URI for Netbox + + .DESCRIPTION + A detailed description of the BuildNewURI function. + + .PARAMETER Hostname + Hostname of the Netbox API + + .PARAMETER Segments + Array of strings for each segment in the URL path + + .PARAMETER Parameters + Hashtable of query parameters to include + + .PARAMETER HTTPS + Whether to use HTTPS or HTTP + + .PARAMETER Port + A description of the Port parameter. + + .PARAMETER APIInfo + A description of the APIInfo parameter. + + .EXAMPLE + PS C:\> BuildNewURI + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + [OutputType([System.UriBuilder])] + param + ( + [Parameter(Mandatory = $false)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [string[]]$Segments, + + [Parameter(Mandatory = $false)] + [hashtable]$Parameters, + + [Parameter(Mandatory = $false)] + [boolean]$HTTPS = $true, + + [ValidateRange(1, 65535)] + [uint16]$Port = 443, + + [switch]$SkipConnectedCheck + ) + + Write-Verbose "Building URI" + + if (-not $SkipConnectedCheck) { + # There is no point in continuing if we have not successfully connected to an API + $null = CheckNetboxIsConnected + } + + if (-not $Hostname) { + $Hostname = Get-NetboxHostname + } + + if ($HTTPS) { + Write-Verbose "Setting scheme to HTTPS" + $Scheme = 'https' + } else { + Write-Warning "Connecting via non-secure HTTP is not-recommended" + + Write-Verbose "Setting scheme to HTTP" + $Scheme = 'http' + + if (-not $PSBoundParameters.ContainsKey('Port')) { + # Set the port to 80 if the user did not supply it + Write-Verbose "Setting port to 80 as default because it was not supplied by the user" + $Port = 80 + } + } + + # Begin a URI builder with HTTP/HTTPS and the provided hostname + $uriBuilder = [System.UriBuilder]::new($Scheme, $Hostname, $Port) + + # Generate the path by trimming excess slashes and whitespace from the $segments[] and joining together + $uriBuilder.Path = "api/{0}/" -f ($Segments.ForEach({$_.trim('/').trim()}) -join '/') + + Write-Verbose "URIPath: $($uriBuilder.Path)" + + if ($parameters) { + # Loop through the parameters and use the HttpUtility to create a Query string + [System.Collections.Specialized.NameValueCollection]$URIParams = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) + + foreach ($param in $Parameters.GetEnumerator()) { + Write-Verbose "Adding URI parameter $($param.Key):$($param.Value)" + $URIParams[$param.Key] = $param.Value + } + + $uriBuilder.Query = $URIParams.ToString() + } + + Write-Verbose "Completed building URIBuilder" + # Return the entire UriBuilder object + $uriBuilder + } + + function GetNetboxAPIErrorBody { + param + ( + [Parameter(Mandatory = $true)] + [System.Net.HttpWebResponse]$Response + ) + + # This takes the $Response stream and turns it into a useable object... generally a string. + # If the body is JSON, you should be able to use ConvertFrom-Json + + $reader = New-Object System.IO.StreamReader($Response.GetResponseStream()) + $reader.BaseStream.Position = 0 + $reader.DiscardBufferedData() + $reader.ReadToEnd() + } + + function InvokeNetboxRequest { + [CmdletBinding(SupportsShouldProcess = $true)] + param + ( + [Parameter(Mandatory = $true)] + [System.UriBuilder]$URI, + + [Hashtable]$Headers = @{}, + + [pscustomobject]$Body = $null, + + [ValidateRange(0, 60)] + [uint16]$Timeout = 5, + + [ValidateSet('GET', 'PATCH', 'PUT', 'POST', 'DELETE', IgnoreCase = $true)] + [string]$Method = 'GET', + + [switch]$Raw + ) + + $creds = Get-NetboxCredentials + + $Headers.Authorization = "Token {0}" -f $creds.GetNetworkCredential().Password + + $splat = @{ + 'Method' = $Method + 'Uri' = $URI.Uri.AbsoluteUri # This property auto generates the scheme, hostname, path, and query + 'Headers' = $Headers + 'TimeoutSec' = $Timeout + 'ContentType' = 'application/json' + 'ErrorAction' = 'Stop' + 'Verbose' = $VerbosePreference + } + + if ($Body) { + Write-Verbose "BODY: $($Body | ConvertTo-Json -Compress)" + $null = $splat.Add('Body', ($Body | ConvertTo-Json -Compress)) + } + + $result = Invoke-RestMethod @splat + + #region TODO: Handle errors a little more gracefully... + + <# + try { + Write-Verbose "Sending request..." + $result = Invoke-RestMethod @splat + Write-Verbose $result + } catch { + Write-Verbose "Caught exception" + if ($_.Exception.psobject.properties.Name.contains('Response')) { + Write-Verbose "Exception contains a response property" + if ($Raw) { + Write-Verbose "RAW provided...throwing raw exception" + throw $_ + } + + Write-Verbose "Converting response to object" + $myError = GetNetboxAPIErrorBody -Response $_.Exception.Response | ConvertFrom-Json + } else { + Write-Verbose "No response property found" + $myError = $_ + } + } + + Write-Verbose "MyError is $($myError.GetType().FullName)" + + if ($myError -is [Exception]) { + throw $_ + } elseif ($myError -is [pscustomobject]) { + throw $myError.detail + } + #> + + #endregion TODO: Handle errors a little more gracefully... + + # If the user wants the raw value from the API... otherwise return only the actual result + if ($Raw) { + Write-Verbose "Returning raw result" + return $result + } else { + if ($result.psobject.Properties.Name.Contains('results')) { + Write-Verbose "Found Results property on data, returning results directly" + return $result.Results + } else { + Write-Verbose "Did NOT find results property on data, returning raw result" + return $result + } + } + } + + function ThrowNetboxRESTError { + $uriSegments = [System.Collections.ArrayList]::new(@('fake', 'url')) + + $URIParameters = @{} + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw + } + + + + + + + + + + #endregion + +#region Invoke-Setup_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:33 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Setup.ps1 + =========================================================================== + .DESCRIPTION + These are the function used to setup the environment for connecting + to a Netbox API + #> + + function SetupNetboxConfigVariable { + [CmdletBinding()] + param + ( + [switch]$Overwrite + ) + + Write-Verbose "Checking for NetboxConfig hashtable" + if ((-not ($script:NetboxConfig)) -or $Overwrite) { + Write-Verbose "Creating NetboxConfig hashtable" + $script:NetboxConfig = @{ + 'Connected' = $false + 'Choices' = @{ + 'Circuits' = $null + 'DCIM' = $null + 'Extras' = $null + 'IPAM' = $null + 'Secrets' = $null + 'Tenancy' = $null + 'Virtualization' = $null + } + } + } + + Write-Verbose "NetboxConfig hashtable already exists" + } + + function GetNetboxConfigVariable { + return $script:NetboxConfig + } + + function Set-NetboxHostName { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname + ) + + $script:NetboxConfig.Hostname = $Hostname.Trim() + $script:NetboxConfig.Hostname + } + + function Get-NetboxHostname { + [CmdletBinding()] + param () + + Write-Verbose "Getting Netbox hostname" + if ($script:NetboxConfig.Hostname -eq $null) { + throw "Netbox Hostname is not set! You may set it with Set-NetboxHostname -Hostname 'hostname.domain.tld'" + } + + $script:NetboxConfig.Hostname + } + + function Set-NetboxCredentials { + [CmdletBinding(DefaultParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'CredsObject')] + [OutputType([pscredential], ParameterSetName = 'UserPass')] + param + ( + [Parameter(ParameterSetName = 'CredsObject', + Mandatory = $true)] + [pscredential]$Credentials, + + [Parameter(ParameterSetName = 'UserPass', + Mandatory = $true)] + [string]$Token + ) + + switch ($PsCmdlet.ParameterSetName) { + 'CredsObject' { + $script:NetboxConfig.Credentials = $Credentials + break + } + + 'UserPass' { + $securePW = ConvertTo-SecureString $Token -AsPlainText -Force + $script:NetboxConfig.Credentials = [System.Management.Automation.PSCredential]::new('notapplicable', $securePW) + break + } + } + + $script:NetboxConfig.Credentials + } + + function Get-NetboxCredentials { + [CmdletBinding()] + [OutputType([pscredential])] + param () + + if (-not $script:NetboxConfig.Credentials) { + throw "Netbox Credentials not set! You may set with Set-NetboxCredentials" + } + + $script:NetboxConfig.Credentials + } + + function VerifyAPIConnectivity { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -SkipConnectedCheck + + InvokeNetboxRequest -URI $uri + } + + function Connect-NetboxAPI { + <# + .SYNOPSIS + Connects to the Netbox API and ensures credentials work properly + + .DESCRIPTION + A detailed description of the Connect-NetboxAPI function. + + .PARAMETER Hostname + A description of the Hostname parameter. + + .PARAMETER Credentials + A description of the Credentials parameter. + + .EXAMPLE + PS C:\> Connect-NetboxAPI -Hostname "netbox.domain.com" + + This will prompt for credentials, then proceed to attempt a connection to Netbox + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Hostname, + + [Parameter(Mandatory = $false)] + [pscredential]$Credentials + ) + + if (-not $Credentials) { + try { + $Credentials = Get-NetboxCredentials -ErrorAction Stop + } catch { + # Credentials are not set... Try to obtain from the user + if (-not ($Credentials = Get-Credential -UserName 'username-not-applicable' -Message "Enter token for Netbox")) { + throw "Token is necessary to connect to a Netbox API." + } + } + } + + $null = Set-NetboxHostName -Hostname $Hostname + $null = Set-NetboxCredentials -Credentials $Credentials + + try { + Write-Verbose "Verifying API connectivity..." + $APIInfo = VerifyAPIConnectivity + $script:NetboxConfig.Connected = $true + Write-Verbose "Successfully connected!" + } catch { + Write-Verbose "Failed to connect. Generating error" + Write-Verbose $_.Exception.Message + if (($_.Exception.Response) -and ($_.Exception.Response.StatusCode -eq 403)) { + throw "Invalid token" + } else { + throw $_ + } + } + + $script:NetboxConfig.Choices.Circuits = Get-NetboxCircuitsChoices + #$script:NetboxConfig.Choices.DCIM = Get-NetboxDCIMChoices + $script:NetboxConfig.Choices.Extras = Get-NetboxExtrasChoices + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + #$script:NetboxConfig.Choices.Secrets = Get-NetboxSecretsChoices + #$script:NetboxConfig.Choices.Tenancy = Get-NetboxTenancyChoices + $script:NetboxConfig.Choices.Virtualization = Get-NetboxVirtualizationChoices + + } + + + + + + + + + + + #endregion + +#region Invoke-Extras_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 3:43 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Extras.ps1 + =========================================================================== + .DESCRIPTION + Extras objects functions + #> + + function Get-NetboxExtrasChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('extras', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri + } + #endregion + +#region Invoke-Circuits_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.148 + Created on: 2/28/2018 4:06 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Circuits.ps1 + =========================================================================== + .DESCRIPTION + Circuit object functions + #> + + function Get-NetboxCircuitsChoices { + <# + .SYNOPSIS + Gets the choices associated with circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuitsChoices function. + + .EXAMPLE + PS C:\> Get-NetboxCircuitsChoices + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('circuits', '_choices')) + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri + } + + function Get-NetboxCircuit { + <# + .SYNOPSIS + Gets one or more circuits + + .DESCRIPTION + A detailed description of the Get-NetboxCircuit function. + + .PARAMETER CID + Circuit ID + + .PARAMETER InstallDate + Date of installation + + .PARAMETER CommitRate + Committed rate in Kbps + + .PARAMETER Query + A raw search query... As if you were searching the web site + + .PARAMETER Provider + The name or ID of the provider. Provide either [string] or [int]. String will search provider names, integer will search database IDs + + .PARAMETER Type + Type of circuit. Provide either [string] or [int]. String will search provider type names, integer will search database IDs + + .PARAMETER Site + Location/site of circuit. Provide either [string] or [int]. String will search site names, integer will search database IDs + + .PARAMETER Tenant + Tenant assigned to circuit. Provide either [string] or [int]. String will search tenant names, integer will search database IDs + + .PARAMETER Id + Database ID of circuit. This will query for exactly the IDs provided + + .PARAMETER ID__IN + Multiple unique DB IDs to retrieve + + .EXAMPLE + PS C:\> Get-NetboxCircuit + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [string]$CID, + + [datetime]$InstallDate, + + [uint32]$CommitRate, + + [string]$Query, + + [object]$Provider, + + [object]$Type, + + [string]$Site, + + [string]$Tenant, + + [uint16[]]$Id + ) + + #TODO: Place script here + } + #endregion + +#region Invoke-Virtualization_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 3:59 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.ps1 + =========================================================================== + .DESCRIPTION + Virtualization object functions + #> + + #region GET commands + + function Get-NetboxVirtualizationChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri + } + + function Get-NetboxVirtualMachine { + <# + .SYNOPSIS + Obtains virtual machines from Netbox. + + .DESCRIPTION + Obtains one or more virtual machines based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a VM + + .PARAMETER Name + Name of the VM + + .PARAMETER Id + Database ID of the VM + + .PARAMETER Status + Status of the VM + + .PARAMETER Tenant + String value of tenant + + .PARAMETER Tenant_ID + Database ID of the tenant. + + .PARAMETER Platform + String value of the platform + + .PARAMETER Platform_ID + Database ID of the platform + + .PARAMETER Cluster_Group + String value of the cluster group. + + .PARAMETER Cluster_Group_Id + Database ID of the cluster group. + + .PARAMETER Cluster_Type + String value of the Cluster type. + + .PARAMETER Cluster_Type_Id + Database ID of the cluster type. + + .PARAMETER Cluster_Id + Database ID of the cluster. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Role + String value of the role. + + .PARAMETER Role_Id + Database ID of the role. + + .PARAMETER Raw + A description of the Raw parameter. + + .PARAMETER TenantID + Database ID of tenant + + .PARAMETER PlatformID + Database ID of the platform + + .PARAMETER id__in + Database IDs of VMs + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachine + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [NetboxVirtualMachineStatus]$Status, + + [string]$Tenant, + + [uint16]$Tenant_ID, + + [string]$Platform, + + [uint16]$Platform_ID, + + [string]$Cluster_Group, + + [uint16]$Cluster_Group_Id, + + [string]$Cluster_Type, + + [uint16]$Cluster_Type_Id, + + [uint16]$Cluster_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } elseif ($CmdletParameterName -eq 'Status') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualMachineInterface { + <# + .SYNOPSIS + Gets VM interfaces + + .DESCRIPTION + Obtains the interface objects for one or more VMs + + .PARAMETER Limit + Number of results to return per page. + + .PARAMETER Offset + The initial index from which to return the results. + + .PARAMETER Id + Database ID of the interface + + .PARAMETER Name + Name of the interface + + .PARAMETER Enabled + True/False if the interface is enabled + + .PARAMETER MTU + Maximum Transmission Unit size. Generally 1500 or 9000 + + .PARAMETER Virtual_Machine_Id + ID of the virtual machine to which the interface(s) are assigned. + + .PARAMETER Virtual_Machine + Name of the virtual machine to get interfaces + + .PARAMETER MAC_Address + MAC address assigned to the interface + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualMachineInterface + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Limit, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [uint16]$Offset, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Name, + + [Parameter(ValueFromPipeline = $true)] + [boolean]$Enabled, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$MTU, + + [Parameter(ValueFromPipeline = $true)] + [uint16]$Virtual_Machine_Id, + + [Parameter(ValueFromPipeline = $true)] + [string]$Virtual_Machine, + + [Parameter(ValueFromPipeline = $true)] + [string]$MAC_Address, + + [Parameter(ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true)] + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $URIParameters = @{ + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } elseif ($CmdletParameterName -eq 'Enabled') { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].ToString().ToLower() + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualizationCluster { + <# + .SYNOPSIS + Obtains virtualization clusters from Netbox. + + .DESCRIPTION + Obtains one or more virtualization clusters based on provided filters. + + .PARAMETER Limit + Number of results to return per page + + .PARAMETER Offset + The initial index from which to return the results + + .PARAMETER Query + A general query used to search for a cluster + + .PARAMETER Name + Name of the cluster + + .PARAMETER Id + Database ID(s) of the cluster + + .PARAMETER Group + String value of the cluster group. + + .PARAMETER Group_Id + Database ID of the cluster group. + + .PARAMETER Type + String value of the Cluster type. + + .PARAMETER Type_Id + Database ID of the cluster type. + + .PARAMETER Site + String value of the site. + + .PARAMETER Site_Id + Database ID of the site. + + .PARAMETER Raw + A description of the Raw parameter. + + .EXAMPLE + PS C:\> Get-NetboxVirtualizationCluster + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [Alias('q')] + [string]$Query, + + [string]$Name, + + [Alias('id__in')] + [uint16[]]$Id, + + [string]$Group, + + [uint16]$Group_Id, + + [string]$Type, + + [uint16]$Type_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'clusters')) + + $URIParameters = @{ + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxVirtualizationClusterGroup { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Name, + + [string]$Slug, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'cluster-groups')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + #endregion GET commands + + + #region ADD commands + + function Add-NetboxVirtualMachine { + [CmdletBinding()] + [OutputType([pscustomobject])] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Cluster, + + [uint16]$Tenant, + + [NetboxVirtualMachineStatus]$Status = 'Active', + + [uint16]$Role, + + [uint16]$Platform, + + [uint16]$vCPUs, + + [uint16]$Memory, + + [uint16]$Disk, + + [hashtable]$Custom_Fields, + + [string]$Comments + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'virtual-machines')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Status')) { + [void]$PSBoundParameters.Add('Status', $Status) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Status') { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName].value__ + } else { + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body + } + + function Add-NetboxVirtualInterface { + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [uint16]$Virtual_Machine, + + [boolean]$Enabled = $true, + + [string]$MAC_Address, + + [uint16]$MTU, + + [string]$Description, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('virtualization', 'interfaces')) + + $Body = @{} + + if (-not $PSBoundParameters.ContainsKey('Enabled')) { + [void]$PSBoundParameters.Add('enabled', $Enabled) + } + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + $Body[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + + $uri = BuildNewURI -Segments $uriSegments + + InvokeNetboxRequest -URI $uri -Method POST -Body $Body + } + + + + #endregion ADD commands + + + #endregion + +#region Invoke-IPAM_ps1 + <# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.ps1 + =========================================================================== + .DESCRIPTION + IPAM Object functions + #> + + function Get-NetboxIPAMChoices { + [CmdletBinding()] + param () + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', '_choices')) + + $uri = BuildNewURI -Segments $uriSegments -Parameters $Parameters + + InvokeNetboxRequest -URI $uri + } + + function VerifyIPAMChoices { + <# + .SYNOPSIS + Internal function to verify provided values for static choices + + .DESCRIPTION + When users connect to the API, choices for each major object are cached to the config variable. + These values are then utilized to verify if the provided value from a user is valid. + + .PARAMETER ProvidedValue + The value to validate against static choices + + .PARAMETER AggregateFamily + Verify against aggregate family values + + .PARAMETER PrefixFamily + Verify against prefix family values + + .PARAMETER PrefixStatus + Verify against prefix status values + + .PARAMETER IPAddressFamily + Verify against ip-address family values + + .PARAMETER IPAddressStatus + Verify against ip-address status values + + .PARAMETER IPAddressRole + Verify against ip-address role values + + .PARAMETER VLANStatus + Verify against VLAN status values + + .PARAMETER ServiceProtocol + Verify against service protocol values + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'loopback' -IPAddressRole + + .EXAMPLE + PS C:\> VerifyIPAMChoices -ProvidedValue 'Loopback' -IPAddressFamily + >> Invalid value Loopback for ip-address:family. Must be one of: 4, 6, IPv4, IPv6 + + .FUNCTIONALITY + This cmdlet is intended to be used internally and not exposed to the user + + .OUTPUT + This function returns nothing if the value is valid. Otherwise, it will throw an error. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [object]$ProvidedValue, + + [Parameter(ParameterSetName = 'aggregate:family', + Mandatory = $true)] + [switch]$AggregateFamily, + + [Parameter(ParameterSetName = 'prefix:family', + Mandatory = $true)] + [switch]$PrefixFamily, + + [Parameter(ParameterSetName = 'prefix:status', + Mandatory = $true)] + [switch]$PrefixStatus, + + [Parameter(ParameterSetName = 'ip-address:family', + Mandatory = $true)] + [switch]$IPAddressFamily, + + [Parameter(ParameterSetName = 'ip-address:status', + Mandatory = $true)] + [switch]$IPAddressStatus, + + [Parameter(ParameterSetName = 'ip-address:role', + Mandatory = $true)] + [switch]$IPAddressRole, + + [Parameter(ParameterSetName = 'vlan:status', + Mandatory = $true)] + [switch]$VLANStatus, + + [Parameter(ParameterSetName = 'service:protocol', + Mandatory = $true)] + [switch]$ServiceProtocol + ) + + $ValidValues = New-Object System.Collections.ArrayList + + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).value) + [void]$ValidValues.AddRange($script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).label) + + if ($ValidValues.Count -eq 0) { + throw "Missing valid values for $($PSCmdlet.ParameterSetName)" + } + + if ($ValidValues -inotcontains $ProvidedValue) { + throw "Invalid value '$ProvidedValue' for '$($PSCmdlet.ParameterSetName)'. Must be one of: $($ValidValues -join ', ')" + } + + # Convert the ProvidedValue to the integer value + try { + $intVal = [uint16]"$ProvidedValue" + } catch { + # It must not be a number, get the value from the label + $intVal = [uint16]$script:NetboxConfig.Choices.IPAM.$($PSCmdlet.ParameterSetName).Where({$_.Label -eq $ProvidedValue}).Value + } + + return $intVal + } + + + function Get-NetboxIPAMAggregate { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [string]$Family, + + [datetime]$Date_Added, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$RIR_Id, + + [string]$RIR, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'aggregates')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMAddress { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + [uint16]$Parent, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Device, + + [uint16]$Device_ID, + + [string]$Virtual_Machine, + + [uint16]$Virtual_Machine_Id, + + [uint16]$Interface_Id, + + [object]$Status, + + [object]$Role, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -IPAddressFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -IPAddressStatus + } + + if ($Role) { + $PSBoundParameters.Role = VerifyIPAMChoices -ProvidedValue $Role -IPAddressRole + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'ip-addresses')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMAvaiableIP { + <# + .SYNOPSIS + A convenience method for returning available IP addresses within a prefix + + .DESCRIPTION + By default, the number of IPs returned will be equivalent to PAGINATE_COUNT. An arbitrary limit + (up to MAX_PAGE_SIZE, if set) may be passed, however results will not be paginated + + .PARAMETER Prefix_ID + A description of the Prefix_ID parameter. + + .PARAMETER NumberOfIPs + A description of the NumberOfIPs parameter. + + .EXAMPLE + PS C:\> Get-NetboxIPAMAvaiableIP -Prefix_ID $value1 + + .NOTES + Additional information about the function. + #> + + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [uint16]$Prefix_ID, + + [uint16]$NumberOfIPs, + + [switch]$Raw + ) + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes', $Prefix_ID, 'available-ips')) + + $uriParameters = @{} + + if ($NumberOfIPs) { + [void]$uriParameters.Add('limit', $NumberOfIPs) + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $uriParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + function Get-NetboxIPAMPrefix { + [CmdletBinding()] + param + ( + [uint16]$Limit, + + [uint16]$Offset, + + [object]$Family, + + [uint16[]]$Id, + + [string]$Query, + + #[string]$Within, + + #[string]$Within_Include, + + [string]$Contains, + + [byte]$Mask_Length, + + [string]$VRF, + + [uint16]$VRF_Id, + + [string]$Tenant, + + [uint16]$Tenant_Id, + + [string]$Site, + + [uint16]$Site_Id, + + [string]$Vlan_VId, + + [uint16]$Vlan_Id, + + [object]$Status, + + [string]$Role, + + [uint16]$Role_Id, + + [switch]$Raw + ) + + if ($Family) { + $PSBoundParameters.Family = VerifyIPAMChoices -ProvidedValue $Family -PrefixFamily + } + + if ($Status) { + $PSBoundParameters.Status = VerifyIPAMChoices -ProvidedValue $Status -PrefixStatus + } + + $uriSegments = [System.Collections.ArrayList]::new(@('ipam', 'prefixes')) + + $URIParameters = @{} + + foreach ($CmdletParameterName in $PSBoundParameters.Keys) { + if ($CmdletParameterName -in $CommonParameterNames) { + # These are common parameters and should not be appended to the URI + Write-Debug "Skipping parameter $CmdletParameterName" + continue + } + + if ($CmdletParameterName -eq 'Id') { + # Check if there is one or more values for Id and build a URI or query as appropriate + if (@($PSBoundParameters[$CmdletParameterName]).Count -gt 1) { + $URIParameters['id__in'] = $Id -join ',' + } else { + [void]$uriSegments.Add($PSBoundParameters[$CmdletParameterName]) + } + } elseif ($CmdletParameterName -eq 'Query') { + $URIParameters['q'] = $PSBoundParameters[$CmdletParameterName] + } else { + $URIParameters[$CmdletParameterName.ToLower()] = $PSBoundParameters[$CmdletParameterName] + } + } + + $uri = BuildNewURI -Segments $uriSegments -Parameters $URIParameters + + InvokeNetboxRequest -URI $uri -Raw:$Raw + } + + + + + + + + + + + + + + + + + + #endregion + +# Build a list of common paramters so we can omit them to build URI parameters +$script:CommonParameterNames = New-Object System.Collections.ArrayList +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::CommonParameters)) +[void]$script:CommonParameterNames.AddRange(@([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)) +[void]$script:CommonParameterNames.Add('Raw') + +SetupNetboxConfigVariable + +if (-not ([System.Management.Automation.PSTypeName]'NetboxVirtualMachineStatus').Type) { + Add-Type -TypeDefinition @" +public enum NetboxVirtualMachineStatus +{ + Offline = 0, + Active = 1, + Staged = 3 +} +"@ +} + + +Export-ModuleMember -Function * +#Export-ModuleMember -Function *-* \ No newline at end of file diff --git a/dist/Tests/Helpers.Tests.ps1 b/dist/Tests/Helpers.Tests.ps1 new file mode 100644 index 0000000..395c666 --- /dev/null +++ b/dist/Tests/Helpers.Tests.ps1 @@ -0,0 +1,189 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 11:36 AM + Created by: Ben Claussen + Organization: NEOnet + Filename: Helpers.Tests.ps1 + =========================================================================== + .DESCRIPTION + Helper functions Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe "Helpers tests" -Tag 'Core', 'Helpers' -Fixture { + It "Should throw because we are not connected" { + { + Check-NetboxIsConnected + } | Should -Throw + } + + Mock -CommandName 'CheckNetboxIsConnected' -MockWith { + return $true + } -ModuleName 'NetboxPS' + + Context "Building URI tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + It "Should give a basic URI object" { + BuildNewURI -HostName 'netbox.domain.com' | Should -BeOfType [System.UriBuilder] + } + + It "Should generate a URI using only a supplied hostname" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api//' + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 443 + $URIBuilder.URI.AbsoluteUri | Should -Be 'https://netbox.domain.com/api//' + } + + It "Should generate a URI using a hostname and segments" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + $URIBuilder.Host | Should -BeExactly 'netbox.domain.com' + $URIBuilder.Path | Should -BeExactly 'api/seg1/seg2/' + $URIBuilder.URI.AbsoluteUri | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using insecure HTTP and default to port 80" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 80 + $URIBuilder.URI.AbsoluteURI | Should -Be 'http://netbox.domain.com/api/seg1/seg2/' + } + + It "Should generate a URI using HTTPS on port 1234" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Port 1234 + $URIBuilder.Scheme | Should -Be 'https' + $URIBuilder.Port | Should -Be 1234 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com:1234/api/seg1/seg2/' + } + + It "Should generate a URI using HTTP on port 4321" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -HTTPS $false -Port 4321 -WarningAction 'SilentlyContinue' + $URIBuilder.Scheme | Should -Be 'http' + $URIBuilder.Port | Should -Be 4321 + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'http://netbox.domain.com:4321/api/seg1/seg2/' + } + + It "Should generate a URI with parameters" { + $URIParameters = @{ + 'param1' = 'paramval1' + 'param2' = 'paramval2' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' -Parameters $URIParameters + $URIBuilder.Query | Should -BeExactly '?param1=paramval1¶m2=paramval2' + $URIBuilder.URI.AbsoluteURI | Should -BeExactly 'https://netbox.domain.com/api/seg1/seg2/?param1=paramval1¶m2=paramval2' + } + } + } + + Context "Invoking request tests" { + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Mock -CommandName 'Invoke-RestMethod' -Verifiable -MockWith { + # Return an object of the items we would normally pass to Invoke-RestMethod + return [pscustomobject]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + 'results' = 'Only results' + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + It "Should return direct results instead of the raw request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder + + Assert-VerifiableMock + + $Result | Should -BeOfType [string] + $Result | Should -BeExactly "Only results" + } + + It "Should generate a basic request" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be $URIBuilder.Uri.AbsoluteUri + $Result.Headers | Should -BeOfType [System.Collections.HashTable] + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Timeout | Should -Be 5 + $Result.ContentType | Should -Be 'application/json' + $Result.Body | Should -Be $null # We did not supply a body + } + + It "Should generate a POST request with body" { + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body @{'bodyparam1' = 'val1'} -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + } + + It "Should generate a POST request with an extra header" { + $Headers = @{ + 'Connection' = 'keep-alive' + } + + $Body = @{ + 'bodyparam1' = 'val1' + } + + $URIBuilder = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + + $Result = InvokeNetboxRequest -URI $URIBuilder -Method POST -Body $Body -Headers $Headers -Raw + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Body | Should -Be '{"bodyparam1":"val1"}' + $Result.Headers.Authorization | Should -Be "Token faketoken" + $Result.Headers.Connection | Should -Be "keep-alive" + } + + It "Should throw because of an invalid method" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Method 'Fake' + } | Should -Throw + } + + It "Should throw because of an out-of-range timeout" { + { + $URI = BuildNewURI -Hostname "netbox.domain.com" -Segments 'seg1', 'seg2' + InvokeNetboxRequest -URI $URI -Timeout 61 + } | Should -Throw + } + } + } +} + + + + + + diff --git a/dist/Tests/IPAM.Tests.ps1 b/dist/Tests/IPAM.Tests.ps1 new file mode 100644 index 0000000..ddcf174 --- /dev/null +++ b/dist/Tests/IPAM.Tests.ps1 @@ -0,0 +1,214 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/10/2018 3:41 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: IPAM.Tests.ps1 + =========================================================================== + .DESCRIPTION + IPAM Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + + +Describe -Name "IPAM tests" -Tag 'Ipam' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxIPAMAggregate" -Fixture { + It "Should request the default number of aggregates" { + $Result = Get-NetboxIPAMAggregate + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAggregate -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAggregate -Query '10.10.0.0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=10.10.0.0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAggregate -Query 'my aggregate' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?q=my+aggregate' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAggregate -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAggregate -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/aggregates/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-NetboxIPAMAddress" -Fixture { + It "Should request the default number of addresses" { + $Result = Get-NetboxIPAMAddress + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxIPAMAddress -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxIPAMAddress -Query '10.10.10.10' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=10.10.10.10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxIPAMAddress -Query 'my ip address' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?q=my+ip+address' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxIPAMAddress -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxIPAMAddress -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + #region TODO: Figure out how to mock/test Verification appropriately... + <# + It "Should request with a family number" { + Mock -CommandName 'Get-NetboxIPAMChoices' -ModuleName 'NetboxPS' -MockWith { + return @" +{"aggregate:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"prefix:status":[{"label":"Container","value":0},{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"ip-address:family":[{"label":"IPv4","value":4},{"label":"IPv6","value":6}],"ip-address:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3},{"label":"DHCP","value":5}],"ip-address:role":[{"label":"Loopback","value":10},{"label":"Secondary","value":20},{"label":"Anycast","value":30},{"label":"VIP","value":40},{"label":"VRRP","value":41},{"label":"HSRP","value":42},{"label":"GLBP","value":43},{"label":"CARP","value":44}],"vlan:status":[{"label":"Active","value":1},{"label":"Reserved","value":2},{"label":"Deprecated","value":3}],"service:protocol":[{"label":"TCP","value":6},{"label":"UDP","value":17}]} +"@ | ConvertFrom-Json + } + + Mock -CommandName 'Connect-NetboxAPI' -ModuleName 'NetboxPS' -MockWith { + $script:NetboxConfig.Connected = $true + $script:NetboxConfig.Choices.IPAM = Get-NetboxIPAMChoices + } + Connect-NetboxAPI + $Result = Get-NetboxIPAMAddress -Role 4 + + Assert-VerifiableMock + Assert-MockCalled -CommandName "Get-NetboxIPAMChoices" + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/ipam/ip-addresses/?role=4' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + #> + #endregion + } + + Context -Name "Get-NetboxIPAMPrefix" { + + } + } +} + + + + + + + + + + diff --git a/dist/Tests/Virtualization.Tests.ps1 b/dist/Tests/Virtualization.Tests.ps1 new file mode 100644 index 0000000..8174020 --- /dev/null +++ b/dist/Tests/Virtualization.Tests.ps1 @@ -0,0 +1,365 @@ +<# + .NOTES + =========================================================================== + Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150 + Created on: 5/8/2018 4:01 PM + Created by: Ben Claussen + Organization: NEOnet + Filename: Virtualization.Tests.ps1 + =========================================================================== + .DESCRIPTION + Virtualization Pester tests +#> + +Import-Module Pester +Remove-Module NetboxPS -Force -ErrorAction SilentlyContinue + +$ModulePath = "$PSScriptRoot\..\dist\NetboxPS.psd1" + +if (Test-Path $ModulePath) { + Import-Module $ModulePath -ErrorAction Stop +} + +Describe -Name "Virtualization tests" -Tag 'Virtualization' -Fixture { + Mock -CommandName 'CheckNetboxIsConnected' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return $true + } + + Mock -CommandName 'Invoke-RestMethod' -Verifiable -ModuleName 'NetboxPS' -MockWith { + # Return a hashtable of the items we would normally pass to Invoke-RestMethod + return [ordered]@{ + 'Method' = $Method + 'Uri' = $Uri + 'Headers' = $Headers + 'Timeout' = $Timeout + 'ContentType' = $ContentType + 'Body' = $Body + } + } + + Mock -CommandName 'Get-NetboxCredentials' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return [PSCredential]::new('notapplicable', (ConvertTo-SecureString -String "faketoken" -AsPlainText -Force)) + } + + Mock -CommandName 'Get-NetboxHostname' -Verifiable -ModuleName 'NetboxPS' -MockWith { + return 'netbox.domain.com' + } + + InModuleScope -ModuleName 'NetboxPS' -ScriptBlock { + Context -Name "Get-NetboxVirtualMachine" -Fixture { + It "Should request the default number of VMs" { + $Result = Get-NetboxVirtualMachine + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualMachine -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualMachine -Query 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualMachine -Query 'test vm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?q=test+vm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualMachine -Name 'testvm' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?name=testvm' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualMachine -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualMachine -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a status" { + $Result = Get-NetboxVirtualMachine -Status 'Active' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/?status=1' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineInterface" -Fixture { + It "Should request the default number of interfaces" { + $Result = Get-NetboxVirtualMachineInterface + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a limit and offset" { + $Result = Get-NetboxVirtualMachineInterface -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a interface with a specific ID" { + $Result = Get-NetboxVirtualMachineInterface -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request a name" { + $Result = Get-NetboxVirtualMachineInterface -Name 'Ethernet0' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?name=Ethernet0' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a VM ID" { + $Result = Get-NetboxVirtualMachineInterface -Virtual_Machine_Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?virtual_machine_id=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with Enabled" { + $Result = Get-NetboxVirtualMachineInterface -Enabled $true + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/?enabled=true' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineCluster" -Fixture { + It "Should request the default number of clusters" { + $Result = Get-NetboxVirtualizationCluster + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationCluster -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a query" { + $Result = Get-NetboxVirtualizationCluster -Query 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with an escaped query" { + $Result = Get-NetboxVirtualizationCluster -Query 'test cluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?q=test+cluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationCluster -Name 'testcluster' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?name=testcluster' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a single ID" { + $Result = Get-NetboxVirtualizationCluster -Id 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/10/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with multiple IDs" { + $Result = Get-NetboxVirtualizationCluster -Id 10, 12, 15 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/clusters/?id__in=10,12,15' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Get-VirtualMachineClusterGroup" -Fixture { + It "Should request the default number of cluster groups" { + $Result = Get-NetboxVirtualizationClusterGroup + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with limit and offset" { + $Result = Get-NetboxVirtualizationClusterGroup -Limit 10 -Offset 12 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?offset=12&limit=10' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a name" { + $Result = Get-NetboxVirtualizationClusterGroup -Name 'testclustergroup' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?name=testclustergroup' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + + It "Should request with a slug" { + $Result = Get-NetboxVirtualizationClusterGroup -Slug 'test-cluster-group' + + Assert-VerifiableMock + + $Result.Method | Should -Be 'GET' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/cluster-groups/?slug=test-cluster-group' + $Result.Headers.Keys.Count | Should -BeExactly 1 + } + } + + Context -Name "Add-NetboxVirtualMachine" -Fixture { + It "Should add a basic VM" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"cluster":1,"name":"testvm","status":1}' + } + + It "Should add a VM with CPUs, Memory, Disk, tenancy, and comments" { + $Result = Add-NetboxVirtualMachine -Name 'testvm' -Cluster 1 -Status Active -vCPUs 4 -Memory 4096 -Tenant 11 -Disk 50 -Comments "these are comments" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/virtual-machines/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"tenant":11,"comments":"these are comments","disk":50,"memory":4096,"name":"testvm","cluster":1,"status":1,"vcpus":4}' + } + } + + Context -Name "Add-NetboxVirtualInterface" -Fixture { + It "Should add a basic interface" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"virtual_machine":10,"name":"Ethernet0","enabled":true}' + } + + It "Should add an interface with a MAC, MTU, and Description" { + $Result = Add-NetboxVirtualInterface -Name 'Ethernet0' -Virtual_Machine 10 -Mac_Address '11:22:33:44:55:66' -MTU 1500 -Description "Test description" + + Assert-VerifiableMock + + $Result.Method | Should -Be 'POST' + $Result.Uri | Should -Be 'https://netbox.domain.com/api/virtualization/interfaces/' + $Result.Headers.Keys.Count | Should -BeExactly 1 + $Result.Body | Should -Be '{"mtu":1500,"description":"Test description","enabled":true,"virtual_machine":10,"name":"Ethernet0","mac_address":"11:22:33:44:55:66"}' + } + } + } +} + + + + + + + + + +