NSX-T PowerCLI Add a VM to a Group - part 2

Submitted by Robin van Altena on Mon, 03/14/2022 - 07:02
 
 
Follow your favourite author

Leave us your email address and be the first to receive a notification when Robin posts a new blog.

NSX-T PowerCLI Add a VM to a Group - part 2
Mon 14 Mar, 2022
It is the most frustrating thing when you can’t seem to script a presumably easy task. As described in the first part of this blog, we needed a simple script to add multiple virtual machines (VM's) to several security groups in NSX-T. Easy right? But scripting turns out to be a little more complex, as you might have guessed already. In this blog I hope to show you a script to accomplish this task.
Textarea

What do we know so far? What have we learned from the first part of this blog.

Groups may contain different member types. These member types are defined by different expressions in NSX-T. To add a VM to a group we need to know if there is already an expression present. If not, we need to add one for the VM's. If an expression is already present, we need to know if it is an expression for VM's or for any other type of resource like; IP-address or dynamic criteria.

The different expressions are defined by member_type and resource_type. The different member types are:

  • VirtualMachine
  • VirtualNetworkInterface
  • CloudNativeServiceInstance
  • PhysicalServer

For this blog we will be focusing on the member_type VirtualMachine. As you may have seen in the first part of this blog both the dynamic criteria and the static VM membership use this member_type. Therefore, the resource_type is also important to be able to add VM's to a group. The different resource_types are:

  • Condition - for Dynamic Membership
  • ConjunctionOperator - for multiple expressions
  • NestedExpression
  • IPAddressExpression - for IP-addresses
  • MACAddressExpression - for MAC-addresses
  • ExternalIDExpression - for Virtual Machines
  • PathExpression - for other groups
  • IdentityGroupExpression - for Active Directory groups

For this script we need to use the ExternalIDExpression and include the external_ids of the VM's.

To complete the script, we need to gather some input. 1. The ID of the group we want to modify. 2. The (external) ID of VM we want to add to the group. 3. To find out if there is an expression and of what type.

Gathering information

After the connection to the NSX-T manager has been made with PowerCLI. The information about the group and the VM can be retrieved in multiple ways. You can use the search option or add all group to an array and get the ID from there. To list all VM's or groups I use:
 

Code (new)

$GroupsData = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups
$GroupsList = $GroupsData.list('default')

$InventoryData = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.realized_state.enforcement_points.virtual_machines
$InventoryVMs = $InventoryData.list('default')

Textarea

And add the results to an array, to be able to search for the ID's. But be aware that these only show the first 1000 entries. An option is to use the cursor value in the returned data or use the search function.
 

Adding a VM to a group with no expressions

If the group has no members whatsoever, the task is relatively simple. We can see if there are any expressions by doing a count on the expressions of a group.

We just need to add a new expression with member_type VirtualMachine and resource_type ExternalIDExpression. The external ID of the VM or VM's needs to be added as an array. To generate the ID for the expression I’m using the New-Guid function in Powershell.
 

Code (new)

$ArrExt_ids = New-Object System.Collections.ArrayList
$ArrExt_ids.Add($VMid)

$GroupExtIDExp = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups.external_id_expressions
$GroupExtIDExpNew = $GroupExtIDExp.help.patch.external_ID_expression.create()
$GroupExtIDExpNew.member_type = 'VirtualMachine'
$GroupExtIDExpNew.external_ids = $ArrExt_ids
$GroupExtIDExpNew.resource_type = 'ExternalIDExpression'
$GroupExtIDExpNew.id = New-Guid

$GroupExtIDExp.patch('default', $Groupid, $GroupExtIDExpNew.id, $GroupExtIDExpNew)

Image
Adding a VM to a group without any members
Textarea

Adding a VM to a group which already has VM members

This part of the function I already described in the first part of this blog. In this case we need to update the existing extension by adding the external ID of the VM we want to add to the array of external ID's. In the example below I’m adding the external ID for a second VM named tstlab-test6 to the same group as in the previous example.

Code (new)

$GroupsData = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups
$Group = $GroupsData.get('default', 'AL_Empty')
$ExtIDExp = $Group.expression

$ArrExt_ids = New-Object System.Collections.ArrayList
foreach ($external_id in $ExtIDExp.external_ids)
{ArrExt_ids.Add($external_id.value)}
$ArrExt_ids.Add('502769f5-822b-7461-898d-6fd91ad09490')

$GroupExtIDExpNew = $GroupExtIDExp.help.patch.external_ID_expression.create()
$GroupExtIDExpNew.member_type = 'VirtualMachine'
$GroupExtIDExpNew.external_ids = $ArrExt_ids
$GroupExtIDExpNew.resource_type = 'ExternalIDExpression'
$GroupExtIDExpNew.id = $ExtIDExp.id

$GroupExtIDExp.patch('default', 'AL_Empty', $GroupExtIDExpNew.id, $GroupExtIDExpNew)

Image
Adding a VM to a group that already has VM's as members
Textarea

Adding a VM to group which already has other member types (None VM)

The last part is relatively simple. NSX-T adds the required conjunction operator for us. So, this part is like adding a VM to a group without any expressions. In the initial script we created, we also added the conjunction operator which made it a little more complex, but both seem to work.

Image
Adding an expression to a group with an existing expression
Textarea

Final function

To be able to run this script some additional logging is required, for the ID for the group and the VM.

Code (new)

#Check if Groupid has Extension External_ids
$Groups = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups
$GroupExtIDExp = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups.external_id_expressions

$Group = $Groups.get('default', $Groupid)
$GroupExtIDExpOld = $Group.expression

if ($GroupExtIDExpOld.count -eq '0')
{
               #Group does not have an External_ids Expression
               $ArrExt_ids = New-Object System.Collections.ArrayList
               $ArrExt_ids.Add($VMid)

               $GroupExtIDExpNew = $GroupExtIDExp.help.patch.external_ID_expression.create()               $GroupExtIDExpNew.member_type = 'VirtualMachine'
               $GroupExtIDExpNew.external_ids = $ArrExt_ids
               $GroupExtIDExpNew.resource_type = 'ExternalIDExpression'
               $GroupExtIDExpNew.id = New-Guid

               #Updating Group with new VM members
               $GroupExtIDExp.patch('default', $Groupid, $GroupExtIDExpNew.id, $GroupExtIDExpNew)
}
Else
{
               #Group already has an External_ids Expression - Check/Modify
               if ($GroupExtIDExpOld.member_type -eq 'VirtualMachine' -and $GroupExtIDExpOld.resource_type -eq 'ExternalIDExpression')
               {
                              #Group already has one VirtualMachine External_ids Expression – Modify
                              ForEach ($ExtIDExp in $GroupExtIDExpOld | where {$_.member_type -eq 'VirtualMachine'-and $_.resource_type -eq 'ExternalIDExpression'})
                              {
                                             #Modify expression
                                             $ExtIDExp
                                             $ArrExt_ids = New-Object System.Collections.ArrayList
                                             foreach ($external_id in $ExtIDExp.external_ids)
                                             {
                                                            #Adding external_id for VM
                                                            $ArrExt_ids.Add($external_id.value)
                                             }
                                             $ArrExt_ids.Add($VMid)

                                             $GroupExtIDExpNew = $GroupExtIDExp.help.patch.external_ID_expression.create()
                                             $GroupExtIDExpNew.member_type = 'VirtualMachine'
                                             $GroupExtIDExpNew.external_ids = $ArrExt_ids
                                             $GroupExtIDExpNew.resource_type = 'ExternalIDExpression'
                                             $GroupExtIDExpNew.id = $ExtIDExp.id

                                             $GroupExtIDExp.patch('default', $Groupid, $GroupExtIDExpNew.id, $GroupExtIDExpNew)
                              }
               }
               Else
               {
                              #Group has one External_ids Expression other then VirtualMachine - Add one

                              $ArrExt_ids = New-Object System.Collections.ArrayList
                              $ArrExt_ids.Add($VMid)


                              $GroupExtIDExpNew = $GroupExtIDExp.help.patch.external_ID_expression.create()
                              $GroupExtIDExpNew.member_type = 'VirtualMachine'
                              $GroupExtIDExpNew.external_ids = $ArrExt_ids
                              $GroupExtIDExpNew.resource_type = 'ExternalIDExpression'
                              $GroupExtIDExpNew.id = New-Guid
                              $GroupExtIDExp.patch('default', $Groupid, $GroupExtIDExpNew.id, $GroupExtIDExpNew)
               }
}

#Updating Group with new VM members

$GroupExtIDExp.patch('default', $Groupid, $GroupExtIDExpNew.id, $GroupExtIDExpNew)

Textarea

Of course, the script can be extended to add multiple VM's at the same time, by adding more VM's to the array of external ID's before adding the array to the expression and executing the patch() command at the end. Further we added some additional logging to keep track of what the script is doing and logging it so we can review it later.

Again, I’m not a PowerShell or scripting guru. So, test this before using it in your environment. I also think the function can be optimized or improved, but hopefully this script will help you getting the job done without our initial frustration getting this to work. It took us quite some time to get everything working. We built the first script around the API call that updates the entire group.

PUT /policy/api/v1/infra/domains/<domain-id>/groups/<group-id>

In that case you also need to create the conjunction operator. We probably should have used:

PATCH /policy/api/v1/infra/domains/<domain-id>/groups/<group-id>/external-id-expressions/<expression-id>

But that's always the case when working under a time pressure. You'll end up with some sort of tunnel vision to get things working (not sure if the saying is the same in English as in Dutch though). If you have any remarks or improvements, please send me a message or contact me thru another method.

Tags

Questions, Remarks & Comments

If you have any questions and need more clarification, we are more than happy to dig deeper. Any comments are also appreciated. You can either post it online or send it directly to the author, it’s your choice.
Let us know  

 
 
Questions, Remarks & Comments

Message Robin directly, in order to receive a quick response.

More about RedLogic