ManageTagsOnNetworkCard.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 50188b3b-5aab-4384-bccc-706b81197ff2
 
.AUTHOR AlexG
 
.COMPANYNAME GooberWorks
 
.COPYRIGHT GooberWorks (c) 2020
 
.TAGS Azure AzureRM Automation TAGS Tags Network Interface card NIC replace remove delete copy add tags ManageTagsOn
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
    This Powershell script will help you manage TAGS on Azure Network Interface Card Resource.
    While it is very easy to add and change tags using console, it is not so easy to delete a specific tag
    from a resource. The console also limits the number of resources you can update to 100. So if you need
    to change tags on more than 100 resources, then you'll need to rinse and repeat as often as neccessary
 
    This script will allow you to -Add, -Replace or -Remove a specific tag from any Netowrk Interface Card that
    matches a search criteria using parameters ManageThisTag and ManageThisTagValue. The Merge Function will
    combine Tags from the Virtual Machine that the Network Interface card is attached to. If a tag exist on
    both Network Interface and Virtual Machine, you can specify which of the two values will be kept by using
    the switches -Merge VmWins or -Merge NicWins. The Merge function will also allow you to copy tags from the
    Virtual Machine that the Network Interface card is attached to. By using -Merge CopyFromVM. The Copy function
    will overwrite the existing Tags on the Network Interface card with those from the Virtual Machine.
 
    While running the -merge process, the script will identify and Network Interface Card that is not attached
    to any Virtual Machine. You may want to carefully review that list to see if you need that NIC.
 
    This script is part of a set of ManageTagsOn scripts. Please look for
    ManageTagsOnVM
    ManageTagsOnDisk
    ManageTagsOnNetworkCard
    ManageTagsOnPublicIP
    ManageTagsOnNetworkSecurityGroup
    ManageTagsOnAvailabilitySet
    ManageTagsOnRouteTable
    ManageTagsOnAutomationRunbooks
 
.SYNOPSIS
    Add, Remove, Replace, Merge or Copy Tags on Network Interface Card Resource in Azure
 
.PARAMETER Remove
    The -Remove switch will tell the script to delete the tag specified by ManageThisTag and optionally if the value
    of the Tag match -ManageThisTagValue
 
.PARAMETER Replace
    The -Replace switch will tell the script to delete the tag specified by ManageThisTag and optionally if the value
    of the Tag match -ManageThisTagValue and replace it with a new Tag an Value specified by NewTagKey and NewTagValue
 
.PARAMETER ManageThisTag
    The name of the TAG to be used as a search criteria. Filters only those resources Where-Object this tag exists.
 
.PARAMETER ManageThisTagValue
    The value of the TAG specified by ManageThisTag. This further filters only those resources Where-Object this tag exists
    and it value matches ManageThisTagValue.
 
.PARAMETER FromGroup
    The name of the Resource Group to limit search scope. Filters only those Resources in the specific Resource Group.
 
.PARAMETER Add
    The -Add switch works together with -NewTagKey and -NewTagValue parameters. This will make the script add a new
    tag NewTagKey with value of NewTagValue to the resource that match the search criteria
 
.PARAMETER Merge
    The -Merge parameter has three possibile values VmWins, -NicWins and -CopyFromVm.
    The Merge Function will combine Tags from the Virtual Machine that the Network Interface card is attached to.
    If a tag exist on both Network Interface and Virtual Machine, you can specify which of the two values will
    be kept by using the switches -Merge VmWins or -Merge NicWins. The Merge function will also allow you to copy
    tags from the Virtual Machine that the Network Interface card is attached to. By using -Merge CopyFromVM.
    The Copy function will overwrite the existing Tags on the Network Interface card with those from the Virtual Machine.
 
.PARAMETER WhatIf
    Safe run of the script without any changes to preview changes that would be made.
 
.EXAMPLE
    ManageTagsOnNetworkCard.ps1 -Remove -ManageThisTag "Environment" -FromGroup "test-vm-servers-rg"
 
.EXAMPLE
    ManageTagsOnNetworkCard.ps1 -Replace -ManageThisTag "Environment" -ManageThisTagValue "Test" -NewTagKey "Environment" -NewTagValue "Development"
 
.EXAMPLE
    ManageTagsOnNetworkCard.ps1 -Merge VmWins -FromGroup "test-vm-servers-rg"
 
.EXAMPLE
    ManageTagsOnNetworkCard.ps1 -Merge CopyFromVm
 
.NOTES
    AUTHOR: Alexander Goldberg
    LASTEDIT: Feb 16, 2020
    WEBSITE: www.alexgoldberg.com
#>


[cmdletbinding(
        DefaultParameterSetName='Remove'
    )]

param(
    [Parameter(Mandatory=$true,ParameterSetName = "Remove")]
    [switch]$Remove,

    [Parameter(Mandatory=$true,ParameterSetName = "Replace")]
    [switch]$Replace,

    [Parameter(Mandatory=$true,ParameterSetName = "Remove")]
    [Parameter(Mandatory=$true,ParameterSetName = "Replace")]
    [Parameter(Mandatory=$false,ParameterSetName = "Add")]
    [Parameter(Mandatory=$false,ParameterSetName = "Merge")]
    [string]$ManageThisTag,

    [Parameter(ParameterSetName = "Remove")]
    [Parameter(ParameterSetName = "Replace")]
    [Parameter(ParameterSetName = "Add")]
    [Parameter(ParameterSetName = "Merge")]
    [string]$ManageThisTagValue,

    [Parameter(Mandatory=$true,ParameterSetName = "Replace")]
    [Parameter(Mandatory=$true,ParameterSetName = "Add")]
    [string]$NewTagKey,

    [Parameter(Mandatory=$true,ParameterSetName = "Replace")]
    [Parameter(Mandatory=$true,ParameterSetName = "Add")]
    [string]$NewTagValue,

    [Parameter(ParameterSetName = "Merge")]
    [ValidateSet("NicWins","VmWins","CopyFromVM")]
    [string]$merge,

    [string]$FromGroup,

    [Parameter(ParameterSetName = "Add")]
    [switch]$Add,

    [switch]$WhatIf

)

function Merge-HashTable {
    param(
        [hashtable] $default, # Your original set
        [hashtable] $uppend # The set you want to update/append to the original set
    )

    # Clone for idempotence
    $default1 = $default.Clone();

    # We need to remove any key-value pairs in $default1 that we will
    # be replacing with key-value pairs from $uppend
    foreach ($key in $uppend.Keys) {
        if ($default1.ContainsKey($key)) {
            $default1.Remove($key);
        }
    }

    # Union both sets
    return $default1 + $uppend;
}

#Getting the list of NetworkInterfaces.
if ($PSCmdlet.MyInvocation.BoundParameters.Keys.Contains('ManageThisTagValue')) {
    if ($PSCmdlet.MyInvocation.BoundParameters.Keys.Contains('FromGroup')) {
        $Resources = Get-AzureRmNetworkInterface -ResourceGroupName $FromGroup | Where-Object -FilterScript {$_.Tag.Keys.Count -gt 0 -and $_.Tag.($ManageThisTag) -eq $ManageThisTagValue}
    } else {
        $Resources = Get-AzureRmNetworkInterface | Where-Object -FilterScript {$_.Tag.Keys.Count -gt 0 -and $_.Tag.($ManageThisTag) -eq $ManageThisTagValue}
    }

} elseif ($PSCmdlet.MyInvocation.BoundParameters.Keys.Contains('ManageThisTag')) {
    if ($PSCmdlet.MyInvocation.BoundParameters.Keys.Contains('FromGroup')) {
        $Resources = Get-AzureRmNetworkInterface -ResourceGroupName $FromGroup | Where-Object -FilterScript {$_.Tag.Keys.Count -gt 0 -and $_.Tag.ContainsKey($ManageThisTag)}
    } else {
        $Resources = Get-AzureRmNetworkInterface | Where-Object -FilterScript {$_.Tag.Keys.Count -gt 0 -and $_.Tag.ContainsKey($ManageThisTag)}
    }
} else {
    if ($PSCmdlet.MyInvocation.BoundParameters.Keys.Contains('FromGroup')) {
        $Resources = Get-AzureRmNetworkInterface -ResourceGroupName $FromGroup
    } else {
        $Resources = Get-AzureRmNetworkInterface
    }
}

# Initilize an Array to hold Unassigned Network Interfaces
$UnassignedNIC = New-Object 'System.Collections.Generic.Dictionary[String,String]'

if ($null -ne $Resources) {
    foreach ($Resource in $Resources)
    {
        Write-Output ('processing: ' + $Resource.Name)
        #set UpdateTags to true
        $UpdateTags = $false
        $ResourceTags = $Resource.tag # Getting the list of all the tags for the Network Interface.

        #Check if NetworkInterface is assigned to a VM

        If ($null -ne $Resource.VirtualMachine) {

            if ($Remove -or $Replace) {
                Write-Output ("Tag " + $ManageThisTag + " with value of " + $ManageThisTagValue + " exists in the " + $Resource.Name + " and will be Removed/Replaced")
                $Resource.Tag.Remove($ManageThisTag)
                if ($Replace) { $Resource.Tag.Add($NewTagKey, $NewTagValue) }
                #set UpdateTags to true
                $UpdateTags = $true
            }

            if ($Merge) {
                #Get tags from the Manager VM
                $NewTags = New-Object 'System.Collections.Generic.Dictionary[String,String]' # Creating a new Hashtable variable to store new Tag Values.

                # If NetworkInterface does not have tags then set the $ResourceTags to an empty HashTable
                # This will allow -remove and -merge directives to work without reporting errors on an empty tag values
                if ($null -eq $ResourceTags) {
                       $ResourceTags = New-Object 'System.Collections.Generic.Dictionary[String,String]' # Creating a new Hashtable variable to store new Tag Values.
                }

                #Get id of the Virtual Machine that uses the Network Interface. Property: VirtualMachine
                $VirtualMachine = Get-AzureRmResource -ResourceId $Resource.VirtualMachine.id
                $VirtualMachineTags = $VirtualMachine.Tags

                # If VirtualMachineTags does not have tags then there is nothing to merge, so skip it
                if ($null -ne $VirtualMachineTags) {
                    Switch ($Merge) {
                        "NicWins" {
                            $mergedtags = Merge-HashTable $VirtualMachineTags $ResourceTags
                        }
                        "VmWins" {
                            $mergedtags = Merge-HashTable $ResourceTags $VirtualMachineTags
                        }
                        "CopyFromVM" {
                            $mergedtags = $VirtualMachineTags
                        }
                    }
                    # The merged HashTable uses object dictionary, we need to use String dictionary.
                    # So we loop through the mergedtags and copy all the values to the $NewTags variable
                    foreach ($mergedtag in $mergedtags.GetEnumerator()) {
                           $NewTags.add($mergedtag.Key,$mergedtag.Value)
                    }
                    $Resource.Tag = $NewTags
                    #set UpdateTags to true
                    $UpdateTags = $true
                }
            }

            if ($Add) {
                $Resource.Tag.Add($NewTagKey, $NewTagValue)

                # In addition to the newtag and value, you can also hardcode any additonal tag value key pairs here
                # I know, it's not pretty, but it works if you want to add multiple tags
                #$Resource.Tags.Add("tag name","tag value") # Adding new tag and value
                #$Resource.Tags.Add("tag name","tag value") # Adding new tag and value

                #set UpdateTags to true
                $UpdateTags = $true
            }

            if ($UpdateTags) {
                Write-Output ("Updating Tags on: " + $Resource.Name)
                if (!$WhatIf) {
                    $Resource | Set-AzureRmNetworkInterface
                }
                else {
                    Write-Output "--- new tags ---"
                    Write-Output ($Resource.Tag | Out-String)
                }
            }
        } else {
            Write-Output ($NetwrokResource.Name + "is not assigned to a VM")
            # No VM found, Add to Unassigned Interface hashtable to report at the end of the script run
            $UnassignedNIC.Add($Resource.Name, $Resource.ResourceGroupName)
        }
    }
} else {
    Write-Warning ("No resources found that matched search criteria")
}
if ($UnassignedNIC.Count -gt 0) {
    Write-Warning ($UnassignedNIC | Out-String)
}