Last active
May 7, 2020 18:38
-
-
Save brucedkyle/7e4a837e5e144cfc92e9c84381caa5d1 to your computer and use it in GitHub Desktop.
Boilerplate to deploy ARM Templates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 5.1 | |
#Requires -Modules Az.Resources, Az.Storage | |
<# | |
.SYNOPSIS | |
Deploys the resource using the boilerplate template | |
.DESCRIPTION | |
Deploys the boilerplate template to the resource group. | |
.PARAMETER SubscriptionID | |
The Azure Subscription ID, such as "9f241d6e-16e2-4b2b-a485-cc546f04799b". Uses the current subscription as the default. | |
.PARAMETER ResourceGroupName | |
Mandatory. Resource group name. The resource group needs to exist, otherwise the script throws an error. | |
.PARAMETER ProjectName | |
Mandatory. | |
Should follow naming convention https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/naming-and-tagging | |
Note: the boilerplate template provides the default prefix to the name, such as "vnet-$resourceName | |
Note: the boilerplate template fixes the default prefix and appends the name to make it unique for storage accounts | |
Suggested: $location_abbr + "-" + "$project_name" + "$environment" | |
.PARAMETER Mode | |
Default to Incremental. | |
Complete: In complete mode, Resource Manager deletes resources that exist in the resource group but are not specified in the template. | |
Incremental: In incremental mode, Resource Manager leaves unchanged resources that exist in the resource group but are not specified in the template. | |
.PARAMETER Tags | |
The tags. If absent, the template will use the default tags. | |
$createdData = Get-Date -Format "yyyy-MM-dd" | |
$tags = @{"Cost Center"=$costCenter; "Location"=$location; "Environment"= $environment; "Project"=$OrganizationName; "Owner"=$owner; "Created Date"=$createdData; "Tier"="Management"; "Application name"=$appName } | |
.NOTES | |
Version: 1.0.2 | |
Author: Bruce Kyle | |
Creation Date: 5/7/2020 | |
Purpose/Change: Publish as GitHub Gist | |
Requires: | |
- resource group must exist | |
- boilerplate.deploy.json, which deploys a storage account | |
- The storage account as deployed does not pass Security Center requirements | |
Copyright 2020 Stretegic Datatech LLC | |
License: MIT https://opensource.org/licenses/MIT | |
.EXAMPLE | |
$resourceGroupName = "rg-testme" | |
$tags = @{ "Cost Center" = "DevTest"; "Location"="West US 2" } | |
New-AzResourceGroup -Name $resourceGroupName -Location "West US 2" -Tags $tags | |
.\boilerplate-armtemplate.ps1 -SubscriptionID dfa5bf78-5552-4332-ba0b-f9efdaa816e5 ` | |
-ResourceGroupName $resourceGroupName ` | |
-ProjectName "test-ing" ` | |
-Mode "Complete" ` | |
-Tags $tags -Verbose | |
#> | |
[CmdletBinding(SupportsShouldProcess=$True)] | |
#--------[Params]--------------- | |
Param( | |
[Parameter(Mandatory=$false)] [string] $SubscriptionID, | |
[Parameter(Mandatory)] [string] $ResourceGroupName, | |
[Parameter(Mandatory)] [string] $ProjectName, | |
[Parameter(Mandatory=$false)] [string] $Mode = "Incremental", | |
[Parameter(Mandatory=$false)] [object] $Tags = $null | |
) | |
#--------[Script]--------------- | |
Set-StrictMode -Version Latest | |
$ErrorActionPreference = "Stop" | |
pushd $PSScriptRoot | |
try { | |
#### | |
# Set subscription | |
#### | |
if ($SubscriptionId -eq $null) { | |
$SubscriptionId = (Get-AzContext).Subscription.SubscriptionId | |
} | |
Set-AzContext -Name "AzureContext" -SubscriptionId $SubscriptionId -Force | |
#### | |
# Basic error checking for the resource group and resource group name | |
#### | |
If ( $ResourceGroupName.Length -gt 90 ) { | |
$error = "Resource group name '$ResourceGroupName' is too long. Must be fewer than 90 characters." | |
Write-Output $error | |
throw $error | |
} | |
Get-AzResourceGroup -Name $ResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue | |
if ($notPresent) | |
{ | |
# ResourceGroup doesn't exist | |
$error = "Resource group '$ResourceGroupName' does not exist. Create resource group before calling this Cmdlet" | |
Write-Output $error | |
throw $error | |
} | |
#must be shorter than 64 characters after the resource names are appended with up to 5 characters | |
If ( $ProjectName.Length -gt 59 ) { | |
$error = "Resource name '$ProjectName' is too long. Must be fewer than 59 characters." | |
Write-Output $error | |
throw $error | |
} | |
#### | |
# Prepare to add resource | |
#### | |
$ProjectName = $ProjectName.ToLower() | |
# need to remove the hyphens from the resource name for storage accounts | |
$paramObject = @{ | |
'resourceName' = $ProjectName -replace '-' | |
} | |
If ($PSBoundParameters.ContainsKey('Tags')) { | |
$paramObject += @{'resourceTags' = $Tags} | |
} | |
$deploymentName = $ProjectName + "-resource-deployment" | |
$parameters = @{ | |
'Name' = $deploymentName | |
'ResourceGroupName' = $ResourceGroupName | |
'TemplateFile' = '.\boilerplate.deploy.json' | |
'TemplateParameterObject' = $paramObject | |
'Mode' = $Mode | |
} | |
Write-Verbose "Deploying resource: $ProjectName" | |
New-AzResourceGroupDeployment @parameters | |
<# | |
New-AzResourceGroupDeployment -ResourceGroupName "ContosoEngineering" ` | |
-TemplateFile "D:\Azure\Templates\EngineeringSite.json" ` | |
-TemplateParameterFile "D:\Azure\Templates\EngSiteParms.json" | |
#> | |
#case matters on return value keys | |
$resourceID = (Get-AzResourceGroupDeployment ` | |
-ResourceGroupName $ResourceGroupName ` | |
-Name $deploymentName).Outputs.resourceId.value | |
Write-Verbose "Resource deployment successful: $resourceID" | |
} | |
catch | |
{ | |
Write-Host "Deployment failed: $ProjectName" -ForegroundColor Red | |
$ErrorMessage = $_.Exception.Message | |
Write-Host $ErrorMessage | |
} | |
finally | |
{ | |
popd | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
:' Boilerplate bash script | |
.NOTES | |
Version: 1.0.1 | |
Author: Bruce Kyle | |
Creation Date: 5/7/2020 | |
Purpose/Change: Not yet complete | |
Requires: | |
- resource group must exist | |
- boilerplate.deploy.json, which deploys a storage account | |
Copyright 2020 Stretegic Datatech LLC | |
License: MIT https://opensource.org/licenses/MIT | |
.EXAMPLE | |
chmod a+x boilerplate-deploy.sh | |
bash boilerplate-deploy.sh --subscription | |
' | |
function displayHelp () { | |
# Using a here doc with standard out. | |
cat <<-END | |
Usage: | |
------ | |
-h | --help | |
Display this help | |
-v | --verbose | |
Provide additional debugging information. | |
--subscriptionID | |
The subscription ID. Defaults to the current subscription id | |
-n | --resourceGroupName | |
The name of the resource group | |
--projectName | |
The name of the project. It used when creating the names of the resources | |
--mode | |
Complete or Incremental. Default is Incremental | |
-t | --tags | |
The tags to apply to the resources | |
Example: | |
chmod a+x boilerplate-deploy.sh | |
TAGS='"Cost Center" = "DevTest"; "Location"="West US 2"' | |
az group create --name $resourceGroupName --location "West US 2" -tags $TAGS | |
bash boilerplate-deploy.sh --subscriptionID dfa5bf78-5552-4332-ba0b-f9efdaa816e5 \ | |
--resourceGroupName $resourceGroupName \ | |
--projectName "test-ing" \ | |
--mode "Complete" \ | |
--tags $TAGS --verbose | |
Requires jq | |
END | |
} | |
## defaults | |
VERBOSE=false | |
MODE="Incremental" | |
TAGS="" | |
SUBSCRIPTIONID=az account list | jq -r '.[].id' | |
## get from args | |
for arg in "$@" | |
do | |
if [ "$arg" == "--help" ] || [ "$arg" == "-h" ] | |
then | |
displayHelp | |
exit | |
;; | |
fi | |
if [ "$arg" == "--verbose" ] || [ "$arg" == "-v" ] | |
then | |
VERBOSE=true | |
fi | |
if [ "$arg" == "--subscriptionID" ] || [ "$arg" == "-s" ] | |
then | |
SUBSCRIPTIONID=$arg | |
fi | |
if [ "$arg" == "--resourceGroupName" ] || [ "$arg" == "-n" ] | |
then | |
RESOURCEGROUPNAME=$arg | |
fi | |
if [ "$arg" == "--projectName" ] || [ "$arg" == "-p" ] | |
then | |
PROJECTNAME=$arg | |
fi | |
if [ "$arg" == "--tags" ] || [ "$arg" == "-t" ] | |
then | |
TAGS=$arg | |
fi | |
done | |
if VERBOSE | |
then | |
echo "subscriptionID: "$SUBSCRIPTIONID | |
echo "resourceGroupName: "$RESOURCEGROUPNAME | |
echo "projectName: "$PROJECTNAME | |
echo "tags: "$TAGS | |
echo "mode: "$MODE | |
echo "verbose: "$VERBOSE | |
fi | |
# _main() | |
# | |
# Usage: | |
# _main [<options>] [<arguments>] | |
{ # try | |
command1 && \ | |
TEMPLATEFILE=".\boilerplate-deploy.json" && \ | |
DEPLOYMENT=$(az deployment group create \ | |
--name deploy-$PROJECTNAME \ | |
--resource-group $RESOURCEGROUPNAME \ | |
--template-file $TEMPLATEFILE) | |
echo "deploy-$PROJECTNAME complete" | |
if VERBOSE | |
then | |
echo "reployment results: "$DEPLOYMENT | |
fi | |
} || { # catch | |
# save log for exception | |
} | |
# Call `_main` after everything has been defined. | |
_main "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", | |
"contentVersion": "1.0.0.0", | |
"parameters": { | |
"resourceName": { | |
"type": "string", | |
"metadata": { | |
"description": "Specifies the name of the resourcee." | |
} | |
}, | |
"resourceTags": { | |
"type": "object", | |
"defaultValue": { | |
"Cost Center": "Admin" | |
} | |
} | |
}, | |
"variables": { | |
"uniqueString": "[uniqueString(subscription().id, parameters('resourceName'))]", | |
"storageAccountName": "[toLower(substring(replace(concat('st', parameters('resourceName'), variables('uniqueString'), variables('uniqueString')), '-', ''), 0, 23) )]" | |
}, | |
"resources": [ | |
{ | |
"apiVersion": "2019-06-01", | |
"kind": "StorageV2", | |
"location": "[resourceGroup().location]", | |
"name": "[variables('storageAccountName')]", | |
"properties": { | |
"supportsHttpsTrafficOnly": true | |
}, | |
"sku": { | |
"name": "Standard_LRS" | |
}, | |
"type": "Microsoft.Storage/storageAccounts", | |
"tags": "[parameters('resourceTags')]" | |
} | |
], | |
"outputs": { | |
"resourceId": { | |
"type": "string", | |
"value": "[resourceId('Microsoft.Storage/storageAccounts',variables('storageAccountName'))]" | |
}, | |
"storageAccountName": { | |
"type": "string", | |
"value": "[variables('storageAccountName')]" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment