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

Submitted by Robin van Altena on Wed, 02/23/2022 - 07:07
 
 
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 1
Wed 23 Feb, 2022
It is the most frustrating thing when you can’t seem to script a presumably easy task. A couple of weeks ago I was assisting a customer and we needed a simple script to add multiple virtual machines (VMs) to several security groups in NSX-T. In the GUI, adding a VM to a security group is a relatively easy task. But scripting it turns out to be a little more complex. But why?
Textarea

If you have read some of my previous scripting blogs, you know that Robert and I have a little battle going on about which method of scripting against NSX-T is better. Direct API calls or PowerCLI? When we were creating a script to add VM's to an NSX-T Security Group I had to agree with Robert. The method of using direct API calls is easier to use and more accessible when getting started with scripting against NSX-T. For both methods there aren’t many examples available on the internet for this specific task. But the NSX-T API guide is well documented and the JSON payload created by a script can be tested using a tool like Postman.

For the PowerCLI module Get-NsxtPolicyService the documentation is included in the module and the errors aren’t always as easy to interpret. Especially if you are not a developer, like me. So hopefully this blog will add to the shared knowledge on the internet.

A little warning in advance, if you are looking for the script to add a VM to a group. You’ll have to skip to the second part of this blog. In this part I’m explaining the process and the structure of the group.

Back to our problem at hand, we needed a script to add about 1000 VM's to more than 100 different groups. To avoid manual error and RSI injuries we decided a script was needed.

With the time constraint on hand I was very glad that Robert had already done some work with handling JSON files and API calls. But still we had some trouble getting the script to work and I want to explain why. Currently there aren’t many examples available regarding this task. So, we had to reverse engineer the working of the Groups.

I was able to do this using PowerCLI, but I was unable to add a new VM to an empty group. Together we built the script using a combination of gathering the information using PowerCLI and updating the group through a direct API call. After it was finished, and a few nights rest later, I was able to completely create the script using PowerCLI instead. Let me show you how.

How NSX-T Security Groups are built up

To explain the issues we ran into, I want to show how the groups are build up in NSX-T. Of course, I’m doing this through the PowerCLI module. With the Get-NsxtPolicyService module a list of the groups can be retrieved using:

Code (new)

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

Textarea

Note that this method only lists the first 1000 results. See NSX-T Powercli Search.

A specific group can then be retrieved using:

Code (new)

$Groups.get(<domain_id>, <group_id>) or
$Groups.get('default', 'Testt-addvm')

Textarea

This retrieves the group with the display name AL_addvm. I used a different ID and display name to make my script more robust. Since the ID and display_name isn’t always the same value. As you can see in the composed screenshot below, this group has a dynamic membership and some static members including two VM's.

Member of the group AL_addvm
Textarea

This is also the major reason with the issues we had creating the script. Because a group can have many different types of members. Like other Security groups, VM's, Active Directory groups, IP-address and dynamic criteria. In NSX-T these types of members are added to a group as an expression. These expressions can be viewed through the API or using PowerCLI.

Code (new)

$Groups.get('default', 'Testt-addvm').expression

Image
Expressions for an NSX-T security group
Textarea

As you can see this group contains three different expressions combined with OR conjunction operators. To be able to add a VM to a security group we need to know how many expressions there are and what the type of each expression is. And if things aren’t difficult enough, we found that the dynamic membership option also uses the member_type VirtualMachine. As shown in the screenshot above. Fortunately, there is also a resource_type which is different for both.

Finding the right expression

The first step in adding a VM to a group is to find out if the group already has an expression. This can be done with the count option.

Code (new)

$Group = $Groups.get('default', 'Testt-addvm').expression
$Group.count

Image
Counting the expressions
Textarea

If there are zero expressions an expression with the resource_type ExternalIDExpression can be added. I’ll show that in the second part of this blog.

If there are expressions the next step is to find out if the group already has an expression with the resource_type ExternalIDExpression. For example, this lists the external_ids of the VM's that are member of the group I’m working with.

Code (new)

$OldExp = $Groups.get('default', 'Testt-addvm').expression
if ($OldExp.member_type -eq 'VirtualMachine' -and $OldExp.resource_type -eq 'ExternalIDExpression') {$OldExp.external_ids}

Image
Listing the VM members of a group using PowerCLI
Textarea

If there already is an expression resource_type ExternalIDExpression we can modify it. If there are other expressions but not of this resource_type we need to add it, including one with the resource_type ConjunctionOperator. Again, I’ll show adding a new expression in the second part of this blog.

Adding a VM to a group with existing static VM's

If a group already has some VM's as static members, meaning they are part of the expression with resource_type ExternalIDExpression, then you can use the patch function to update the ExternalIDExpression. This can be done with the API call or with the PowerCLI Get-NsxtPolicyService module:

Code (new)

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

PowerCLI
$GroupExtIDExp = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups.external_id_expressions

Textarea

To be able to patch the external_id_expressions we need to retrieve the ID of the expression containing the external ID.

Code (new)

$OldExp = $Groups.get('default', 'Testt-addvm').expression

foreach ($Exp in $OldExp| where {$_.member_type -eq 'VirtualMachine' -and $_.resource_type -eq 'ExternalIDExpression'}) {$Exp.id}

Image
Help for the patch function and the ID of the expression
Textarea

As shown in the screenshot above you need the domain_id, group_id, expression_id and the external_id_expression. The required fields of the expression are listed at the bottom of the screenshot.

To add the VM you need the external_id of the VM and the existing VM's. So, it can be added as an array of external_ids to the expression. To demonstrate I’m going to add the external_id ‘50279d18-cb47-3319-0cd7-c1f4a0e427da’. This is the external_id for a VM called tstlab-test5 in our lab. I have created an array containing the external ids called $Arrexternal_ids. I know not a fancy name for an array.

Code (new)

$Exp = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups.external_id_expressions
$Expnew = $Exp.help.patch.external_ID_expression.create()
$ExpNew.member_type = 'VirtualMachine'
$ExpNew.external_ids = $Arrexternal_ids
$ExpNew.resource_type = 'ExternalIDExpression'
$ExpNew.id = '61e2e863-3a4e-4c7a-a133-2040a14579df'

$Exp.patch('default', 'Testt-addvm', $ExpNew.id, $ExpNew)

Image
Adding an external_id to an existing expression
Textarea

If you look at the code above the screenshot you can see that the expression_id is different from the one in the previous screenshots. Sometimes the expression_id gets updated when the group is modified. So, retrieve the ID just before you want to modify it, otherwise some strange things can happen.

I’ll continue building the script in the second part of this blog, but first I want to show you why you need to do some thorough testing before using it at scale in a production environment.

Messing up the group

With scripting you can do a lot of good, but you can also mess things up. For example, what happens if I create a second expression with the same VM's but with a different expression_id?

Image
Duplicate VM's in a Security group
Textarea

Indeed, it looks like there are multiple VM's with the same name member of this group. On the ‘Effective Members’ tab there are still only 3 VM's present.

Or what happens if I add a nonexistent external_id to the group?
Does NSX-T accept IDs that don’t exist?

Image
NSX-T Group with none existing external_ids
Textarea

As, you can see this can mess up the group completely. Fortunately, someone already build a ‘Show Deleted Entities’ button in NSX-T. I guess I’m not the only one who added some nonexistent external_ids. If you click Edit you can see the ‘Show Deleted Entities’ button. From there you can click ‘Remove All’ and the group gets cleaned up.

Removing none existing external_ids
Textarea

Enough for now. I’ll continue with the rest of the script to add VM’s to groups using PowerCLI and see you back here for the second part of this blog series.

Thanks for reading and if you have any questions or remarks, please send me a message.

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