Skip to content

Instantly share code, notes, and snippets.

@InputObject2
Last active April 26, 2024 09:14
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save InputObject2/6ccea46b28ae6baf07b3896e058afbf5 to your computer and use it in GitHub Desktop.
Save InputObject2/6ccea46b28ae6baf07b3896e058afbf5 to your computer and use it in GitHub Desktop.
# 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 = "<netbox 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]
}
}
@InputObject2
Copy link
Author

InputObject2 commented Nov 8, 2021

@evant89 I updated it, it's working with my Hyper-V 2016 and Netbox v2.10.4

Just gotta update the lines 17-25

@evant89
Copy link

evant89 commented Nov 8, 2021

@evant89 I updated it, it's working with my Hyper-V 2016 and Netbox v2.10.4

Just gotta update the lines 17-25

Thanks a lot

@InputObject2
Copy link
Author

@evant89 it wasn't working as well as I remembered and it was clunky so I remade it with a bunch of small functions to make it more easily readable and upgradable.

I've added the ip/network interface attachment, maybe I'll add the vlan tagging/access mode from the interfaces.

@evant89
Copy link

evant89 commented Nov 15, 2021

@PulseBright Hi. that would be a good idea. Now I'm testing your script on netbox 3.x and there are some issues
thanks for you help

@swe-mbernhard
Copy link

@evant89 Any chance of making a version for system center vmm? I can't seem to get the network mask part working, and in scvmm you can retreive the network mask and prefix instead of doing the workaround of digging into netbox prefixes and look for a match.

@JordanRN
Copy link

JordanRN commented Mar 2, 2023

Resolved some IPAM issues by changing lines;
67 to $ipconcat="$ip/$mask"
168 to $ipconcat="$ip/$mask"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment