ManageTagsOnNetworkCard.ps1


<#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)
}