Leave us your email address and be the first to receive a notification when Robin posts a new blog.
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:
$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')
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.
$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)

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.
$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)

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.

Final function
To be able to run this script some additional logging is required, for the ID for the group and the VM.
#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)
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.
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.