Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Powershell vCenter server Rest API create and assign tag and tagcategory

While working on one of the automation project I wanted to assign tags and tag category on VMware clusters using Powershell, It is easy task when done using PowerCLI module but the requirement was not to use PowerCLI module instead make use of vSphere vCenter Rest API

PowerCLI create, modify and assign tag and tagcategory

What is Tag, TagCategory and Cardinality?
Tags permit you to assign metadata to items in the vSphere inventory to make these items more sortable and searchable. A tag is a label that you can apply to items in the vSphere inventory. When you create a tag, you assign that tag to a category. Categories allow you to group related tags together. 

  • You can also set Cardinality using vCenter Rest API, There are two type of tag Cardinality. Select One tag per object to permit only one tag from this category to be applied to an item at any one time. Use this option for categories whose tags are mutually exclusive. For example, a category called Priority with tags High, Medium, and Low should allow one tag per object, because an object should have only one priority.
  • Select Many tags per object to allow multiple tags from the category to be applied to an object at any one time.

After running the script to create and apply tags and tagcategory for the first time result looks like below.

VMware vSphere vCenter api tagcategory tags powershell powercli automation cluster ClusterComputeResource, DistributedVirtualSwitch, VmwareDistributedVirtualSwitch, LibraryItem.png

While executing script it needs a Cluster, Tag, TagCategory, Cardinality, associaable_types information in the below CSV file format.

1
2
3
4
5
6
Cluster,Tag,TagCategory,Cardinality,associable_types
Gotham,Batman,Superhero,SINGLE,ClusterComputeResource
Krypton,Zor-EL,Superhero,SINGLE,ClusterComputeResource
Mogo,Green Laterns,Superhero,SINGLE,ClusterComputeResource
Smallville,Superman,Superhero,SINGLE,ClusterComputeResource
Test,NoComics,Superhero,SINGLE,"ClusterComputeResource, DistributedVirtualSwitch, VmwareDistributedVirtualSwitch, LibraryItem, ResourcePool, Folder, HostNetwork, DistributedVirtualPortgroup, VirtualApp, StoragePod, Datastore, Network, Datacenter, Library, HostSystem, OpaqueNetwork, VirtualMachine, com.vmware.content.library.Item, com.vmware.content.Library"

After created Tags they looks like as below screenshot in the vSphere Client >> Tags & Custom Attributes. All the tags are created, from CSV data.

Vmware vSPhere vCenter api microsoft powershell vcsa Tags & Custom Attributes tag category PowerShell assign modify tags from csv excel file administration .png

This is how assigned tag on the VMware cluster looks like after assignment.

If there is a conflict between configured tags data and CSV data, it is updated/overwritten accordingly on the vCenter server.

VMware vSphere vCenter rest api Microsoft Powershell API tagging tags tag category cardianility Single associated types vcsa api.png

Download this script vSphere API tagging.zip, It is also available on github.com/kunaludapi.

 $csv = Import-Csv C:\temp\data.csv  
 $vCenter = 'marvel.vcloud-lab.com'  
 $username = 'administrator@vsphere.local'   
 $password = '123456'  
   
 $secureStringPassword = ConvertTo-SecureString $password -AsPlainText -Force  
 $encryptedPassword = ConvertFrom-SecureString -SecureString $secureStringPassword  
 $credential = New-Object System.Management.Automation.PsCredential($username,($encryptedPassword | ConvertTo-SecureString))  
 #$credential.GetNetworkCredential().Password  
   
 if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)   
 {  
   $certCallback = @'  
     using System;  
     using System.Net;  
     using System.Net.Security;  
     using System.Security.Cryptography.X509Certificates;  
     public class ServerCertificateValidationCallback  
     {  
       public static void Ignore()  
       {  
         if (ServicePointManager.ServerCertificateValidationCallback == null)  
         {  
           ServicePointManager.ServerCertificateValidationCallback +=  
           delegate   
           (  
             Object Obj,  
             X509Certificate certificate,  
             X509Chain chain,  
             SslPolicyErrors errors  
           )  
           {  
             return true;  
           };  
         }  
       }  
     }  
 '@  
   Add-Type $certCallback  
 }  
   
 #execute c# code and ignore invalid certificate error  
 [ServerCertificateValidationCallback]::Ignore();  
   
 #Type credential and process to base 64  
 #$credential = Get-Credential -Message 'Type vCenter Password' -UserName 'administrator@vsphere.local'  
 $auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($credential.UserName+':'+$credential.GetNetworkCredential().Password))  
 $head = @{  
   Authorization = "Basic $auth"  
 }  
   
 #Authenticate against vCenter  
 $a = Invoke-WebRequest -Uri "https://$vCenter/rest/com/vmware/cis/session" -Method Post -Headers $head  
 $token = ConvertFrom-Json $a.Content | Select-Object -ExpandProperty Value  
 $session = @{'vmware-api-session-id' = $token}  
   
   
 #Main tag category API url  
 $tagCategoryAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/category"  
   
 #Get tagCategory list from vcenter  
 $tagCategoryAPI = Invoke-WebRequest -Uri $tagCategoryAPIUrl -Method Get -Headers $session  
 $tagCategoryList = ConvertFrom-Json $tagCategoryAPI.Content | Select-Object -ExpandProperty Value  
   
 $tagCategoryInfo = @()  
 #Get single tagCategory from collected list  
 foreach ($tagCategory in $tagCategoryList)  
 {  
   $tagCategory = $tagCategory -replace ":","%3A"  
   $tagCategorySelectedAPI = Invoke-WebRequest -Uri "https://$vCenter/rest/com/vmware/cis/tagging/category/id:$tagCategory" -Method Get -Headers $session  
   $tagCategoryInfo += ConvertFrom-Json $tagCategorySelectedAPI.Content | Select-Object -ExpandProperty Value  
 } #foreach ($tagCategory in $tagCategoryList)  
   
 #Create tagCategory  
 #http://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/structures/com/vmware/cis/tagging/category/svc.create_spec-structure.html  
 $uniqueTagCategory = $csv | Sort-Object -Property @{Expression='TagCategory'; Descending=$true}, Cardinality, EntityType -Unique  
 foreach ($csvTagCategory in $uniqueTagCategory)  
 {  
   $tagCategoryExists = $tagCategoryInfo | Where-Object {$_.name -eq $csvTagCategory.TagCategory}  
   $associable_types = $tagCategoryExists.associable_types  
   if ($tagCategoryInfo.name -contains $csvTagCategory.TagCategory)   
   {  
     Write-Warning "Already exist - TagCategory '$($tagCategoryExists.name)' with Cardinality '$($tagCategoryExists.cardinality)' and associable types '$associable_types'"   
   } #if ($tagCategoryInfo.name -contains $csvTagCategory.TagCategory)  
   else   
   {  
    
     #$tagCategoryAssociableTypes = "'{0}'" -f $csvTagCategory.associable_types.Replace(',', "', '")  
     $tagCategoryAssociableTypes = $csvTagCategory.associable_types -split ',' | ForEach-Object {$_.trim()}  
     $bodyCreateTagCategoryJSON = @{  
       create_spec = @{  
         cardinality = $csvTagCategory.Cardinality.ToUpper()  
         associable_types = @($tagCategoryAssociableTypes)  
         name = $csvTagCategory.TagCategory  
         description = $csvTagCategory.TagCategory  
       }  
     }  
       
     <#  
     $tagCategoryAssociableTypes = '{  
       "create_spec": {  
         "associable_types": [  
           "ClusterComputeResource",  
           "Datastore"  
         ],  
         "cardinality": "SINGLE",  
         "category_id": "obj-103",  
         "description": "string",  
         "name": "string"  
       }  
     }'  
     #>  
   
     #Help on the JSSON   
     #""associable_types"": [ClusterComputeResource, DistributedVirtualSwitch, VmwareDistributedVirtualSwitch, LibraryItem, ResourcePool, Folder, HostNetwork, DistributedVirtualPortgroup, VirtualApp, StoragePod, Datastore, Network, Datacenter, Library, HostSystem, OpaqueNetwork, VirtualMachine, com.vmware.content.library.Item, com.vmware.content.Library]  
     #""cardinality"": ""SINGLE"" #or ""MULTIPLE""  
     #""category_id"": "obj-103" #Optional automatically created by vCenter  
     
     try  
     {  
       $tagCategoryCreateAPI = Invoke-WebRequest -Uri $tagCategoryAPIUrl -Method POST -Headers $session -Body ($bodyCreateTagCategoryJSON | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop  
       Write-Host "New TagCategory created - '$($csvTagCategory.TagCategory)'" -BackgroundColor DarkGreen  
     }  
     catch  
     {  
       Write-Host "New TagCategory created failed - '$($csvTagCategory.TagCategory)'" -BackgroundColor DarkRed  
     }  
   } #else if ($tagCategoryInfo.name -contains $csvTagCategory.TagCategory)  
 } #foreach ($csvTagCategory in $uniqueTagCategory)  
   
 ### Tagging part ###  
   
 #Main tag category API url  
 $tagCategoryAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/category"  
   
 #Get tagCategory list from vcenter  
 $tagCategoryAPI = Invoke-WebRequest -Uri $tagCategoryAPIUrl -Method Get -Headers $session  
 $tagCategoryList = ConvertFrom-Json $tagCategoryAPI.Content | Select-Object -ExpandProperty Value  
   
 #get latest TagCategory list  
 $tagCategoryInfo = @()  
 #Get single tagCategory from collected list  
 foreach ($tagCategory in $tagCategoryList)  
 {  
   $tagCategory = $tagCategory -replace ":","%3A"  
   $tagCategorySelectedAPI = Invoke-WebRequest -Uri "https://$vCenter/rest/com/vmware/cis/tagging/category/id:$tagCategory" -Method Get -Headers $session  
   $tagCategoryInfo += ConvertFrom-Json $tagCategorySelectedAPI.Content | Select-Object -ExpandProperty Value  
 } #foreach ($tagCategory in $tagCategoryList)  
   
   
 #Main cluster API url  
 $clusterAPIUrl = "https://$vCenter/rest/vcenter/cluster"  
   
 #Get cluster list from vcenter  
 $clusterListAPI = Invoke-WebRequest -Uri $clusterAPIUrl -Method Get -Headers $session  
 $clusterList = ConvertFrom-Json $clusterListAPI.Content | Select-Object -ExpandProperty Value  
   
 foreach ($data in $csv)  
 {  
   $currentCluster = $clusterList | Where-Object {$_.name -eq $data.Cluster}  
   $tagsOnClusterAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/tag-association?~action=list-attached-tags-on-objects"  
     
   $bodyTagsOnClusterJSON = @{  
     object_ids = @(  
       @{  
         id = $currentCluster.cluster #$($clusterInfo.resource_pool)   
         type = 'ClusterComputeResource'  
       }  
     )  
   }  
     
 <#  
 $bodyTagsOnClusterJSON = "  
 {  
   ""object_ids"": [  
     {  
       ""id"": ""$($clusterInfo.resource_pool)"",  
       ""type"": ""ClusterComputeResource""  
     }  
   ]  
 }  
 "  
 #>  
   
   $attachedTagOnClusterAPI = Invoke-WebRequest -Uri $tagsOnClusterAPIUrl -Method POST -Headers $session -Body ($bodyTagsOnClusterJSON | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop  
   $assignedTagsOnCluster = ConvertFrom-Json $attachedTagOnClusterAPI.Content | Select-Object -ExpandProperty Value | Select-Object -ExpandProperty tag_ids  
   
   $assignedTagInfo = @()  
   foreach ($tag in $assignedTagsOnCluster)  
   {  
     $tagsAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/tag/id:$tag"  
     $tagAPI = Invoke-WebRequest -Uri $tagsAPIUrl -Method Get -Headers $session  
     $assignedTagInfo += ConvertFrom-Json $tagAPI.Content | Select-Object -ExpandProperty Value  
   }  
   
   $tagCategoryAssignmentConf = $tagCategoryInfo | Where-Object {$_.name -eq $data.TagCategory}  
   $tagAssignmentConf = $assignedTagInfo | Where-Object {$_.category_id -in $tagCategoryAssignmentConf.id}  
     
   #$clusterAPI = "https://$vCenter/rest/vcenter/cluster/$($currentCluster.cluster)"  
   #$clusterAPIInfo = Invoke-WebRequest -Uri $clusterAPI -Method Get -Headers $session  
   #$clusterInfo = ConvertFrom-Json $clusterAPIInfo.Content | Select-Object -ExpandProperty Value  
     
   if ($tagAssignmentConf.name -eq $null)  
   {  
     <#  
       {  
         "create_spec": {  
           "category_id": "obj-103",  
           "description": "string",  
           "name": "string",  
           "tag_id": "obj-103"  
         }  
       }  
     #>      
     $bodyCreateTagJSON = @{  
       create_spec = @{  
         category_id = $TagCategoryAssignmentConf.id  
         description = $data.Tag  
         name = $data.Tag  
         #tag_id = 'obj-103'  
       }  
     }  
   
     $createTagAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/tag"  
     $createTagAPI = Invoke-WebRequest -Uri $createTagAPIUrl -Method POST -Headers $session -Body ($bodyCreateTagJSON | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop  
     $createdTag = ConvertFrom-Json $createTagAPI.Content | Select-Object -ExpandProperty Value  
     $formattedCreatedTag = $createdTag -replace ":","%3A"  
       
     <#  
     {  
       "object_id": {  
         "id": "obj-103",  
         "type": "string"  
       }  
     }  
     #>  
     #http://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/operations/com/vmware/cis/tagging/tag_association.attach-operation.html  
   
     $bodyAssociateTagJSON = @{  
       object_id = @{  
         id = $currentCluster.cluster  
         type = 'ClusterComputeResource'  
       }  
     }  
   
     $associateTagAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/tag-association/id:$formattedCreatedTag`?~action=attach"  
     $createTagAPI = Invoke-WebRequest -Uri $associateTagAPIUrl -Method POST -Headers $session -Body ($bodyAssociateTagJSON | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop  
       
     $message = "Cluster '{0}' assigned New tag '{1}' under TagCategory '{2}'" -f $currentCluster.name, $data.Tag, $data.TagCategory  
     Write-Host $message -ForegroundColor Yellow  
   }  
   elseif ($tagAssignmentConf.Name -ne $data.Tag)  
   {  
     #http://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/operations/com/vmware/cis/tagging/tag.update-operation.html  
     $bodyUpdateTagJSON = @{  
       update_spec = @{  
         description = $data.Tag  
         name = $data.Tag  
       }  
     }  
   
     $formattedExistingTag = $tagAssignmentConf.id -replace ":","%3A"  
     $associateTagAPIUrl = "https://$vCenter/rest/com/vmware/cis/tagging/tag/id:$formattedExistingTag"  
     $createTagAPI = Invoke-WebRequest -Uri $associateTagAPIUrl -Method PATCH -Headers $session -Body ($bodyUpdateTagJSON | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop  
       
     $message = "Cluster '{0}' current tag '{1}' replaced with '{2}' under TagCategory '{3}'" -f $currentCluster.name, $tagAssignmentConf.name, $data.Tag, $data.TagCategory  
     Write-Host $message -ForegroundColor Red  
   }  
   else   
   {  
     $message = "Cluster '{0}' is already configured with Tag '{1}' under TagCategory '{2}'" -f $currentCluster.name, $tagAssignmentConf.name, $data.TagCategory  
     Write-Host $message -ForegroundColor Green  
   }  
 } #foreach ($data in $csv)  

Useful Articles
Getting started Ansible AWX tower for IT automation run first playbook
Ansible for VMwary Using vmware_vm_inventory dynamic inventory plugin
Ansible selectattr The error was TemplateRuntimeError no test named 'equalto'
ansible create an array with set_fact
Ansible get information from esxi advanced settings nested dictionary with unique keynames
Powershell Using vRealize Log Insight Rest API

Go Back

Comment

Blog Search

Page Views

4032935

Follow me on Blogarama