Working with Groups in NSX created with PowerCLI

By | 28. January 2020

In this Blog I will explain how to use Groups in NSX and how to create Groups with PowerCLI.

About NSX Firewall and Groups

The NSX Firewall is working  based on IP to IP Communication, like all other Firewalls. But NSX will use different Identifiers to get the IP Information for the Firewall entries.

Instead of creating Firewall Rules based on Source/Destination IP(s) you will use Source/Destination Group(s).

Example: Firewall Entries 3 Tier Application

Inside the Group you can can define how IP Addresses will be identified. My personal recommendation,  using Membership Criteria based on following Identifiers:

  • Virtual Machine TAG (Equals, Contains, Starts with, Ends with)
  • Virtual Machine Name (Equals, Contains, Starts with, Ends with, Not Equals)
  • Virtual Machine OS Name (Equals, Contains, Starts with, Ends with, Not Equals)
  • Virtual Machine Computer Name (Equals, Contains, Starts with, Ends with, Not Equals)
  • Segment Port TAG (Equals)
  • Segment TAG (Equals)
  • IP Set TAG (Equals)

Identifiers can be combined with “AND” or “OR”.

“AND” means all conditions must match, “OR” means at least one condition must match.

But you can also create Groups based on IP Networks or IP Addresses. This is useful to create Firewall Rules for Devices/Networks that are not directly connected to NSX.

You can also integrate your Active Directory in NSX and use AD Attributes to create your groups. This can be used for VDI or Remote Desktop environments to control Network Access based on the current User.

NSX Firewall can be used with the same principles you are using for Active Directory. Nobody will create new AD Groups if a new Employee starts working in a company. Normally you will check the rights from the new Employee and put him in the existing AD Groups.

We can do the same with NSX. Instead of creating a Firewall Entry for each new Server/Application, we set the right Tags to the new Machine and with the Tags the Machine is automatically Member in different Groups. If the Machine will be deleted, all Firewall Entries (IPtoIP) will be deleted automatically.

Creating Groups with PowerCLI

The Datasource for the Group Content can be different files like .csv file or in my example a .json file.

In my example I will create the Groups WEB, APP and DB for Virtual Machines (VirtualMachine) and also for Containers (SegmentPort).

But before we jump into the Details let’s have a look at the expected API Structure!

NSX Policy API Structure for Groups

GET https://<policy-mgr>/policy/api/v1/infra/domains/default/groupsNSX

{
	"expression":[
		{
			"member_type":"VirtualMachine",
			"key":"Tag",
			"operator":"EQUALS",
			"value":"WEB",
			"resource_type":"Condition"
		},
		{
			"conjunction_operator":"OR",
			"resource_type":"ConjunctionOperator"
		},
		{
			"member_type":"SegmentPort",
			"key":"Tag",
			"operator":"EQUALS",
			"value":"WEB",
			"resource_type":"Condition"
		}
	],
	"resource_type":"Group",
	"id":"A_WEB",
	"display_name":"A_WEB",
	"tags":[
		{
			"scope":"",
			"tag":"PowerCLI"
		}
	]
}

The Order is sometimes a little bit complicated, but If you look only on the Brackets and Curly Brackets it become easier….;-) You will see that the output starts with the Group Content and on the bottom you will find the Group Information.

Now we will check the Fields in the Group Information:

"resource_type":"Group",
	"id":"A_WEB",
	"display_name":"A_WEB",
	"tags":[
		{
			"scope":"",
			"tag":"PowerCLI"
		}

The “id” and “display_name” can be identical, but the “id” must be unique! If you search later for the Object with an API call you must search with the “id” in the NSX Manager UI you will see the “display_name”.

“tags” are optional but this will help to find Objects our Group of Objects faster.

Next we will check the first part in the Group Content:

"expression": [
    {
      "member_type": "VirtualMachine",
      "key": "Tag",
      "operator": "EQUALS",
      "value": "WEB",
      "resource_type": "Condition"
    }

Be aware that the Text is case sensitive!

The “member_type” can be either “VirtualMachine”, “SegmentPort”, “Segment” or “IPSet”.

Depends on your Input, you may not have all options available.

The “key” can be “Name”, “Tag”, “OSName” or “ComputerName”

The “operator” can be “EQUALS”,”CONTAINS”, “STARTSWITH”, ENDSWITH”, “NOTEQUALS”

“value” will deliver the content for the “operator”. In the example above Virtual Machines with the exact Tag “WEB” will math this condition.

If you have only one criteria the “resource_type” will be “Condition”. But if you have more than one criteria (up to 5 criteria are allowed) you need to define how to combine the criteria.

Either all criteria must match “AND” or any criteria must match “OR”.

This will be done with “resource_type”: “ConjunctionOperator”

{
      "conjunction_operator": "OR",
      "resource_type": "ConjunctionOperator"
    }

Now we are ready to create the Content!

Create Group Content for PowerCLI

I decided to use a .json file for my content because you can use .json also to retrieve the information from a Database or other CMDBs in your environment.

In my example I will create the Groups WEB, APP and DB for Virtual Machines (VirtualMachine) and also for Containers (SegmentPort). The Fields are simmilar the same we see before but in a different order to make it better readable.

[
   {
      "display_name":"A_WEB",
      "id":"A_WEB",
      "tag":"PowerCLI",
      "groupspecinput":[
         {
            "member_type":"VirtualMachine",
            "key":"Tag",
            "value":"WEB",
            "operator":"EQUALS",
            "conjunction_operator":"OR"       
},
         {
            "member_type":"SegmentPort",
            "key":"Tag",
            "value":"WEB",
            "operator":"EQUALS"
}
] 
},
   {
      "display_name":"A_APP",
      "id":"A_APP",
      "tag":"PowerCLI",
      "groupspecinput":[
         {
            "member_type":"VirtualMachine",
            "key":"Tag",
            "value":"APP",
            "operator":"EQUALS",
            "conjunction_operator":"OR"       
},
         {
            "member_type":"SegmentPort",
            "key":"Tag",
            "value":"APP",
            "operator":"EQUALS"   
}   
] 
},
   {
      "display_name":"A_DB",
      "id":"A_DB",
      "tag":"PowerCLI",
      "groupspecinput":[
         {
            "member_type":"VirtualMachine",
            "key":"Tag",
            "value":"DB",
            "operator":"EQUALS",
            "conjunction_operator":"OR" 
},
         {
            "member_type":"SegmentPort",
            "key":"Tag",
            "value":"DB",
            "operator":"EQUALS"   
}   
]
}
]

You can paste the Text directly in the PowerShell Sript into a variable

$jsonfilegroups = 'Above_JSON_file'

And convert the Content into PowerShell Format

$jsonfilegroupsconverted = ConvertFrom-Json -InputObject $jsonfilegroups

Or you store the content as .json file and load the .json file into a PowerShell Variable. I will use this Option for my example.

$jsonfilegroupsconverted = Get-Content -Raw -Path /path/to/groups.json | ConvertFrom-Json

First we will set the Parameters for the Group

{
      "display_name":"A_WEB",
      "id":"A_WEB",
      "tag":"PowerCLI",

And inside the Group we will create a list with the criteria

"groupspecinput":[
         {
            "member_type":"VirtualMachine",
            "key":"Tag",
            "value":"WEB",
            "operator":"EQUALS",
            "conjunction_operator":"OR"       
},
         {
            "member_type":"SegmentPort",
            "key":"Tag",
            "value":"WEB",
            "operator":"EQUALS"
}
] 

May you recognize in the first block I set the “conjunction_operator”:”OR”. In the second block I didn’t set the “conjunction_operator”. If you would like to create more criteria, you need to set the “conjunction_operator” on all blocks but not on the last one!

When we created the .json file we can create the PowerCLI Script

Creating the PowerCLI Sscript

First we will convert the .json file into PowerShell format:

$jsonfilegroupsconverted = Get-Content -Raw -Path groups.json | ConvertFrom-Json

Your output should look similar. You can see that you have a second list inside the list under groupspecinput.

Example: $jsonfilegroupsconverted

If you would like to check the list under groupspecinput you can do this with following command:

$jsonfilegroupsconverted.groupspecinput

Because we would create more than one group with this script, we need to create a foreach loop

foreach ($groupitem in $jsonfilegroupsconverted) {

Inside the the Loop we will retrieve the information to create a Group

$groupsvc = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups

and set the Group information we used in our .json file. The $groupdomainspec should be “default” if you didn’t change anything in NSX Manager.

$groupspec = $groupsvc.Help.patch.group.Create()
$groupspec.display_name = $groupitem.display_name
$groupdomainspec = "default"
$groupidspec = $groupsvc.Help.patch.group_id.Create()
$groupidspec = $groupitem.id

To find the objects better, we set also a Tag on the Group

$grouptag = $groupsvc.Help.patch.group.tags.Element.Create()
$grouptag.tag = $groupitem.tag
$groupspec.tags.Add($grouptag) | Out-Null
foreach ($criteria in $groupitem.groupspecinput) {
$groupspecexp = $groupsvc.Help.patch.group.expression.Element.condition.Create()
$groupspecexp.member_type = $criteria.member_type
$groupspecexp.key = $criteria.key
$groupspecexp.value = $criteria.value
$groupspecexp.operator = $criteria.operator
$groupspec.expression.Add($groupspecexp) | Out-Null

If we set more than one criteria we defined in our .json file the “conjuction_operator”. If the “conjunction_operator” exist, the Script will execute the commands. If not, the script will directly jump to the next section.

if ($criteria.conjunction_operator) {
$groupspec_conj = $groupsvc.Help.patch.group.expression.Element.conjunction_operator.Create()
$groupspec_conj.conjunction_operator = $criteria.conjunction_operator
$groupspec.expression.Add($groupspec_conj) | Out-Null
}

Now we need to close the criteria foreach loop and create the group.

}
$groupsvc.patch($groupdomainspec, $groupidspec, $groupspec)

To close the first foreach Loop we need to set again a curly bracket

}

If everything works fine you should see in your NSX Manager the newly created groups

Example: Created Groups
Example: Criteria

In my last Blog (https://www.vrealize.it/2019/12/22/add-or-remove-tags-in-nsx-t-with-powercli/) I explained how to set Tags on VMs. So I will also see the effective Members in the Group

Example: Effective Members
Example: IP Address

Following you will find my complete Script (without the .json part)

$jsonfilegroupsconverted = Get-Content -Raw -Path groups.json | ConvertFrom-Json
#Create Groups
Write-Output ""
Write-Host "Create Groups" -ForegroundColor Green
foreach ($groupitem in $jsonfilegroupsconverted) {
    $groupsvc = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.domains.groups
    #Add Group Content
    $groupspec = $groupsvc.Help.patch.group.Create()
    $groupspec.display_name = $groupitem.display_name
    $groupdomainspec = "default"
    #Add Group ID
    $groupidspec = $groupsvc.Help.patch.group_id.Create()
    $groupidspec = $groupitem.id
    #Add TAG
    $grouptag = $groupsvc.Help.patch.group.tags.Element.Create()
    $grouptag.tag = $groupitem.tag
    $groupspec.tags.Add($grouptag) | Out-Null
    #Add Group Membership Criteria
    foreach ($criteria in $groupitem.groupspecinput) {
        $groupspecexp = $groupsvc.Help.patch.group.expression.Element.condition.Create()
        $groupspecexp.member_type = $criteria.member_type
        $groupspecexp.key = $criteria.key
        $groupspecexp.value = $criteria.value
        $groupspecexp.operator = $criteria.operator
        $groupspec.expression.Add($groupspecexp) | Out-Null
        #Combine Criterias
        if ($criteria.conjunction_operator) {
            $groupspec_conj = $groupsvc.Help.patch.group.expression.Element.conjunction_operator.Create()
            $groupspec_conj.conjunction_operator = $criteria.conjunction_operator
            $groupspec.expression.Add($groupspec_conj) | Out-Null
        }
    }
$groupsvc.patch($groupdomainspec, $groupidspec, $groupspec)
Write-Host "Created Group" $groupidspec 
}

Happy Reading!

print
Daniel Stich
Follow me

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.