Thursday, May 14, 2026

Retrieving Groups from NSX-T

This might seem like a bit of a theme developing, but in my work life I'm assisting in the migration from a "standalone" vSphere environment to a VCF 9 environment, and having some of this information from the old environment is helpful for building and auditing the new environment.

So this script will dump groups from NSX-T into a CSV-formatted text. It was a fun one to code because of the way groups are handled: some sort of boolean logic—up to and including selection of objects by individual ID—is possible, and when you're mixing & matching [AND] and [OR] clauses, you are starting to nest evaluation scope, similar to the way parenthesis work in math (remember PEMDAS?).

At any rate, this code uses 'recursion,' where a function calls itself with new arguments rather than creating deeper and deeper loops. When the language permits it—and PowerShell does—it becomes a powerful tool for writing efficient and highly readable (in my experience) code. It can also create pitfalls for a coder who doesn't build in the "escape hatch" that keeps the recursion from happening infinitely, but that's an entirely different discussion.

So with the help of recursion, this script will dive into the criteria used to define group membership and assemble it all together in a single field. This is output along with the group name and any description that is available from the source environment

Get-NsxGroups.ps1

FUNCTION Decode-Expression() { # decode an individual Expression # these can come in several types, so handle each using the switch control param ( [System.Object]$expr ) switch ($expr.resource_type){ 'Condition' { $str += '(' + $expr.member_type + ' [' + $expr.key + '] ' + $expr.operator + ' "' + $expr.value.replace('|','') + '")' } 'ConjunctionOperator' { $str += ' ' + $expr.conjunction_operator + ' ' } 'NestedExpression' { # nested expressions are not individual expressions, so recurse through the nested criteria $str += Decode-Expressions($expr.expressions) } 'MACAddressExpression' { $addr_string = '' foreach ($addr in $expr.mac_addresses){ $addr_string += "$addr," } $addr_string = $addr_string.SubString(0,$addr_string.Length-1) $str += '[MAC in (' + $addr_string + ')]' } 'IPAddressExpression' { $addr_string = '' foreach ($addr in $expr.ip_addresses){ $addr_string += "$addr," } $addr_string = $addr_string.SubString(0,$addr_string.Length-1) $str += '[IP in (' + $addr_string + ')]' } 'ExternalIDExpression' { $str += ($expr.external_ids.Length.ToString() + ' explicit VMs') } default { $str += '<<unhandled>>' } } return $str } FUNCTION Decode-Expressions(){ # One or more expressions--including multi-level nesting--can be used to define # what makes a group member. # This function handles iterating and recursing through all criteria that could be in # any given expression param ( [System.Object]$expr ) $str = '' if (($expr -is [Array]) -and ($expr.Length -gt 1)){ #passed object is an array of objects for ($i = 0; $i -lt $expr.Length; $i++) { $str += Decode-Expressions($expr[$i]) } } else { if ($expr.Length) { $str += Decode-Expression($expr) } else { $str += 'No criteria set' } } return $str } $dfltNSXMGR = "default NSX manager" $nsxtManager = Read-Host ("Enter NSX-T IP or FQDN [$dfltNSXMGR]" -f $dfltNSXMGR) if (-not $nsxtManager) { $nsxtManager = "https://$dfltNSXMGR" } else { $nsxtManager = "https://$nsxtManager" } $output = Read-Host "Enter output filepath" $username = Read-Host "Enter username" $secPwd = Read-Host "Enter password" -AsSecureString $password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secPwd)) $response = Invoke-RestMethod -Uri "$nsxtManager/api/v1/infra/domains/default/groups" -Method Get -Headers @{ "Authorization" = "Basic $( [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("${username}:${password}"))) )" "Content-Type" = "application/json" } -Body '{}' -SkipCertificateCheck $grp_list = @() foreach ($grp in $response.results) { if ($grp._system_owned -ne 'false') { #ignore system-owned groups; these should be auto-created anyway $grp_name = $grp.display_name $grp_descr = $grp.description $rules = Decode-Expressions($grp.expression) $row = New-Object PSObject -Property @{ Grp = $grp.display_name Descr = $grp.description Crit = $rules } $grp_list += $row } } $grp_list | Select-Object 'Grp','Descr','Crit' | Export-CSV -Path $output -NoTypeInformation

Note: I made the decision to ignore any explicit VMs that were in these groups. It was a business decision driven by several factors:

  • There weren't many groups using this feature
  • Most groups using the feature had references to VMs that no longer existed

No comments:

Post a Comment