-
-
Save tyconsulting/2a6b84938f871bcfb4b896868cf37ab8 to your computer and use it in GitHub Desktop.
Test Azure Resource Manager (ARM) template using Pester
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
<# | |
.SYNOPSIS | |
Test Azure Resource Manager (ARM) template using Pester. The following tests are performed: | |
* Template file validation | |
* Test if the ARM template file exists | |
* Test if the ARM template is a valid JSON file | |
* Template content validation | |
* Contains all required elements | |
* Only contains valid elements | |
* Has valid Content Version | |
* Only has approved parameters | |
* Only has approved variables | |
* Only has approved functions | |
* Only has approved resources | |
* Only has approved outputs | |
.DESCRIPTION | |
.PARAMETER -TemplatePath | |
The path to the ARM Template that needs to be tested against. | |
.PARAMETER -parameters | |
The names of all parameters the ARM template should contain (optional). | |
.PARAMETER -variables | |
The names of all variables the ARM template should contain (optional). | |
.PARAMETER -functions | |
The list of all the functions (namespace.member) the ARM template should contain (optional). | |
.PARAMETER -resources | |
The list of resources (of its type) the ARM template should contain. Only top level resources are supported. child resources defined in the templates are not supported. | |
.PARAMETER -output | |
The names of all outputs the ARM template should contain (optional). | |
.EXAMPLE | |
# Test ARM template file with parameters, variables, functions, resources and outputs: | |
$params = @{ | |
TemplatePath = 'c:\temp\azuredeploy.json' | |
parameters = 'virtualMachineNamePrefix', 'virtualMachineSize', 'adminUsername', 'virtualNetworkResourceGroup', 'virtualNetworkName', 'adminPassword', 'subnetName' | |
variables = 'nicName', 'publicIpAddressName', 'publicIpAddressSku', 'publicIpAddressType', 'subnetRef', 'virtualMachineName', 'vnetId' | |
functions = 'tyang.uniqueName' | |
resources = 'Microsoft.Compute/virtualMachines', 'Microsoft.Network/networkInterfaces', 'Microsoft.Network/publicIpAddresses' | |
outputs = 'adminUsername' | |
} | |
.\Test.ARMTemplate.ps1 @params | |
.EXAMPLE | |
# Test ARM template file with only the resources elements: | |
$params = @{ | |
TemplatePath = 'c:\temp\azuredeploy.json' | |
resources = 'Microsoft.Compute/virtualMachines', 'Microsoft.Network/networkInterfaces', 'Microsoft.Network/publicIpAddresses' | |
} | |
.\Test.ARMTemplate.ps1 @params | |
#> | |
<# | |
====================================== | |
AUTHOR: Tao Yang | |
DATE: 09/09/2018 | |
Version: 1.0 | |
Comment: Pester Test for ARM Template | |
====================================== | |
#> | |
[CmdLetBinding()] | |
param ( | |
[Parameter(Mandatory=$true)] | |
[string]$TemplatePath, | |
[Parameter(Mandatory=$false)] | |
[string[]]$parameters, | |
[Parameter(Mandatory=$false)] | |
[string[]]$variables, | |
[Parameter(Mandatory=$false)] | |
[string[]]$functions, | |
[Parameter(Mandatory=$true)] | |
[string[]]$resources, | |
[Parameter(Mandatory=$false)] | |
[string[]]$outputs | |
) | |
#variables | |
$requiredElements = New-object System.Collections.ArrayList | |
$optionalElements = New-Object System.Collections.ArrayList | |
[void]$requiredElements.Add('$schema') | |
[void]$requiredElements.Add('contentversion') | |
[void]$requiredElements.Add('resources') | |
[void]$optionalElements.Add('parameters') | |
[void]$optionalElements.Add('variables') | |
[void]$optionalElements.Add('functions') | |
[void]$optionalElements.Add('outputs') | |
#Read template file | |
$TemplateContent = Get-Content $TemplatePath -Raw -ErrorAction SilentlyContinue | |
$TemplateJson = ConvertFrom-Json -InputObject $TemplateContent -ErrorAction SilentlyContinue | |
If ($TemplateJson) | |
{ | |
$TemplateElements = $TemplateJson.psobject.Properties.name.tolower() | |
} else { | |
$TemplateElements = $null | |
} | |
#determine what tests to perform | |
If ($PSBoundParameters.ContainsKey('parameters')) | |
{ | |
$bCheckParameters = $true | |
} | |
If ($PSBoundParameters.ContainsKey('variables')) | |
{ | |
$bCheckVariables = $true | |
} | |
If ($PSBoundParameters.ContainsKey('functions')) | |
{ | |
$bCheckFunctions = $true | |
} | |
If ($PSBoundParameters.ContainsKey('outputs')) | |
{ | |
$bCheckOutputs = $true | |
} | |
#Pester tests | |
Describe 'ARM Template Validation' { | |
Context 'Template File Validation' { | |
It 'Template File Exists' { | |
Test-Path $TemplatePath -PathType Leaf -Include '*.json' | Should Be $true | |
} | |
It 'ARM Template is a valid JSON file' { | |
$TemplateContent | ConvertFrom-Json -ErrorAction SilentlyContinue | Should Not Be $Null | |
} | |
} | |
Context 'Template Content Validation' { | |
It "Contains all required elements" { | |
$bValidRequiredElements = $true | |
Foreach ($item in $requiredElements) | |
{ | |
if (-not $TemplateElements.Contains($item)) | |
{ | |
$bValidRequiredElements = $false | |
Write-Output "template does not contain '$item'" | |
} | |
} | |
$bValidRequiredElements | Should be $true | |
} | |
It "Only contains valid elements" { | |
$bValidElements = $true | |
Foreach ($item in $TemplateElements) | |
{ | |
if ((-not $requiredElements.Contains($item)) -and (-not $optionalElements.Contains($item))) | |
{ | |
$bValidElements = $false | |
} | |
} | |
$bValidElements | Should be $true | |
} | |
It "Has valid Content Version" { | |
If ($TemplateJson.contentVersion -match '^[0-9]+.[0-9]+.[0-9]+.[0-9]+$') | |
{ | |
$bValidContentVersion = $true | |
} else { | |
$bValidContentVersion = $false | |
} | |
$bValidContentVersion | Should be $true | |
} | |
If ($bCheckParameters -eq $true) | |
{ | |
It "Only has approved parameters" { | |
$parametersFromTemplateFile = $TemplateJson.parameters.psobject.Properties.name | Sort-Object | |
$strParametersFromTemplateFile = $parametersFromTemplateFile -join ',' | |
$parameters = $parameters | Sort-Object | |
$strParameters = $parameters -join ',' | |
$strParametersFromTemplateFile | Should be $strParameters | |
} | |
} | |
if ($bCheckVariables) | |
{ | |
It "Only has approved variables" { | |
$variablesFromTemplateFile = $TemplateJson.variables.psobject.Properties.name | Sort-Object | |
$variables = $variables | Sort-Object | |
$strVariablesFromTemplate = $variablesFromTemplateFile -join ',' | |
$strVariables = $variables -join ',' | |
$strVariablesFromTemplate | Should be $strVariables | |
} | |
} | |
if ($bCheckFunctions) | |
{ | |
It "Only has approved functions" { | |
#parse functions from the template file | |
$arrFunctionsFromTemplateFile = @() | |
Foreach ($item in $TemplateJson.functions) | |
{ | |
foreach ($member in $item.members.psobject.Properties.name) | |
{ | |
$arrFunctionsFromTemplateFile += "$($item.namespace).$member" | |
} | |
} | |
$arrFunctionsFromTemplateFile = $arrFunctionsFromTemplateFile | Sort-Object | |
$strFunctionsFromTemplateFile = $arrFunctionsFromTemplateFile -join ',' | |
#parse input parameter functions | |
$arrApprovedFunctions = $functions | Sort-Object | |
$strApprovedFunctions = $arrApprovedFunctions -join "," | |
$strFunctionsFromTemplateFile | Should be $strApprovedFunctions | |
} | |
} | |
It "Only has approved resources" { | |
$resourcesFromTemplate = $TemplateJson.resources.type | Sort-Object | |
$strResourcesFromTemplate = $resourcesFromTemplate -join ',' | |
$resources = $resources | Sort-Object | |
$strResources = $resources -join ',' | |
$strResourcesFromTemplate | Should be $strResources | |
} | |
If ($bCheckOutputs) | |
{ | |
It "Only has approved outputs" { | |
$outputsFromTemplate = $TemplateJson.outputs.psobject.Properties.name | Sort-Object | |
$strOutputsFromTemplate = $outputsFromTemplate -join ',' | |
$outputs = $outputs | Sort-Object | |
$strOutputs = $outputs -join ',' | |
$strOutputsFromTemplate | Should be $strOutputs | |
} | |
} | |
} | |
} | |
#Done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment