# Powershell refuses to connect to the Netbox API on our setup without this. add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ########################## # Fill out these settings ########################## # Some useful settings. $token = "" $uri = "http://netbox.domain.tld/api" $hyperVHost = "hyper-v-host.domain.tld" # These are some ID's in Netbox # We added a "Hyper-V" (id 3) cluster type. This needs to match yours! # id 25 for us corresponds to the role "Server". $NetboxHyperVClusterType = 3 $NetboxServerRoleID = 25 # Source: https://www.reddit.com/r/PowerShell/comments/8u14wl/check_a_list_of_ips_against_a_list_of_subnets/e1brhe3/ function Test-IPInSubnet { [CmdletBinding()] param( [Parameter( Position = 0, Mandatory, ValueFromPipelineByPropertyName )][ValidateNotNull()][System.Net.IPAddress]$Subnet, [Parameter( Position = 1, Mandatory, ValueFromPipelineByPropertyName )][Alias('Mask')][ValidateNotNull()][System.Net.IPAddress]$SubnetMask, [Parameter( Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName )][Alias('Address')][ValidateNotNull()][System.Net.IPAddress]$IPAddress ) process { $Subnet.Address -eq ($IPAddress.Address -band $SubnetMask.Address) } } function Add-NetboxIP { [CmdletBinding()] param ( [Parameter()][System.Net.IPAddress]$ip, [Parameter()][String]$mask ) $id = Get-NetboxIP -ip $ip -mask $mask if(-not $id) { # Add the IP and return the resulting Id Write-host "[$($vm.name)] Adding new ip address object for $ip." $ipconcat=$ip + "/" + "$mask" $id = ((Invoke-WebRequest -Uri "$uri/ipam/ip-addresses/" -Method POST -Headers $headers -Body $(@{address=$ipconcat} | Convertto-json)).content | convertfrom-json).id } return $id } function Add-NetboxVM { [CmdletBinding()] param ( [Parameter()][Microsoft.HyperV.PowerShell.VirtualMachine]$vm, [Parameter()][String]$roleId, [Parameter()][String]$clusterId ) # Get or add the VM to Netbox $id = Get-NetboxVM -name $vm.name $virtualMachineBody = $(@{ name=$($vm.VMName) cluster=$clusterId status=$(if($vm.state -eq "Running") {"active"} else {"offline"}) role=$roleId vcpus=$($vm.ProcessorCount) memory=$(if($vm.DynamicMemoryEnabled){$vm.MemoryMaximum/1MB}else{$vm.MemoryStartup/1MB}) disk=$(((($vm.HardDrives | Get-VHD -computername $hyperVHost).Size) | Measure-Object -Sum).Sum/1GB) } | ConvertTo-Json) if (-not $id) { # Create Write-host "[$($vm.name)] Creating new VM." $id = ((Invoke-WebRequest -uri "$uri/virtualization/virtual-machines/" -Method POST -Body $virtualMachineBody -Headers $headers).content | convertfrom-json).id } else { # Update Write-host "[$($vm.name)] Updating existing VM with id $id." $id = ((Invoke-WebRequest -uri "$uri/virtualization/virtual-machines/$id/" -Method PATCH -Body $virtualMachineBody -Headers $headers).content | convertfrom-json).id } return $id } function Add-NetboxNetworkInterface { [CmdletBinding()] param ( [Parameter()][Microsoft.HyperV.PowerShell.VMNetworkAdapter]$networkAdapter, [Parameter()][String]$virtualMachineId ) $id = Get-NetboxNetworkInterface -networkAdapter $networkAdapter -virtualMachineId $virtualMachineId if(-not $id) { $id = ((Invoke-WebRequest -Uri "$uri/virtualization/interfaces/" -method Post -Headers $headers -body $(@{name=$networkAdapter.name;virtual_machine=$virtualMachineId;mac_address=$networkAdapter.macaddress} | Convertto-json)).content | convertfrom-json).id } return $id } function Add-NetboxIPNetworkInterfaceAssociation { [CmdletBinding()] param ( [Parameter()][String]$networkInterfaceId, [Parameter()][String[]]$ipList ) foreach($ipId in ($ipList | Where-Object {($null -ne $_) -and ($_ -notlike "fe80*")})) { Write-host "[$($vm.name)] Creating interface $networkInterfaceId association with ip $ipId." $result = Invoke-WebRequest -Uri "$uri/ipam/ip-addresses/$ipId/" -Method Patch -Headers $headers -Body $(@{assigned_object_type="virtualization.vminterface";assigned_object_id=$networkInterfaceId}| ConvertTo-Json) } } function Add-NetboxCluster { [CmdletBinding()] param ( [Parameter()][String]$name ) Write-Host -foregroundcolor yellow "[$name] The cluster doesn't exist. Let's add it !" return ((Invoke-WebRequest -Uri "$uri/virtualization/clusters/" -Method Post -Body $(@{name=$name;type=$NetboxHyperVClusterType}| Convertto-json) -Headers $headers).content | convertfrom-json).id } function Get-NetboxCluster { [CmdletBinding()] param ( [Parameter()][String]$name ) Write-host "[$name] Looking for a matching cluster." try { return ((Invoke-WebRequest -Uri "$uri/virtualization/clusters/?name=$name" -Method Get -Headers $headers).content | convertfrom-json).results[0].id } catch { Write-host "[$name] No match found." return $null } } function Get-NetboxVM{ [CmdletBinding()] param ( [Parameter()][String]$name ) Write-host "[$($vm.name)] Looking for a matching VM." try { return ((Invoke-WebRequest -uri "$uri/virtualization/virtual-machines/?q=$name" -Method Get -Headers $headers).content | convertfrom-json).results[0].id } catch { Write-host "[$($vm.name)] No match found" return $null } } function Get-NetboxIP { [CmdletBinding()] param ( [Parameter()][System.Net.IPAddress]$ip, [Parameter()][String]$mask ) $ipconcat="$ip" + "/" + "$mask" Write-host "[$($vm.name)] Looking for a ip matching $ipconcat." try { return ((Invoke-WebRequest -Uri "$uri/ipam/ip-addresses/?q=$ipconcat" -Headers $headers -Method Get).content | convertfrom-json).results[0].id } catch { Write-host "[$($vm.name)] $ipconcat : no match found." return $null } } function Get-NetboxIPAMPrefixes { Write-host -ForegroundColor Cyan "Getting Netbox IP prefixes" return ((Invoke-WebRequest -Uri "$uri/ipam/prefixes/" -Method Get -Headers $headers).content | convertfrom-json).results } function Get-NetboxNetworkInterface { [CmdletBinding()] param ( [Parameter()][Microsoft.HyperV.PowerShell.VMNetworkAdapter]$networkAdapter, [Parameter()][String]$virtualMachineId ) Write-host "[$($vm.name)] Looking for a network interface matching VM with id $virtualMachineId." try { return (((Invoke-WebRequest -uri "$uri/virtualization/interfaces/?virtual_machine_id=${virtualMachineID}" -Method Get -Headers $headers).content | convertfrom-json).results | Where-Object {$_.name -eq $networkAdapter.name}).id } catch { Write-host "[$($vm.name)] No existing interfaces found that match." return $null } } function Get-HyperVClusterName { # If we're not in a cluster, we use "Standalone - $Hostname" as a cluster name instead. # We try to see if the cluster exists, if it does, we take it's ID for later. If not, we create it. Write-host -foregroundcolor cyan "[$hyperVHost] Trying to determine if server is part of a cluster..." $clusterName = (Get-Cluster -Domain $($env:USERDNSDOMAIN) | Get-ClusterNode | where-object {$_.Name -eq $hyperVHost}).Cluster.name if($null -eq $clusterName) { Write-Host -foregroundcolor cyan "[$hyperVHost] Host is standalone" $clusterName = "Standalone-$hyperVHost" } return $clusterName } function Get-MaskFromPrefix { [CmdletBinding()] param ( [Parameter()][String]$prefix ) $MaskLength = $prefix.split('/')[1] [System.Net.IPAddress] $mask = 0 $mask.Address = ([UInt32]::MaxValue) -shl (32 - $MaskLength) -shr (32 - $MaskLength) #Write-host "[$($vm.name)] Mask for network prefix $($prefix.split('/')[1]) is $mask." return $mask } function Get-NetboxPrefixFromIP { [CmdletBinding()] param ( [Parameter()][System.Net.IPAddress]$ip ) Write-host "[$($vm.name)] Looking for a subnet matching ip $ip." foreach($prefix in $prefixes) { $mask = Get-MaskFromPrefix -prefix $prefix.prefix #Write-host "$($prefix.prefix) has $mask" if(Test-IPInSubnet -IPAddress $ip -Subnet $prefix.prefix.split('/')[0] -SubnetMask $mask) { write-host -ForegroundColor Green "[$($vm.name)] Match found : $ip matches subnet $($prefix.prefix.split('/')[0])" return $prefix.prefix.split('/')[1] } } return $null } function Get-HyperVVMNics { [CmdletBinding()] param ( [Parameter()][String]$vmname ) Write-host "[$($vm.name)] Getting network interface list." return Get-VMNetworkAdapter -VMName $vm.Name -computername $hyperVHost } function Set-NetboxCluster { [CmdletBinding()] param ( [Parameter()][String]$name ) Write-host "[$name] Setting cluster variable." $id = Get-NetboxCluster($name) if($null -eq $id) { Write-host "[$name] Cluster does not exists - adding." $id = Add-NetboxCluster($name) } return $id } function Set-NetboxVMPrimaryIP { [CmdletBinding()] param ( [Parameter()][String]$virtualMachineId, [Parameter()][String]$ipId ) Write-host "[$($vm.name)] Setting primary IP to id $ipId for VM $virtualMachineId" $result = Invoke-WebRequest -uri "$uri/virtualization/virtual-machines/$virtualMachineId/" -Method Patch -Headers $headers -Body $(@{primary_ip4=$ipId} | ConvertTo-Json) } ######################################### # Script starts here ######################################### # Set API Headers $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Authorization", "Token $token") $headers.Add("Content-Type", 'application/json') $headers.Add("Accept", 'application/json') # Prepare the common variables $clusterName = Get-HyperVClusterName $clusterId = Set-NetboxCluster($clustername) $prefixes = Get-NetboxIPAMPrefixes $vms = Get-VM -computername $hyperVHost foreach($vm in $vms) { $virtualMachineId = Add-NetboxVM -vm $vm -clusterId $clusterId -roleId $NetboxServerRoleID $virtualMachineIPList = @() # Foreach interface, create the IP, create the nic and create the association foreach($nic in (Get-HyperVVMNics -vmname $vm.name)) { $ipList = @() foreach ($ip in $nic.IPAddresses | Where-Object {($null -ne $_) -and ($_ -notlike "fe80*")}) { $ipList += Add-NetboxIP -ip $ip -mask (Get-NetboxPrefixFromIP -ip $ip) } $nicId = Add-NetboxNetworkInterface -networkAdapter $nic -virtualMachineId $virtualMachineId Add-NetboxIPNetworkInterfaceAssociation -networkInterfaceId $nicId -ipList $ipList $virtualMachineIPList += $ipList } # Set the ip from the first interface as being the primary ipv4 if($virtualMachineIPList -ne @()) { Set-NetboxVMPrimaryIP -virtualMachineId $virtualMachineId -ipId ($virtualMachineIPList | Where-Object {$null -ne $_})[0] } }