Erstellen oder löschen von Tags in NSX-T mit PowerCLI

Von | 8. Januar 2020

This post is also available in: Englisch

In diesem Blogpost möchte ich zeigen wir man Tags in NSX-T zu virtuellen Maschinen hinzufügt oder löscht.

Sollte die VM noch keinen Tag haben, ist es sehr einfach neue Tags zu dieser Maschine hinzuzufügen. Sobald die VM aber schon Tags besitzt müssen diese vorher ausgelesen und wieder neu gesetzt werden, weil die NSX API keinen Befehl mit add oder remove in diesem Zusammenhang kennt sondern jedes mal die Tags neu schreibt.

Wenn Sie mehr darüber lernen wollen wir Sie mit PowerCLI Objekte in NSX anlegen können, steht das in meinem folgenden Blogpost: Objekte in NSX-T Policy API mit VMware PowerCLI erstellen

Complete Script

Das nachfolgende Script setzt einen neuen Tag mit dem Namen “quarantine” auf eine vorhandene VM. Über den interaktiven User Input kann entschieden werden welche VM getagged werden soll. Der VM Name ist Case Sensitive und kann im NSX Manager über Inventory -> Virtual Machines gefunden werden.

$display_name = Read-Host -Prompt 'VM Name'
$SecTag = "quarantine"
$secscope = ""
if ($vmdataentrytags) {Remove-Variable vmdataentrytags}
$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")
if ($vmdataentry -like '*scope*') {
$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)

Schauen wir uns das Script im Detail an

Wir erstellen einen Variable und mit dem Zusatzbefehl “Read-Host” wird festgelegt, dass die Information von der Variable durch den Nutzer eingetragen werden muss. Über “-Prompt ‘VM Name’ wird dem Nutzer noch angezeigt was er eingeben muss.

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

Wie schon eingangs geschrieben setze ich in meinem Beispiel ein Tag mit den Namen “quarantine” und lasse das Scope Feld leer, da dieses Optional in NSX ist.

$SecTag = "quarantine"
$secscope = ""

Als erstest speichern wir die Informationen aller VMs die an NSX angeschlossen sind in der Variable “$vmdata”.

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

Für jede VM sehen wir jetzt eine ganze Menge Informationen.

In den nachfolgenden Beispielen benutze ich als Virtualle Maschine meine VM “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----

Um die VM zu taggen, benötigen wir nicht den VM Namen sondern die VM ID (VM UUID). Das heißt wir müssen als erstes den  VM Display Name und die ID  in einer Variable mit dem Namen “$vmdatavmid”

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

Mit select-string “display_name=$display_name” suchen wir nach der richtigen VM.

Aber diese Informationen kann noch nicht genutzt werden bevor wir es nicht richtig zugeschnitten haben, da wir nur die ID benötigen.

Das ist die Ausgabe von $vmdatavmid

@{display_name=DEV-DB; external_id=564d2f4a-05a3-3fc5-6afc-f839afad7dc1}
Wir löschen “@{display_name=DEV-DB; ” und “}

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

Danach sollte die Ausgabe wie folgt aussehen:
$vmdatavmid
external_id=564d2f4a-05a3-3fc5-6afc-f839afad7dc1

Da die Information noch in einem falschen Format vorliegt konvertieren wir die Information in eine Tabelle.

$vmdataid=$vmdatavmid|ConvertFrom-StringData
Jetzt sieht die Ausgabe von “$vmdataid” schon besser aus.
Name                Value
—-                      —–
external_id      564d2f4a-05a3-3fc5-6afc-f839afad7dc1
 

Damit am Ende noch alle bereits gesetzten Tags verfügbar sind lesen wir nun die Infromation über die bestehnden TAGs aus und speichern diese in  $vmdataentry.

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

Das ist die Ausgabe von “$vmdataentry” und hier müssen eine ganze Menge Informationen entfernt werden…

@{display_name=DEV-DB; tags=[struct {'scope': 2, 'tag': dev}, struct {'scope': 1, 'tag': internal}, struct {'scope': 3, 'tag': db}]}
Mann könnte alles in einer Zeile ersetzen und entfernen aber damit es nachvollziehbar beibt habe ich es in kleinere tasks unterteilt
Wir entfernen als erstes”@{display_name=DEV-DB; tags=[struct ” and die eckige Klammer “]” am Ende.
Eckige Klammern werden von PowerShell als Commando interpretiert und müssen daher zuerst isoliert werden. (\]).
 
$vmdataentrytags=$vmdataentry-replace ("@{display_name=$display_name; tags=(\[)struct ") -replace'(\])'

Im nächsten Schritt entfernen und ersetzen wir die anderen Informationen.

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

Schauen wir uns die Variable ncoh einmal an “$vmdataentrytags”:

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

Wenn Sie einen Tag/Scope entfernen wollen, müssten an dieser Stelle folgende Zeilen eingefügt werden:

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

Wir unterteilen den String nun in scope und tag. Der Identifier ist “;”

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

 

…und entfernen auch die geschweiften Klammern

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

Die Ausgabe von “$vmdataentrytags” sollte jetzt wie folgt aussehen.

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

Da hier noch unser Tag fehlt den wir definiert haben fügen wie diesen jetzt noch zu der bestehenden Liste hinzu.

Wenn Sie einen Tag entfernen wollen muss die nächste Zeile auskommentiert werden.

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

Jetzt hat die variable “$vmdataentrytags” sowohl die existierenden Tags als auch den neuen Tag.

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

Wir lesen nun die Struktur aus um die Tags setzen zu können.

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

Jetzt setzen wird die Virtual Machine ID (UUID)

$vmdatacontent.virtual_machine_id = $vmdataid.external_id

Die API Structure für VM Tags sieht wie folgt aus:

Leider sind die Tags nicht in einer Liste sonder einzelne Einträge und können daher nicht als Liste hizugefügt werden. Das Problem lösen wir mit einer foreach Schleife um die tags zu setzen.

foreach ($item in $vmdataentrytags) {

Innerhalb der Schleife splitten wir die Variable “$vmdataentrytags” in scope und tag. Der identifier ist “,”.

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

…und nun erstellen wir daraus eine Liste

$vmdatatags1=$item|ConvertFrom-StringData

Wir fügen jetzt die Tags zu der Variablen “$vmdatacontent” und schließen die Schleife.

$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

}

Der letzte Schritt fügt nun den neuen Tag und die bereits vorhanden Tags der VM zu.

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

Ein Gedanke zu „Erstellen oder löschen von Tags in NSX-T mit PowerCLI

  1. Daniel Stich Beitragsautor

    Update des Scriptes:
    Ich habe festgestellt, dass mein Script nur dann funktionierte, wenn bereits ein TAG vorhanden ist. Ansonsten läuft die SPLIT Operation in einen Fehler.

    Daher habe ich ein „if“ eingebaut das prüft, ob der Text „scope“ existiert. Wenn kein TAG gesetzt ist, existiert weder scope noch tag und das script springt direkt zu dem Punkt wo der neue Tag hinzugefügt wird.

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.