Advertisement
Guest User

Untitled

a guest
May 18th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ## Helper Functions
  2. <#
  3.     Helper function for merging hashtables
  4.     <https://stackoverflow.com/questions/8800375/merging-hashtables-in-powershell-how>
  5. #>
  6.  
  7. function Merge-HashTable {
  8.     param(
  9.         [hashtable] $OriginTable, # your original set
  10.         [hashtable] $Append # the set you want to update/Append to the original set
  11.     )
  12.  
  13.     # clone for idempotence
  14.     $OriginTable1 = $OriginTable.Clone() ;
  15.  
  16.     # we need to remove any key-value pairs in $OriginTable1 that we will
  17.     # be replacing with key-value pairs from $uppend
  18.     foreach ($key in $Append.Keys) {
  19.         if ($OriginTable1.ContainsKey($key)) {
  20.             $OriginTable1.Remove($key) ;
  21.         }
  22.     }
  23.  
  24.     # union both sets
  25.     return $OriginTable1 + $Append ;
  26. }
  27.  
  28. ## Runbook Variables
  29. # Resource types that are untaggable
  30. $exAzureResources = @(
  31.     "Microsoft.ClassicNetwork/virtualNetworks"
  32.     "Microsoft.ClassicStorage/storageAccounts"
  33.     "Microsoft.ClassicCompute/domainNames"
  34.     "Microsoft.ClassicCompute/virtualMachines"
  35.     "Microsoft.OperationsManagement/solutions"
  36.     "Microsoft.DomainRegistration/domains"
  37.     "microsoft.insights/alertrules"
  38.     "microsoft.insights/webtests"
  39.     "TrendMicro.DeepSecurity/accounts"
  40.     "Microsoft.Automation/automationAccounts/configurations"
  41. )
  42.  
  43. # Counters for results
  44. $tagCounterSuccess      = 0
  45. $tagCounterFail         = 0
  46. $tagCounterSkip         = 0
  47. $tagCounterNull         = 0
  48. $tagCounterUntaggable   = 0
  49. $tagCounterError        = 0
  50.  
  51. ## Connect to Azure with Run As account
  52. $Conn = Get-AutomationConnection -Name AzureRunAsConnection
  53. $azRMAccountParams = @{
  54.     ServicePrincipal        = $true
  55.     Tenant                  = $Conn.TenantID
  56.     ApplicationId           = $Conn.ApplicationID
  57.     CertificateThumbprint   = $Conn.CertificateThumbprint
  58. }
  59. Add-AzureRMAccount @azRMAccountParams | Out-Null
  60.  
  61. ## Script main
  62. try {
  63.     /write-host
  64.     # Capture Tags from Resource Group
  65.     $azResourceGroups = Get-AzureRmResourceGroup
  66.  
  67.     # Iterate through groups and set tags
  68.     foreach ($azResourceGroup in $azResourceGroups) {
  69.         # Get Resources in the Resource Group
  70.         $azResources = Get-AzureRmResource | Where-Object {
  71.             $_.ResourceGroupName -like $azResourceGroup.ResourceGroupName
  72.         }
  73.         # Standard TFL tags
  74.         $tflTags = @{
  75.             "SvcName"       = $null
  76.             "SvcOwner"      = $null
  77.             "CrgCostCode"   = $null
  78.             "Environment"   = $null
  79.         }
  80.         # Temp var to store RG tags before merge
  81.         $tempTable = @{}
  82.         # Test for Tags property
  83.         switch ($azResourceGroup.PSObject.Properties['Tags']) {
  84.             # If Tags property is present
  85.             ({$PSItem.Value})
  86.             {
  87.                 # Iterate through Resource Group Tags
  88.                 foreach ($kvpRG in $azResourceGroup.Tags.GetEnumerator()) {
  89.                     # Iterate through TFL Tags
  90.                     foreach ($kvpTag in $tflTags.GetEnumerator()) {
  91.                         # If match is found add Resource Group Tag/Value to $tempTable
  92.                         if ($kvpTag.Key -like $kvpRG.Key) {
  93.                             $tempTable.Add($kvpRG.Key,$kvpRG.Value)
  94.                         }
  95.                     }
  96.                 }
  97.             }
  98.             # If Tags property is not present
  99.             ({!($PSItem.Value)})
  100.             {
  101.                 $tagCounterNull++
  102.                 # Log this for informational purposes
  103.                 Write-Output "No Tags set on $($azResourceGroup.ResourceGroupName)"
  104.             }
  105.         }
  106.  
  107.         # Merge TFL Tags with the Resource Group Tags
  108.         # We do it this way so that even if it's blank the key is added
  109.         $mergeTableRGParams = @{
  110.             "OriginTable"   = $tflTags
  111.             "Append"        = $tempTable
  112.         }
  113.         $mergeTableRG = Merge-HashTable @mergeTableRGParams
  114.  
  115.         # Iterate through the Resources
  116.         foreach ($azResource in $azResources) {
  117.             # Test if resourceType is classic
  118.             switch ($azResource.ResourceType) {
  119.                 # If in the exclude list ignore
  120.                 ({$PSItem -in $exAzureResources})
  121.                 {
  122.                     $tagCounterUntaggable++
  123.                     break
  124.                     # Uncomment for debugging purposes
  125.                     #Write-Output "$($azResource.ResourceName) is not a taggable resource"
  126.                 }
  127.                 # If not in the exclude list
  128.                 ({!($PSItem -in $exAzureResources)})
  129.                 {
  130.                     continue
  131.                 }
  132.             } # End Classic Resource test
  133.             # Test each Resource for Tags property
  134.             switch ($azResource.PSObject.Properties['Tags']) {
  135.                 # If Tags property is present
  136.                 ({$PSItem})
  137.                 {
  138.                     # Capture Tags hashtable to var
  139.                     $azResourceTags = $azResource.Tags
  140.                 }
  141.                 # If Tags property is not present
  142.                 ({!($PSItem)})
  143.                 {
  144.                     # Create blank/dummy hashtable for the merge
  145.                     $azResourceTags = @{}
  146.                 }
  147.             }
  148.  
  149.             # Final merge with all tags for resource
  150.             $mergeTable = Merge-HashTable -OriginTable $mergeTableRG -Append $azResourceTags
  151.  
  152.             # Test if tags are up to date
  153.             # Convert hastables to PSCustomObject so that we can use Compare-Object
  154.             $currentTags = [PSCustomObject]$azResourceTags
  155.             $newTags = [PSCustomObject]$mergeTable
  156.             switch (!(Compare-Object $currentTags.PSObject.Properties $newTags.PSObject.Properties)) {
  157.                 # If tags match skip
  158.                 ({$PSItem})
  159.                 {
  160.                     $tagCounterSkip++
  161.                     break
  162.                     # Commented out to avoid noise
  163.                     # Uncomment for debugging purposes
  164.                     #Write-Output "Skip $($azResource.ResourceName)"
  165.                 }
  166.                 # If mismatch then tag
  167.                 ({!($PSItem)})
  168.                 {
  169.                     continue
  170.                 }
  171.             } # End Tagging switch
  172.             try {
  173.                 # Get-AzureRmResource Paramaters
  174.                 $GetAzureRmResourceParams = @{
  175.                     ResourceName        = $azResource.ResourceName
  176.                     ResourceGroupName   = $azResourceGroup.ResourceGroupName
  177.                 }
  178.                 # Set-AzureRmResource Parameters
  179.                 $SetAzureRmResourceParams = @{
  180.                     Tag     = $mergeTable
  181.                     Force   = $true
  182.                 }
  183.                 # Run tagging command
  184.                 Write-Output "Tagging $($azResource.ResourceName)..."
  185.                 Get-AzureRmResource @GetAzureRmResourceParams | Set-AzureRmResource @SetAzureRmResourceParams | Out-Null
  186.                 # Verify Tagging was successful
  187.                 # Grab new Tags
  188.                 $verifyTagsTest = [PSCustomObject](Get-AzureRmResource @GetAzureRmResourceParams).Tags
  189.                 # Compare current tags to what *SHOULD* have been applied
  190.                 switch (!(Compare-Object $verifyTagsTest.PSObject.Properties $newTags.PSObject.Properties)) {
  191.                     # If match, log successfull
  192.                     ({$PSItem})
  193.                     {
  194.                         $tagCounterFail++
  195.                         Write-Warning -Message "$($azResource.ResourceName) failed tagging"
  196.                         Write-Warning -Message "Error message: $($Error[0])"
  197.                     }
  198.                     # If they don't match log and log last error for debugging
  199.                     ({!($PSItem)})
  200.                     {
  201.                         $tagCounterSuccess++
  202.                         Write-Output "$($azResource.ResourceName) was tagged successfully"
  203.                     }
  204.                 }
  205.             }
  206.             catch {
  207.                 $tagCounterError++
  208.                 Write-Warning -Message "Unable to set tag"
  209.                 Write-Warning -Message "Error message: $($Error[0])"
  210.             }
  211.         } # End Resource loop
  212.     } # End Resource Group loop
  213.  
  214.     ## Final Script Output
  215.     $outputTable = @{
  216.         "Resources Tagged"          = $tagCounterSuccess
  217.         "Resources Failed Tagging"  = $tagCounterFail
  218.         "Resources Skipped Tagging" = $tagCounterSkip
  219.         "Resource Groups w/o Tags"  = $tagCounterNull
  220.         "Resources Untaggable"      = $tagCounterUntaggable
  221.         "Errors"                    = $tagCounterError
  222.     }
  223.     $Output = [PSCustomObject]$outputTable
  224.     return $Output
  225. }
  226. catch {
  227.     # Capture all errors
  228.     $errorMessage = @(
  229.         "Error in Runbook: Unhandled exception ::"
  230.         "Line: $($_.InvocationInfo.ScriptLineNumber)"
  231.         "Line: $($_.InvocationInfo.Line.Trim())"
  232.         "Error message: $($_.exception.message)"
  233.     )
  234.     # Output errors for debugging and halt runbook
  235.     throw ($errorMessage -join " ") |Out-Null
  236. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement