riweston

Untitled

Sep 7th, 2018
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2.     .SYNOPSIS
  3.         Runbook for creating Azure Resource Groups
  4.  
  5.     .DESCRIPTION
  6.         This Runbook will create Resource Groups based on user input parameters
  7.  
  8.     .PARAMETER ResourceGroupName
  9.         Specify the Resource Group name
  10.  
  11.     .PARAMETER ResourceGroupRegion
  12.         Region Resource Group will reside in
  13.  
  14.     .PARAMETER SvcName
  15.         SvcName Tag value
  16.  
  17.     .PARAMETER SvcOwner
  18.         SvcOwner Tag value
  19.  
  20.     .PARAMETER CrgCostCode
  21.         CrgCostCode Tag value
  22.  
  23.     .PARAMETER Environment
  24.         Environment Tag value
  25.  
  26.     .EXAMPLE
  27.         Run the Runbook through Azure and specify the name/region/tags with parameters
  28.  
  29.     .NOTES
  30.         Owner:  TSO N&H Cloud and Automation Team ([email protected])
  31.         VSTS:   TSO-NH-Automation/azure/runbooks/new-resourcegroup.ps1
  32.  
  33.         | Author            | QC                | VSTS Story ID     | Release Date  |
  34.         -----------------------------------------------------------------------------
  35.         | Richard Weston    |                   | User Story 777    | 26/07/18      |
  36. #>
  37.  
  38. ## Parameters for RunBook
  39. Param(
  40.     [Parameter( Mandatory = $true )]
  41.     [string]$ResourceGroupName,
  42.  
  43.     [Parameter()]
  44.     [string]$ResourceGroupRegion = "NorthEurope",
  45.  
  46.     [Parameter( Mandatory = $true )]
  47.     [ValidateNotNullOrEmpty()]
  48.     [string]$SvcName,
  49.  
  50.     [Parameter( Mandatory = $true )]
  51.     [ValidateNotNullOrEmpty()]
  52.     [string]$SvcOwner,
  53.  
  54.     [Parameter( Mandatory = $true )]
  55.     [ValidateNotNullOrEmpty()]
  56.     [string]$CrgCostCode,
  57.  
  58.     [Parameter( Mandatory = $true )]
  59.     [ValidateNotNullOrEmpty()]  
  60.     [string]$Environment
  61. )
  62.  
  63. try {
  64.     ######################################
  65.     ##### SUPPORTING FUNCTIONS START #####
  66.     ######################################
  67.  
  68.     <#
  69.         .SYNOPSIS
  70.             Validate tag key/value pair against an Azure Blob Table
  71.  
  72.         .DESCRIPTION
  73.             This function should be used as a helper to validate user entered Azure
  74.             Resource Tags. It requires a storage account and resource group for the
  75.             storage account the Blob Table is stored in. If run successfully the
  76.             casing will be crrected and output to the "Result" property with an Exit
  77.             Code of '0' otherwise '1' will be returned with the last message from the
  78.             "Log" property.
  79.  
  80.         .PARAMETER resourceGroup
  81.             The Resource Group that the Blob Table resides on must be supplied.
  82.  
  83.         .PARAMETER storageAccount
  84.             The Storage Account that the Blob Table resides on must be supplied.
  85.  
  86.         .PARAMETER tagKey
  87.             User entered Tag Key to be validated.
  88.  
  89.         .PARAMETER tagValue
  90.             User entered Tag Value to be validated.
  91.  
  92.         .EXAMPLE
  93.             Test-ValidTags @Params
  94.  
  95.         .NOTES
  96.             Owner:  TSO N&H Cloud and Automation Team ([email protected])
  97.             VSTS:   azure/functions/test-ValidTags.ps1
  98.  
  99.             | Author            | QC                | VSTS Story ID     | Release Date  |
  100.             -----------------------------------------------------------------------------
  101.             | Richard Weston    | Will White        |  | 29/08/18      |
  102.     #>
  103.     function Test-ValidTags {
  104.         param(
  105.             ## Resource Group Storage account resides in
  106.             [Parameter( Mandatory = $true )]
  107.             [ValidateNotNullOrEmpty()]
  108.             [string]$resourceGroup,
  109.             ## Storage Account name
  110.             [Parameter( Mandatory = $true )]
  111.             [ValidateNotNullOrEmpty()]
  112.             [string]$storageAccount,
  113.             ## Name of the tag to validate
  114.             [Parameter( Mandatory = $true )]
  115.             [ValidateNotNullOrEmpty()]
  116.             [string]$tagKey,
  117.             ## Value the tag contains to validate
  118.             [Parameter( Mandatory = $true )]
  119.             [ValidateNotNullOrEmpty()]
  120.             [string]$tagValue
  121.         )
  122.         try {
  123.             #################
  124.             ##### BEGIN #####
  125.             #################
  126.             ## Output Declaration
  127.             class TFL_Output {
  128.                 ################
  129.                 ### PROPERTY ###
  130.                 ################
  131.                 # Output successful execution result
  132.                 [string]
  133.                 $Result = $null
  134.            
  135.                 # Execution exit code
  136.                 [int]
  137.                 hidden
  138.                 $ExitCode  = $null
  139.            
  140.                 # Capture script details here
  141.                 [array]
  142.                 hidden
  143.                 $Log = @()
  144.            
  145.                 ################
  146.                 ###  METHOD  ###
  147.                 ################
  148.                 # Method to append to log property
  149.                 AddLogEntry( [string]$Message ) {
  150.                     # Append to array
  151.                     $This.Log       += [pscustomobject] @{
  152.                         # User logged message
  153.                         Message     = $Message
  154.                         # Generate timestamp for the log
  155.                         TimeStamp   = ( Get-Date -Format hh:mm:ss.ffff )
  156.                     }
  157.                 }
  158.            
  159.                 # Method to return the last entry in $Log
  160.                 [pscustomobject]
  161.                 LastLogEntry() {
  162.                     # Select last entry in $Log
  163.                     return $This.Log[-1]
  164.                 }
  165.            
  166.                 # Return a specified Log entry as a string with timestamp
  167.                 [string]
  168.                 LogToString([int]$logRef) {
  169.                     #Capture Log details as array
  170.                     $logString = @(
  171.                         $This.log[$logRef].TimeStamp
  172.                         $This.log[$logRef].Message
  173.                     )
  174.                     # Stitch strings together and return
  175.                     return ( $logString -join " - " )
  176.                 }
  177.             }
  178.  
  179.             $Output = [TFL_Output]::new()
  180.  
  181.  
  182.             ## Output Declaration
  183.             #################
  184.             #####  END  #####
  185.             #################
  186.  
  187.             #################
  188.             ##### BEGIN #####
  189.             #################
  190.             ## Paramater validation
  191.  
  192.             # $resourceGroup validation
  193.             $validationTestParam = @{
  194.                 Name = $resourceGroup
  195.             }
  196.             $validationTest = Get-AzureRmResourceGroup @validationTestParam
  197.             if ( ! ( $validationTest ) ) {
  198.                 # Set output variables
  199.                 $Output."ExitCode" = 1
  200.                 $Output.AddLogEntry( "Resource Group parameter invalid" )
  201.                 # Break and return output
  202.                 return
  203.             } else {
  204.                 # Log validation pass
  205.                 $Output.AddLogEntry( "Resource Group parameter valid" )
  206.             }
  207.             # Santise test variables
  208.             Clear-Variable -Name validationTest,validationTestParam
  209.  
  210.             # $storageAccount validation
  211.             $validationTestParam = @{
  212.                 ResourceGroupName   = $resourceGroup
  213.                 Name                = $storageAccount
  214.             }
  215.             $validationTest = Get-AzureRmStorageAccount @validationTestParam
  216.             if ( ! ( $validationTest ) ) {
  217.                 # Set output variables
  218.                 $Output."ExitCode" = 2
  219.                 $Output.AddLogEntry( "Storage Account parameter invalid" )
  220.                 # Break and return output
  221.                 return
  222.             } else {
  223.                 # Log validation pass
  224.                 $Output.AddLogEntry( "Storage Account parameter valid" )
  225.             }
  226.             # Santise test variables
  227.             Clear-Variable -Name validationTest,validationTestParam
  228.  
  229.             ## Paramater validation
  230.             #################
  231.             #####  END  #####
  232.             #################
  233.  
  234.             #################
  235.             ##### BEGIN #####
  236.             #################
  237.             ## Script Main
  238.  
  239.             ## Get the storage account context
  240.             $saContextParam = @{
  241.                 ResourceGroupName   = $resourceGroup
  242.                 Name                = $storageAccount
  243.             }
  244.             $saContext = (Get-AzureRmStorageAccount @saContextParam).Context
  245.             # Validate $saContext
  246.             if ( ! ( $saContext ) ) {
  247.                 # Set output variables
  248.                 $Output."ExitCode" = 3
  249.                 $Output.AddLogEntry( "Unable to get storage account context" )
  250.                 # Break and return output
  251.                 return
  252.             } else {
  253.                 # Log validation pass
  254.                 $Output.AddLogEntry( "Storage account context verified" )
  255.             }
  256.             ## Capture the Blob Table as a variable
  257.             $GetAzureStorageTableCrgCostCodeParam = @{
  258.                 Name    = "AzureTags"
  259.                 Context = $saContext
  260.             }
  261.             $blbTblTag = Get-AzureStorageTable @GetAzureStorageTableCrgCostCodeParam
  262.             # Validate Storage Table
  263.             if ( ! ( $blbTblTag ) ) {
  264.                 # Set output variables
  265.                 $Output."ExitCode" = 4
  266.                 $Output.AddLogEntry( "Unable to get storage table" )
  267.                 # Break and return output
  268.                 return
  269.             } else {
  270.                 # Log validation pass
  271.                 $Output.AddLogEntry( "Storage table verified" )
  272.             }
  273.             ## Capture all rows in the table
  274.             $tblTag = Get-AzureStorageTableRowAll -table $blbTblTag
  275.             if ( ! ( $tblTag ) ) {
  276.                 # Set output variables
  277.                 $Output."ExitCode" = 5
  278.                 $Output.AddLogEntry( "Table is blank or inaccessible" )
  279.                 # Break and return output
  280.                 return            
  281.             } else {
  282.                 # Log validation pass
  283.                 $Output.AddLogEntry( "Storage table contents verified" )
  284.             }
  285.             $tblTagTagKeyTest = $tblTag.$TagKey -contains $tagValue
  286.             ## Test if the value is contained in the Blob Table
  287.             if ( ! ( $tblTagTagKeyTest ) ) {
  288.                 # Tag value NOT an exact match
  289.                 $Output."ExitCode" = 6
  290.                 $Output.AddLogEntry( "$( $tagKey ) tag is invalid" )
  291.                 # Break and return output
  292.                 return
  293.             } else {
  294.                 # Log validation pass
  295.                 $Output.AddLogEntry( "Tag validated" )
  296.             }
  297.  
  298.             ## Script Main
  299.             #################
  300.             #####  END  #####
  301.             #################
  302.  
  303.             ## Result
  304.             # Tag value IS an exact match, additional code just captures the casing
  305.             $Output.Result      = $tblTag.$TagKey | Where-Object { $PSItem -contains $tagValue }
  306.             $Output."ExitCode"  = 0
  307.             return
  308.  
  309.         }
  310.         catch {
  311.             $errorMessage = @(
  312.                 "Error in function: Unhandled exception ::"
  313.                 "Line: $($_.InvocationInfo.ScriptLineNumber)"
  314.                 "Line: $($_.InvocationInfo.Line.Trim())"
  315.                 "Error message: $($_.Exception.Message)"
  316.             )  
  317.             # Output errors for debugging and halt runbook
  318.             Write-Error -Message ( $errorMessage -join " " )
  319.             return
  320.         }
  321.         finally {
  322.             ## Return $Output object
  323.             $Output
  324.         }
  325.  
  326.     }
  327.  
  328.     ######################################
  329.     ##### SUPPORTING FUNCTIONS END   #####
  330.     ######################################
  331.  
  332.     ## Connect to Azure with Run As Account
  333.     $Conn = Get-AutomationConnection -Name AzureRunAsConnection
  334.     [hashtable]$AddAzureRMAccountParam = @{
  335.         ServicePrincipal        = $true
  336.         Tenant                  = $Conn.TenantID
  337.         ApplicationId           = $Conn.ApplicationID
  338.         CertificateThumbprint   = $Conn.CertificateThumbprint
  339.     }
  340.     [hashtable]$ConnectAzureADParam = @{
  341.         Tenant                  = $Conn.TenantID
  342.         ApplicationId           = $Conn.ApplicationID
  343.         CertificateThumbprint   = $Conn.CertificateThumbprint
  344.     }
  345.     [void]@(
  346.         Add-AzureRMAccount @AddAzureRMAccountParam
  347.         Set-AzureRmContext -SubscriptionId $Conn.SubscriptionId
  348.         Enable-AzureRmContextAutosave
  349.         Connect-AzureAD @ConnectAzureADParam
  350.     )
  351.     ## Script Main
  352.     ## Test if Resource Group Already Exists
  353.     if ( Get-AzureRmResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue ) {
  354.         Write-Error -Message "Resource group already exists"
  355.         return
  356.     }
  357.     ## Test if SvcOwner is a Group
  358.     #$SvcOwnerGroup = Get-AzureADGroup -SearchString $SvcOwner
  359.     #$SvcOwnerGroup = $SvcOwnerGroup | Where-Object { $SvcOwnerGroup.Mail -contains $SvcOwner }
  360.     $SvcOwnerGroup = Get-AzureADGroup -Filter "mail eq '$SvcOwner'"
  361.     if ( ! ( $SvcOwnerGroup ) ) {
  362.         Write-Error -Message "SvcOwner tag is not a distribution list"
  363.         return
  364.     }
  365.     ## Tag validation variables
  366.     $resourceGroup = "TSO-NH-Automation-MO-rg"
  367.     $storageAccount = "tsonhautomationmoblob"
  368.     # CrgCostCode test parameters
  369.     $TestValidTagsParam = @{
  370.         resourceGroup   = $resourceGroup
  371.         storageAccount  = $storageAccount
  372.         tagKey          = "CrgCostCode"
  373.         tagValue        = $CrgCostCode
  374.     }
  375.     # Environment test parameters
  376.     $TestValidTagsParam = @{
  377.         resourceGroup   = $resourceGroup
  378.         storageAccount  = $storageAccount
  379.         tagKey          = "Environment"
  380.         tagValue        = $Environment
  381.     }
  382.     # Complete tests
  383.     $crgTagTest = Test-ValidTags @TestValidTagsParam
  384.     if ( ! ( $crgTagTest ).ExitCode -eq 0 ) {
  385.         Write-Error -Message "The tag for CrgCostCode entered is invalid"
  386.         Write-Error -Message "Please double-check the tag or contact the team who manages this"
  387.         return
  388.     } else {
  389.         # Set the variable as the output to correct any casing issues
  390.         $CrgCostCode = ( $crgTagTest ).Result
  391.     }
  392.     $envTagTest = Test-ValidTags @TestValidTagsParam
  393.     if ( ! ( $envTagTest ).ExitCode -eq 0 ) {
  394.         Write-Error -Message "The tag for Environment entered is invalid"
  395.         Write-Error -Message "Please double-check the tag or contact the team who manages this"
  396.         return
  397.     } else {
  398.         # Set the variable as the output to correct any casing issues
  399.         $Environment = ( $envTagTest ).Result
  400.     }
  401.  
  402.     # Assemble hashtable for new RG
  403.     [hashtable]$azRGTagTable = @{
  404.         SvcName     = $SvcName
  405.         SvcOwner    = $SvcOwner
  406.         CrgCostCode = $CrgCostCode
  407.         Environment = $Environment
  408.     }
  409.  
  410.     # New Resource Group creation
  411.     [hashtable]$NewAzureRmResourceGroupParam = @{
  412.         Name        = $ResourceGroupName
  413.         Location    = $ResourceGroupRegion
  414.         Tags        = $azRGTagTable
  415.     }
  416.     $azNewRG = New-AzureRmResourceGroup @NewAzureRmResourceGroupParam
  417.     # RBAC settings
  418.     [hashtable]$NewAzureRmRoleAssignment = @{
  419.         ResourceGroupName   = $azNewRG.ResourceGroupName
  420.         RoleDefinitionName  = "Owner"
  421.         ObjectId            = $SvcOwnerGroup.ObjectId
  422.     }
  423.     New-AzureRmRoleAssignment @NewAzureRmRoleAssignment
  424.  
  425. }
  426. catch {
  427.     $errorMessage = @(
  428.         "Error in Runbook: Unhandled exception ::"
  429.         "Line: $($_.InvocationInfo.ScriptLineNumber)"
  430.         "Line: $($_.InvocationInfo.Line.Trim())"
  431.         "Error message: $($_.Exception.Message)"
  432.     )
  433.     # Output errors for debugging and halt runbook
  434.     Write-Error -Message ( $errorMessage -join " " ) -ErrorAction Stop
  435. }
Advertisement
Add Comment
Please, Sign In to add comment