Add or remove Tags in NSX-T with PowerCLI

By | 22. December 2019

This post is also available in: German

In this Blogpost I will explain how to add or remove a Tag in NSX-T.

If the VM is not tagged before it is very easy to set a new Tag, but if the VM has already been tagged and you don’t want to loose the existing Tags, it becomes more complicated, because the NSX API will overwrite all Tags if a new one will be set.

If you would like to learn how to use PowerCLI with NSX-T Policy API you can read my Blog: Creating Objects in NSX-T Policy API with VMware PowerCLI

Complete Script

This Script will add a “quarantine” Tag to a VM, with interactive User Input to define which VM should be tagged. The VM name is Case Sensitive and can be found in NSX Inventory -> Virtual Machines.

$display_name = Read-Host -Prompt 'VM Name'
$SecTag = "quarantine"
$secscope = ""
$vmdata = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.realized_state.enforcement_points.virtual_machines
$vmdatavmid = @([PSCustomObject]$vmdata.list("default").results | select-object -property display_name, external_id | select-string "display_name=$display_name")
$vmdatavmid = $vmdatavmid -replace ("@{display_name=$display_name; ") -replace ("}")
$vmdataid=$vmdatavmid|ConvertFrom-StringData
$vmdataentry = @([PSCustomObject]$vmdata.list("default").results | select-object -property display_name, tags | select-string "display_name=$display_name")
$vmdataentrytags=$vmdataentry-replace ("@{display_name=$display_name; tags=(\[)struct ") -replace'(\])'
$vmdataentrytags = $vmdataentrytags -replace ("struct ") -replace ("'") -replace ("}}"),("}") -replace (":"),("=") -replace (" ") -replace ("},"),("};")

#$vmdataentrytags = $vmdataentrytags -replace ("{scope=$secscope,tag=$SecTag};") -replace (";{scope=$secscope,tag=$SecTag}")
$vmdataentrytags = @($vmdataentrytags.split(";"))
$vmdataentrytags = $vmdataentrytags -replace ("{") -replace ("}")
$vmdataentrytags+="scope=$secscope,tag=$SecTag"
$vmdatacontent = $vmdata.Help.updatetags.virtual_machine_tags_update.Create()
$vmdatacontent.virtual_machine_id = $vmdataid.external_id
foreach ($item in $vmdataentrytags) {
$item=@($item.split(","))
$vmdatatags1=$item|ConvertFrom-StringData
$vmdatatags=$vmdata.Help.updatetags.virtual_machine_tags_update.tags.Element.Create()
$vmdatatags.tag=$vmdatatags1.tag
$vmdatatags.scope=$vmdatatags1.scope
$vmdatacontent.tags.Add($vmdatatags) |Out-Null
}
$vmdata.updatetags("default", $vmdatacontent)

Let dive into the script:

we will create a Variable, and with “Read-Host”, the Input can be tipped in after the “-Prompt” VM Name.

$display_name = Read-Host -Prompt 'VM Name'

In my example I will set a Tag with the Name “quarantine” and no Scope.

$SecTag = "quarantine"
$secscope = ""

We will store the Information from all VMs recognized in NSX to the Variable “$vmdata”.

$vmdata = Get-NsxtPolicyService -Name com.vmware.nsx_policy.infra.realized_state.enforcement_points.virtual_machines

For each VM we will have now a lot of information.

In all examples I will use the Virtual Machine “DEV-DB”

$vmdata.list("default").results 

----output omitted----
guest_info : struct {'computer_name': dev-db, 'os_name': Ubuntu Linux
(64-bit)}
compute_ids : {moIdOnHost:5, hostLocalId:5,
locationId:564d2f4a-05a3-3fc5-6afc-f839afad7dc1,
instanceUuid:52caf68c-335e-e4e9-18b3-221f5ffe0300…}
resource_type : VirtualMachine
external_id : 564d2f4a-05a3-3fc5-6afc-f839afad7dc1
source : struct {'target_display_name': esx2, 'is_valid': True,
'target_type': HostNode, 'target_id':
283c61ef-fcc0-481f-a881-027338e11654}
_last_sync_time : 1577041205593
type : REGULAR
display_name : DEV-DB
power_state : VM_RUNNING
host_id : 283c61ef-fcc0-481f-a881-027338e11654
local_id_on_host : 5
tags : {struct {'scope': 2, 'tag': dev}, struct {'scope': 1, 'tag':
internal}, struct {'scope': 3, 'tag': db}}
----output omitted----

To add a Tag to a Specific VM we need the external VM ID (VM UUID). We will store the VM Display Name and the ID  in a Variable named “$vmdatavmid”

$vmdatavmid = @([PSCustomObject]$vmdata.list(“default”).results | select-object -property display_name, external_id | select-string “display_name=$display_name”)

With select-string “display_name=$display_name” we will choose the right VM.

But the Information cannot be used without some modification, because we only need the ID.

This will be the output from $vmdatavmid

@{display_name=DEV-DB; external_id=564d2f4a-05a3-3fc5-6afc-f839afad7dc1}
So we need to remove “@{display_name=DEV-DB; ” and “}

$vmdatavmid = $vmdatavmid -replace (“@{display_name=$display_name; “) -replace (“}”)

Let us check the output again
$vmdatavmid
external_id=564d2f4a-05a3-3fc5-6afc-f839afad7dc1

The Information is still in the wrong format so we will convert the information into a table:

$vmdataid=$vmdatavmid|ConvertFrom-StringData
Let us check the output from “$vmdataid”
Name                Value
—-                      —–
external_id      564d2f4a-05a3-3fc5-6afc-f839afad7dc1
 

We will now retrieve the existing Tags and Scope from the VM and store the Information in $vmdataentry.

$vmdataentry = @([PSCustomObject]$vmdata.list("default").results | select-object -property display_name, tags | select-string "display_name=$display_name")

This is the Output from “$vmdataentry” and we need to remove a lot of information…

@{display_name=DEV-DB; tags=[struct {'scope': 2, 'tag': dev}, struct {'scope': 1, 'tag': internal}, struct {'scope': 3, 'tag': db}]}
You can remove/replace everything in one line but I make smaller portions to understand what happen with the string.
So I will remove now “@{display_name=DEV-DB; tags=[struct ” and the Bracket “]” at the end.
Brackets will be interpreted by PowerShell and must be isolated with (\]).
 
$vmdataentrytags=$vmdataentry-replace ("@{display_name=$display_name; tags=(\[)struct ") -replace'(\])'

In the next Step we will remove and replace all other information

$vmdataentrytags = $vmdataentrytags -replace ("struct ") -replace ("'") -replace ("}}"),("}") -replace (":"),("=") -replace (" ") -replace ("},"),("};")

Let’s check the Variable “$vmdataentrytags”:

{scope=2,tag=dev};{scope=1,tag=internal};{scope=3,tag=db}

If you would like to remove a Tag/Scope, you need to insert here the following Line:

$vmdataentrytags = $vmdataentrytags -replace ("{scope=$secscope,tag=$SecTag};") -replace (";{scope=$secscope,tag=$SecTag}")

We will split the String now. The Identifier is “;”

$vmdataentrytags = @($vmdataentrytags.split(";"))

…and remove also the curly brackets.

$vmdataentrytags = $vmdataentrytags -replace ("{") -replace ("}")

The output from “$vmdataentrytags” should look like the following output.

scope=2,tag=dev
scope=1,tag=internal
scope=3,tag=db

We will add now our additional Tag/Scope we defined on the Top of the script. If you would like to remove the Tag/Scope you need to comment out this line.

$vmdataentrytags+="scope=$secscope,tag=$SecTag"

The output from “$vmdataentrytags” will have now the additional Tag.

scope=2,tag=dev
scope=1,tag=internal
scope=3,tag=db
scope=,tag=quarantine

The next Variable for NSX-T will apply later the Tags/Scope to a VM.

$vmdatacontent = $vmdata.Help.updatetags.virtual_machine_tags_update.Create()

We will add the Virtual Machine ID (UUID)

$vmdatacontent.virtual_machine_id = $vmdataid.external_id

The API Structure for VM Tags is as follows:

Unfortunately the Tags are not placed in a list so each scope/tag combination must be added as a single entry. We will create a loop (foreach) to attach all Tags.

foreach ($item in $vmdataentrytags) {

We will split now each “$vmdataentrytags” in scope and tag. The identifier is “,”.

$item = @($item.split(","))

…and create a List

$vmdatatags1=$item|ConvertFrom-StringData

We will add now for each entry the Tag/Scope to “$vmdatacontent” and close the loop.

$vmdatatags = $vmdata.Help.updatetags.virtual_machine_tags_update.tags.Element.Create()

$vmdatatags.tag=$vmdatatags1.tag

$vmdatatags.scope=$vmdatatags1.scope
$vmdatacontent.tags.Add($vmdatatags) | Out-Null

}

The Last step will add the Tags to the VM.

$vmdata.updatetags("default", $vmdatacontent)
print
Follow me

Daniel Stich

Senior Specialist Solutions Engineer - Network Virtualization and Security at VMware Global Inc.

Daniel kommt aus Wuppertal und ist seit 20+ Jahren im klassichen Routing und Switching unterwegs. Seit 2013 liegt sein Schwerpunkt auf Datacenter Networking und beschäftig sich seitdem mit Software Defined Networking.
Seit 2017 ist Daniel als NSX Solutions Engineer bei VMware und kümmert sich schwerpunktmäßig um das Thema NSX für Software Defined Datacenter, Public Cloud und Kubernetes.
Daniel Stich
Follow me

Latest posts by Daniel Stich (see all)

Category: IT-Security NSX Uncategorized Tags: , , ,

About Daniel Stich

Daniel kommt aus Wuppertal und ist seit 20+ Jahren im klassichen Routing und Switching unterwegs. Seit 2013 liegt sein Schwerpunkt auf Datacenter Networking und beschäftig sich seitdem mit Software Defined Networking. Seit 2017 ist Daniel als NSX Solutions Engineer bei VMware und kümmert sich schwerpunktmäßig um das Thema NSX für Software Defined Datacenter, Public Cloud und Kubernetes.

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.