Hello Everyone,
In today’s edition, I’m going to share with you a script that I wrote that will do the following:
- Get all the VMs from your infrastructure
- For each VM (and each virtual nic that is connected to a portgroup), it will query
- Portgroup Name
- Portgroup VLAN Type (because we’re going to skip trunk VLANs)
- Portgroup VLAN ID
- Default gateway (here is where it gets tricky…)
- Gateway network prefix (also tricky)
Once we have all that data, we will proceed to create all of these segments (with the gateway and network prefix) inside NSX-T, using REST API calls.
By creating the segments with the gateway, we serve two great purposes
- The segment is already prepared to be connected to a T1 DR and does not need further manual editing
- Customers may not know all the gateways of all their vSphere networks, and this script will output that for you!
What do I need from you to run it?
- vCenter & NSX Manager FQDNs and credentials
- NSX-T Overlay transport zone name (the transport zone we’re going to use to create the segments)
This is the link to the script, where you can take a look at the code: https://github.com/luchodelorenzi/scripts/blob/master/createSegments.ps1
I’m going to explain it bit by bit, mostly focusing on the logic and the problems I encountered while testing it.
The end result would be something like this:
Enter vCenter FQDN: vcsa-01a.corp.local
PowerShell credential request
Enter vCenter Credentials
User: administrator@vsphere.local
Password for user administrator@vsphere.local: ********
Enter NSX Manager FQDN: nsxapp-01a.corp.local
PowerShell credential request
Enter NSX Credentials
User: admin
Password for user admin: ****************
Enter NSX Overlay Transport Zone name: nsx-overlay-transportzone
Name Port User
---- ---- ----
vcsa-01a.corp.local 443 VSPHERE.LOCAL\Administrator
Querying data for rdsh-01a ...
Querying data for log-01a ...
Querying data for web-01a ...
Querying data for vm-01a ...
Querying data for app-01a ...
Querying data for web-02a ...
Querying data for edgenode-01a ...
############################################################
Found the following possible segments in your infrastructure
Portgroup PG-WEB with VLAN 100 gateway 172.16.10.1 and prefix length 24
Portgroup PG-VM with VLAN 200 gateway 172.16.101.1 and prefix length 24
Portgroup PG-APP with VLAN 300 gateway 172.16.20.1 and prefix length 24
Would you like to Create these segments on NSX-T?
( y / n ) : y
Yes, create segments
found transport zone id: 1b3a2f36-bfd1-443e-a0f6-4de01abc963e
Creating Segment PG-WEB-VLAN100-GW-172.16.10.1 on transport zone nsx-overlay-transportzone
Creating Segment PG-VM-VLAN200-GW-172.16.101.1 on transport zone nsx-overlay-transportzone
Creating Segment PG-APP-VLAN300-GW-172.16.20.1 on transport zone nsx-overlay-transportzone

So let’s start breaking the script up in parts…
Part 1 – Getting FQDNs and Credentials
This is pretty self explanatory, we’re just getting the FQDNs and credentials and saving them into variables.
$vcenter=Read-Host "Enter vCenter FQDN"
$vccredential = Get-Credential -message "Enter vCenter Credentials"
$nsxmanager=Read-Host "Enter NSX Manager FQDN"
$nsxcredential = Get-Credential -message "Enter NSX Credentials"
$overlayTransportZone = Read-Host "Enter NSX Overlay Transport Zone name"
Connect-VIServer -Server $vcenter -credential $vccredential
Part 2 – Exporting Data from VMs
So what are we doing here?
- We’re iterating through every VM in the infrastructure, and getting the IP stack (which is part of the extensiondata.guest object, therefore, being read from VMware tools – This would be empty if this VM does not have VMware tools running)
- We’re getting the device (virtual nic) that has the portgroup with the default gateway (this is needed in the scenario of multiple virtual nics and multiple portgroups)
This is important because the VMware tools data is not available in vSphere, so we need to do the mapping ourselves. - We filter stuff out that we don’t need, such as:
- Any network with less than 6 characters (ipv6 empty network)
- Any network that does not have “.” on the address (so no ipv4)
- Any prefix length that is 0 or 32 (useless in this scenario, this is not the gateway network)
- Any network that starts with 224. or 169.254
After having filtered that, we’re going to have our gateway and network prefix, so what’s next?
- Using the device, we get the portgroup that we’re going to use, and from that portgroup, we get the VLAN configuration and VLAN ID, and we discard it if it is a trunk portgroup
- We will also discard the portgroup if it contains “vxw-dvs” because this will mean it is a NSX-V portgroup and won’t be VLAN backed
- We create a new object that will contain:
- Portgroup Name
- Portgroup VLAN ID
- Gateway
- Network prefix
- And we add this object to an array of objects
foreach ($vm in $vms) {
$networkObject = "" | Select Portgroups,Gateway,Prefix
$networkObject.Portgroups = ($vm | Get-NetworkAdapter | Get-VDPortgroup)
Write-Host Querying data for $vm...
if ($vm.extensiondata.guest.ipstack){
$device = ($vm.extensiondata.guest.ipstack[0].iprouteconfig.iproute | where {$_.network -eq "0.0.0.0"}).gateway.device
$networkObject.gateway = ($vm.extensiondata.guest.ipstack[0].iprouteconfig.iproute |
where {$_.network -eq "0.0.0.0"}).gateway.ipaddress
$networkObject.Prefix = ($vm.extensiondata.guest.ipstack[0].iprouteconfig.iproute |
where {$_.network.length -gt 6} | where {$_.network -like "*.*"} |
where {$_.prefixlength -ne 32} | where {$_.network.substring(0,4) -ne "224."} |
where {$_.prefixlength -ne 0} | where {$_.network.substring(0,8) -ne "169.254."} |
where {$_.gateway.device -eq $device}).prefixlength
if (($vm | Get-NetworkAdapter)[$device]){
$pg = ($vm | Get-NetworkAdapter)[$device] | get-vdportgroup
}
$PGObject = "" | Select Name, VLAN, Gateway, PrefixLength
$PGObject.Name = $pg.name
$PGObject.VLAN = $pg.VlanConfiguration.VlanId
$PGObject.Gateway = $networkObject.Gateway
$PGObject.PrefixLength = $networkObject.Prefix
#Skip Trunk vLAN
if ($pg.VlanConfiguration.vlantype -ne 'Trunk' -and $pg.name -notlike "*vxw-dvs*" -and $pg.name -ne $null){
$PossibleSegments += $PGObject
}
}
Part 3 – Parsing the data
We have an array of objects that have all the data we need, but this will likely have many repeated entries, since a lot of VMs are going to be using the same portgroup and same gateway. We could use a single entry per portgroup, but this will not be ideal.
There is nothing stopping anyone from using multiple networks inside a same portgroup and VLAN, so the ‘uniqueness’ of the segment will be given by a combination of the portgroup as well as the gateway
In that way, we will have all the data we need and won’t discard anything useful!
$UniqueSegments = $PossibleSegments | Where {$_.Gateway -ne $null} | sort-object -Property @{E="Name"; Descending=$True}, @{E="Gateway"; Descending=$True} -unique
Write-Host "############################################################"
Write-Host "Found the following possible segments in your infrastructure"
$uniqueSegments | % {
Write-Host Portgroup $_.name with VLAN $_.VLAN, gateway $_.gateway and prefix length $_.prefixlength
}
Part 4 – Pushing the data to NSX-T
So now that we have our array of segment objects fully sorted out and having unique entries, we need to push it to NSX-T
Remember at the beginning I asked for the NSX-T Overlay Transport zone? We’re going to need the transport zone ID
NSX-T 3.0 Rest API – List transport zones
So with the name, we can execute that API call and get the transport zone ID, to use it in the create segment API call!
NSX-T 3.0 Rest API – Create Segment
$getTzUrl = "https://$nsxmanager/api/v1/transport-zones"
$getTzRequest = Invoke-RestMethod -Uri $gettzurl -Authentication Basic -Credential $nsxcredential -Method get -ContentType "application/json" -SkipCertificateCheck
$gettzrequest.results | % {
if ($_.display_name -eq $overlayTransportZone){
$overlayTzId = $_.id
Write-Host found transport zone id: $overlayTzId
}
}
foreach ($segment in $uniqueSegments)
{
$segmentDisplayName = $segment.name + "-VLAN" + $segment.VLAN + "-GW-" + $segment.gateway
$Body = @{
display_name = $segmentDisplayName
subnets = @(
@{
gateway_address = $segment.gateway + "/" + $segment.prefixlength
}
)
transport_zone_path="/infra/sites/default/enforcement-points/default/transport-zones/$overlayTzId"
}
$jsonBody = ConvertTo-Json $Body
Write-Host "Creating Segment $segmentDisplayName on transport zone $overlayTransportZone"
$patchSegmentUrl = "https://$nsxmanager/policy/api/v1/infra/segments/" + $segmentDisplayName
$patchRequest = Invoke-RestMethod -Uri $patchSegmentUrl -Authentication Basic -Credential $nsxCredential -Method patch -body $jsonBody -ContentType "application/json" -SkipCertificateCheck
}
}
Conclusion
I hope you find this script useful – It should GREATLY improve times in fresh NSX-T deployments, not only by quickly creating all the segments automatically, but also since it does all the hard work of exporting all the gateway and prefix configuration, which can be super tedious!
If you have any questions regarding the script, please leave it on the comments below and I’ll address it
If you found any bugs or errors or better ways to accomplish the same thing, please also leave a comment! It will also be super helpful!
Cheers,