testcases/deploymentTemplate/Location-Should-Not-Be-Hardcoded.test.ps1

param(
[Parameter(Mandatory=$true)]
[string]$TemplateText,

[Parameter(Mandatory=$true)]
[PSObject]$TemplateObject,

[Parameter(Mandatory=$true)]
[string]$TemplateFileName,

[switch]$IsMainTemplate
)

# First, create a copy of the template object
$TemplateObjectCopy = $templateText | ConvertFrom-Json
# Then remove the location property
$TemplateObjectCopy.parameters.psobject.properties.remove('location')
# and turn it back into JSON.
$TemplateWithoutLocationParameter = $TemplateObjectCopy | 
    ConvertTo-Json -Depth 10        

# Now get the location parameter
$locationParameter = $templateObject.parameters.location

# All location parameters must be of type "string" in the parameter declaration
if($locationParameter -ne $null -and $locationParameter.type -ne "string"){
    Write-Error "The location parameter must be a 'string' type in the parameter declaration `"$($locationParameter.type)`"" -ErrorId Location.Parameter.TypeMisMatch -TargetObject $parameter
}

# In mainTemplate:
# there must be a parameter named "location"
# if that parameter has a defaultValue, it must be the expression [resourceGroup().location]
if ($IsMainTemplate){ 
    if($locationParameter.defaultValue -and 
      "$($locationParameter.defaultvalue)".Trim() -ne '[resourceGroup().location]' -and 
      "$($locationParameter.defaultvalue)".Trim() -ne 'global') {
            Write-Error "The defaultValue of the location parameter in the main template must not be a specific location. `
                         The default value must be [resourceGroup().location] or 'global'. It is `"$($locationParameter.defaultValue)`""
 -ErrorId Location.Parameter.Hardcoded -TargetObject $parameter
}
# In all other templates:
# if the parameter named "location" exists, it must not have a defaultValue property
# Note that Powershell will count an empty string (which should fail the test) as null if not explictly tested, so we check for it
}else {
    if($locationParameter.defaultValue -ne $null){ 
        Write-Error "The location parameter of nested templates must not have a defaultValue property. It is `"$($locationParameter.defaultValue)`"" -ErrorId Location.Parameter.DefaultValuePresent -TargetObject $parameter
    }   
}
# Now check that the rest of the template doesn't use [resourceGroup().location]
if ($TemplateWithoutLocationParameter -like '*resourceGroup().location*') {
    # If it did, write an error
    Write-Error "$TemplateFileName must use the location parameter, not resourceGroup().location (except when used as a default value in the main template)" -ErrorId Location.Parameter.Should.Be.Used -TargetObject $parameter
}