public/Set-AzureResourceTags.ps1


function Set-AzureResourceTags {

<#
 
.SYNOPSIS
Set standard tags for a given Azure resource, or multiple Azure resources
 
.DESCRIPTION
Set-AzureResourceTags cmdlet sets standard tags for a given Azure resource, or multiple Azure resources. Input is a json data, which can be built manually or converted form a csv file.
 
.PARAMETERS jsonObject
Use following data structure (only 'Resource Name' and 'Resource Type' are mandatory for Azure resource correlation, the rest are entirely custom tag key/value pairs):
 
[
    {
        "Resource Name": "",
        "Resource Role": "",
        "Resource Type": "",
        "Resource Class": "",
        "Primary Contact": "",
        "Cost Center": "",
        "Business Value": "",
        "Notes": ""
    }
 
]
 
.EXAMPLE
$<VariableName> = Import-Csv <CSVfilepath>
$<VariableName1> = $<VariableName> | ConvertTo-Json
Set-AzureResourceTags -jsonobject $<VariableName1> -subscriptionname <SubscriptionName> -Verbose
 
#>


    [cmdletbinding()]

    Param (

        [parameter(Mandatory=$true,
            ValueFromPipeline=$true)]
        [string]$jsonobject,

        [parameter(Mandatory=$false)]
        [bool]$replace = $false
    
    )

    Process 
    {

        # check to see if local token exists (ran Login-AzureRMAccount)
        if (($null -eq (Get-AzureRmContext).Account)) {
            Write-Warning "Please run < Login-AzureRMAccount > first to create a session token...exiting."
            break
        }
        
     
 
    
        # convert json literal string to system.object
        Try {
            $targetresources = $jsonobject | ConvertFrom-Json -ErrorAction Stop -Verbose
        }
        Catch {
            $error[0].Exception
            break
        }

        $currentsubscription = (Get-AzureRmContext).subscription.Name

        if (($null -eq $currentsubscription)) {
            Write-Warning "No subscription selected. Run Select-AzureRMSubscription to target a specific subscription, before running this tool again."
            break
        }
        else {
            Write-Verbose "Current subscription is '$currentsubscription'. "
        }

        # get resources in current subscription and reconcile with input data
        Try {
            $resources = Get-AzureRmResource -ErrorAction Stop -Verbose
        }
        Catch {
            $error[0].Exception
            break
        }
        
        $resourcesnotfound = @()
        $foundresources = @()
        $targetresources | ForEach-Object {

        Write-Debug "validating resource name $($_.'resource name')"
        
            if ("$($_.'Resource Name')" -in $resources.name) {
                Write-Verbose "Found $($_.'Resource Name') in current subscription's resources"
                $foundresources += $_
            }
            elseif ($_."resource name" -notin $resources.name) {
                Write-Warning "$($_.'Resource Name') not found in current subscription's resource list"
                $resourcesnotfound += $_
            }
            else {
                Write-Warning "resource reconciliation condition failed"
                break
            }    
        } # end foreach jsonobject loop

        # replace exiting values
        if (($replace -eq $true)) {
            foreach ($resource in $foundresources) {
        
                $totag = $resources | Where-Object {($_.name -eq "$($resource.'Resource Name')" -and ($_.resourcetype -eq "$($resource.'resource type')"))}
                
                if (($totag).count -ge 2) {
                    Write-Warning "Multiple resources found using resource name of $($resource.'Resource Name') and type of $($resource.'Resource Type'). Remediate the resource below manually."
                    $totag
                    break
                }


                # convert pscustomobject to hashtable to enumerate keys/values
                $tags = Convert-JsonToHash -json $resource

                Try {
                
                    $parameters = @{
                        ResourceGroupName = "$($totag.resourcegroupname)";
                        ResourceName      = "$($totag.resourcename)";
                        ResourceType      = "$($totag.resourcetype)";
                        Tags              = $tags

                    }
                
                    $tagoperation = Set-AzureRmResource @parameters -ErrorAction Stop -Verbose -Force
                }
                Catch {
                    $error[0].Exception
                    continue
                }
            
            }

        }
        
        elseif (($replace -eq $false)) {
            foreach ($resource in $foundresources) {
        
                $totag = $resources | Where-Object {($_.name -eq "$($resource.'Resource Name')" -and ($_.resourcetype -eq "$($resource.'resource type')"))}

                if (($totag).count -ge 2) {
                    Write-Warning "Multiple resources found using resource name of $($resource.'Resource Name') and type of $($resource.'Resource Type'). Remediate the resource below manually."
                    $totag
                    break
                }

                # convert pscustomobject to hashtable to enumerate keys/values
                $tags = Convert-JsonToHash -json $resource

                Try {
                    $ErrorActionPreference = 'Stop'

                    $tags += ($totag).tags

                }
                Catch [System.ArgumentException] {
                    Write-Warning "$($error[0].Exception.Message)"
                }
                Finally {
                    $ErrorActionPreference = 'Continue'
                }


                Try {
                
                    $parameters = @{
                        ResourceGroupName = "$($totag.resourcegroupname)";
                        ResourceName      = "$($totag.resourcename)";
                        ResourceType      = "$($totag.resourcetype)";
                        Tags              = $tags

                    }
                
                    $tagoperation = Set-AzureRmResource @parameters -ErrorAction Stop -Verbose -Force
                }
                Catch {
                    $error[0].Exception
                    continue
                }
            
            }

        }

        else {
            Write-Warning "Failed to evaluate whether or not to replace tags."
            break
        }



        if (($resourcesnotfound.Count -ne 0)) {
            Write-Warning "Some resources were not found in the current subscription..."
            return $resourcesnotfound
        }
        else {
            Write-Verbose "All resources accounted for in current subscription."
        }


    } # end process block

} # end Set-AzureResourceTags function