"The provided value for the template parameter is not valid" in ARM template deployments

I've come across this one before, but I hit it again today and I wanted to share the details of what happened. Basically the scenario is this, I have an ARM template that I want to deploy and it takes in parameters. The deployment needs to run through PowerShell using the Azure RM PowerShell cmdlets. When I call New-AzureRmResourceGroupDeployment I get the error that says "The provided value for the template parameter is {parameter name} not valid", and this is where things start getting weird. Here is an example of how I was calling it:

 New-AzureRmResourceGroupDeployment -ResourceGroupName "MyRGName" `
                                   -Name "MyDeployment" `
                                   -TemplateUri "https://url.of/MyTemplate.json" `
                                   -TemplateParameterObject @{
                                       Parameter1 = "Value"
                                       Parameter2 = "Other value"
                                   }

Now what you're looking at here is perfectly valid PowerShell - it gets parsed by the engine, compiled and executed as you would expect it to, but for some reason I was getting the error about Parameter1 not being a valid value. This error typically comes up where there is a data type mismatch or some other type of parameter validation error - such as asking for a string in the template but you give it a number, or you didn't provide a mandatory value, or those sorts of things. But in my case, none of that was true - the data type was a string and there was a value and that's all there was to it. I even put the parameter values in to an external file and ran that, and that worked! So I knew there was no issue with the value I was providing, so I had to figure out why it wouldn't accept it in the format I was providing. I started trying things, I tried taking the hashtable out in to a separate variable and that didn't seem to help - but then I found another way of calling things that seemed to do the trick:

 $params = @{}
$params.Add("Parameter1", "Value")
$params.Add("Parameter2", "Other value")

New-AzureRmResourceGroupDeployment -ResourceGroupName "MyRGName" `
                                   -Name "MyDeployment" `
                                   -TemplateUri "https://url.of/MyTemplate.json" `
                                   -TemplateParameterObject $params

 

For those not familiar, the first line of that example is creating a new and empty hashtable (it's the equivalent of running 'New-Object -TypeName System.Collections.Hashtable'). From there I call the .Add() method to add each item to the hashtable rather than doing it inline like I was doing in the first example. Now I've done this both ways in separate PowerShell windows and I absolutely cannot for the life of me pick a difference between a hashtable declared in the first example and the second one. They are the same object time, they compare the same, they have the same keys and values ... and yet for some reason when I pass the second example in to the Azure RM cmdlets it works, while the first is clearly losing the value somewhere along the way.

So I don't have an explanation on the "why" in this case, but I can tell you that the second example works where the first one doesn't. I've observed this behavior from both my laptop when I run cmdlets, as well as in Azure Automation when I try to do a deployment from a runbook as well, so look out for it anywhere the RM cmdlets run. I hope this helps other people get around this one if you come up against it!