Working with vCloud Metadata in PowerCLI – Part 1
Way back in 2012 Alan Renouf created a PowerCLI module to deal with manipulation of metadata entries for vCloud Director objects - this can be incredibly useful to track related information for these objects. The vCD metadata functionality was enhanced in v5.1 (and then later in 5.5, 5.6 and 8.0) - in particular typed values were added with functionality to use date/time, boolean and numeric values (as well as free-form string text). Also added were security levels so that metadata could be made read-only or hidden (from a tenant perspective) but still accessible/visible to system owners. I've taken the PowerShell module that Alan published here and updated it to cope with these enhancements. I've also updated the returned fields/views to include the extra attributes (where present) such as security levels of metadata entries.
Note that I am definitely not a professional developer (and most of my PowerShell knowledge comes from Google) so there's probably significant room for improvement in the code - comment back if you have suggestions for improvement and I'll update this post.
Use of the module requires a valid connection to a vCloud instance (using Connect-CIServer). This won't work for versions prior to v5.1 (most of my testing has been with PowerCLI 6 against a v8 vCD deployment) so please use at your own risk and make sure you thoroughly test your own scenarios. I'll write a follow-up post detailing some example code and usage scenarios which people may find useful in the next few days.
I'd suggest copy/pasting the code (below) into a PowerShell module (.psm1) file and including the module in your scripts as needed.
1Function New-CIMetaData {
2 <#
3 .SYNOPSIS
4 Creates a Metadata Key/Value pair.
5 .DESCRIPTION
6 Creates a custom Metadata Key/Value pair on a specified vCloud object
7 .PARAMETER Key
8 The name of the Metadata to be applied.
9 .PARAMETER Value
10 The value of the Metadata to be applied, the string 'Now' can be used
11 for the current date/time for values using the 'DateTime' type.
12 .PARAMETER Visibility
13 The visibility of the Metadata entry (General, Private, ReadOnly)
14 .PARAMETER Type
15 The type of the Metadata entry (String, Number, DateTime, Boolean)
16 (these correspond to the types of: MetadataStringValue,
17 MetadataNumberValue, MetadataDateTimeValue or MetadataBooleanValue
18 respectively)
19 .PARAMETER CIObject
20 The object on which to apply the Metadata.
21 .EXAMPLE
22 New-CIMetadata -Key "Owner" -Value "Alan Renouf" -CIObject (Get-Org Org1)
23 Creates a new metadata value "Alan Renouf" in a key "Owner" on the Org1 object.
24 .EXAMPLE
25 New-CIMetadata -Key "Company" -Value "ABC Corp" -Visibility READONLY -CIObject (Get-CIVM 'client')
26 Creates a new metadata value "ABC Corp" in a key "Company" on the 'client' VM object with the READONLY attribute set preventing changes by non-system users.
27 .EXAMPLE
28 New-CIMetadata -Key "Backup" -Value $false -Visibility Private -Type Boolean -CIObject (Get-CIVapp 'testvapp')
29 Creates a new hidden metadata value $false in a key "Backup" on the vApp object with the 'Private' attribute set preventing visibility to non-system users.
30 .NOTES
31 NAME: Get-CIMetaData
32 AUTHOR: Jon Waite based on code by Alan Renouf
33 LASTEDIT: 2016-02-23
34 KEYWORDS: metadata set vcloud director
35 #Requires -Version 2.0
36 #>
37 [CmdletBinding(
38 SupportsShouldProcess=$true,
39 ConfirmImpact="High"
40 )]
41 param(
42 [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
43 [PSObject[]]$CIObject,
44 [parameter(Mandatory=$true)]
45 [String]$Key,
46 [parameter(Mandatory=$true)]
47 $Value,
48 [ValidateSet('General','Private','ReadOnly')]
49 [String]$Visibility = 'General',
50 [ValidateSet('String','Number','DateTime','Boolean')]
51 [String]$Type = "String"
52 )
53 Process {
54 Foreach ($Object in $CIObject) {
55 $Metadata = New-Object VMware.VimAutomation.Cloud.Views.Metadata
56 $Metadata.MetadataEntry = New-Object VMware.VimAutomation.Cloud.Views.MetadataEntry
57
58 $Metadata.MetadataEntry[0].Key = $Key
59
60 switch($Type) {
61 'String' { $Metadata.MetadataEntry[0].TypedValue = New-Object VMware.VimAutomation.Cloud.Views.MetadataStringValue }
62 'Number' { $Metadata.MetadataEntry[0].TypedValue = New-Object VMware.VimAutomation.Cloud.Views.MetadataNumberValue }
63 'DateTime' { $Metadata.MetadataEntry[0].TypedValue = New-Object VMware.VimAutomation.Cloud.Views.MetadataDateTimeValue }
64 'Boolean' { $Metadata.MetadataEntry[0].TypedValue = New-Object VMware.VimAutomation.Cloud.Views.MetadataBooleanValue }
65 }
66
67 if ($Type -eq 'DateTime' -and $Value -eq 'Now') {
68 $Metadata.MetadataEntry[0].TypedValue.Value = [string](Get-Date).ToUniversalTime().GetDateTimeFormats('s')
69 } else {
70 $Metadata.MetadataEntry[0].TypedValue.Value = $Value
71 }
72
73 switch($Visibility) {
74 'General' { } #Default, don't need to change
75 'Private' {
76 $Metadata.MetadataEntry[0].Domain = New-Object VMware.VimAutomation.Cloud.Views.MetadataDomainTag
77 $Metadata.MetadataEntry[0].Domain.Value = 'SYSTEM'
78 $Metadata.MetadataEntry[0].Domain.Visibility = 'PRIVATE'
79 }
80 'ReadOnly' {
81 $Metadata.MetadataEntry[0].Domain = New-Object VMware.VimAutomation.Cloud.Views.MetadataDomainTag
82 $Metadata.MetadataEntry[0].Domain.Value = 'SYSTEM'
83 $Metadata.MetadataEntry[0].Domain.Visibility = 'READONLY'
84 }
85 }
86
87 $Object.ExtensionData.CreateMetadata($Metadata)
88 ($Object.ExtensionData.GetMetadata()).MetadataEntry | Where {$_.Key -eq $key } | Select @{N="CIObject";E={$Object.Name}},
89 @{N="Type";E={$_.TypedValue.GetType().Name}},
90 @{N="Visibility";E={ if ($_.Domain.Visibility) { $_.Domain.Visibility } else { "General" }}},
91 Key -ExpandProperty TypedValue
92 }
93 }
94}
95Function Get-CIMetaData {
96 <#
97 .SYNOPSIS
98 Retrieves all Metadata Key/Value pairs.
99 .DESCRIPTION
100 Retrieves all custom Metadata Key/Value pairs on a specified vCloud object
101 .PARAMETER CIObject
102 The object on which to retrieve the Metadata.
103 .PARAMETER Key
104 The key to retrieve.
105 .EXAMPLE
106 Get-CIMetadata -CIObject (Get-Org Org1)
107 #>
108 param(
109 [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
110 [PSObject[]]$CIObject,
111 $Key
112 )
113 Process {
114 Foreach ($Object in $CIObject) {
115 If ($Key) {
116 ($Object.ExtensionData.GetMetadata()).MetadataEntry | Where {$_.Key -eq $key } | Select @{N="CIObject";E={$Object.Name}},
117 @{N="Type";E={$_.TypedValue.GetType().Name}},
118 @{N="Visibility";E={ if ($_.Domain.Visibility) { $_.Domain.Visibility } else { "General" }}},
119 Key -ExpandProperty TypedValue
120 } Else {
121 ($Object.ExtensionData.GetMetadata()).MetadataEntry | Select @{N="CIObject";E={$Object.Name}},
122 @{N="Type";E={$_.TypedValue.GetType().Name}},
123 @{N="Visibility";E={ if ($_.Domain.Visibility) { $_.Domain.Visibility } else { "General" }}},
124 Key -ExpandProperty TypedValue
125 }
126 }
127 }
128}
129Function Remove-CIMetaData {
130 <#
131 .SYNOPSIS
132 Removes a Metadata Key/Value pair.
133 .DESCRIPTION
134 Removes a custom Metadata Key/Value pair on a specified vCloud object
135 .PARAMETER Key
136 The name of the Metadata to be removed.
137 .PARAMETER CIObject
138 The object on which to remove the Metadata.
139 .EXAMPLE
140 Remove-CIMetaData -CIObject (Get-Org Org1) -Key "Owner"
141 #>
142 [CmdletBinding(
143 SupportsShouldProcess=$true,
144 ConfirmImpact="High"
145 )]
146 param(
147 [parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
148 [PSObject[]]$CIObject,
149 $Key
150 )
151 Process {
152 $CIObject | Foreach {
153 $metadataValue = ($_.ExtensionData.GetMetadata()).GetMetaDataValue($Key)
154 If($metadataValue) { $metadataValue.Delete() }
155 }
156 }
157}