Search code examples
jsonazurepowershellazure-rm-template

Parameter NO_PARAM in request is invalid Please provide correct value for parameter NO_PARAM while deploying azure arm template using Powershell


I am trying to create azure recovery services backup vault using powershell along with arm templates. For this deployment, I have created deployment template and parameters template. I am editing parameters template json file using powershell by ConvertFrom-Json and again converting back to json and saivng to tempalte file using ConvertTo-Json.

When I execute New-AzResourceGroupDeployment, I am getting a strange error as below Parameter NO_PARAM in request is invalid Please provide correct value for parameter NO_PARAM

Below is the backuppolicy.deploy.json

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "vaultName": {
      "type": "string",
      "metadata": {
        "description": "Name of the Recovery Services Vault"
      }
    },
    "policyName": {
      "type": "string",
      "metadata": {
        "description": "Name of the Backup Policy"
      }
    },
    "scheduleRunDays": {
      "type": "array",
      "metadata": {
        "description": "Backup Schedule will run on array of Days like, Monday, Tuesday etc. Applies in Weekly Backup Type only."
      }
    },
    "scheduleRunTimes": {
      "type": "array",
      "metadata": {
        "description": "Times in day when backup should be triggered. e.g. 01:00, 13:00. This will be used in LTR too for daily, weekly, monthly and yearly backup."
      }
    },
    "timeZone": {
      "type": "string",
      "metadata": {
        "description": "Any Valid timezone, for example:UTC, Pacific Standard Time. Refer: https://msdn.microsoft.com/en-us/library/gg154758.aspx"
      }
    },
    "weeklyRetentionDurationCount": {
      "type": "int",
      "metadata": {
        "description": "Number of weeks you want to retain the backup"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    }
  },
  "resources": [
    {
      "apiVersion": "2016-06-01",
      "name": "[concat(parameters('vaultName'), '/', parameters('policyName'))]",
      "type": "Microsoft.RecoveryServices/vaults/backupPolicies",
      "location": "[parameters('location')]",
      "properties": {
        "backupManagementType": "AzureIaasVM",
        "instantRpRetentionRangeInDays": 5,
        "schedulePolicy": {
          "scheduleRunFrequency": "Weekly",
          "scheduleRunDays": "[parameters('scheduleRunDays')]",
          "scheduleRunTimes": "[parameters('scheduleRunTimes')]",
          "schedulePolicyType": "SimpleSchedulePolicy"
        },
        "retentionPolicy": {
          "dailySchedule": null,
          "weeklySchedule": {
            "daysOfTheWeek": "[parameters('scheduleRunDays')]",
            "retentionTimes": "[parameters('scheduleRunTimes')]",
            "retentionDuration": {
              "count": "[parameters('weeklyRetentionDurationCount')]",
              "durationType": "Weeks"
            }
          },
          "retentionPolicyType": "LongTermRetentionPolicy"
        },
        "timeZone": "[parameters('timeZone')]"
      }
    }
  ]
}

Below is backuppolicy.parameters.json

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "vaultName": {
      "value": "diskencrypt"
    },
    "policyName": {
      "value": "autoamted-policy-changed"
    },
    "scheduleRunDays": {
      "value": [
        "Monday",
        "Tuesday",
        "Friday"
      ]
    },
    "scheduleRunTimes": {
      "value": [
        "20200309T110019Z"
      ]
    },
    "timeZone": {
      "value": "UTC"
    },
    "weeklyRetentionDurationCount": {
      "value": 5
    }
  }
}

Below is the powershell code that I used to modify json template and trigger deployment

$days = "Monday,Tuesday,Friday"
$ScheduleBackupDays = @()
$days = $days.Split(',')
$CurrentTime = @(Get-Date -Format yyyyMMddTHHmmssZ)
foreach($day in $days){
    $ScheduleBackupDays += $day
}
$params = @{
    policyName = "autoamted-policy-changed"
    vaultName = "diskencrypt"
    scheduleRunDays = $ScheduleBackupDays
    scheduleRunTimes = $CurrentTime
    timeZone = "UTC"
    weeklyRetentionDurationCount = 5

}
$templateFile = "$PSScriptRoot\backuppolicy.deploy.json"
$paramtersfile = "$PSScriptRoot\backuppolicy.parameters.json"

$ParameterFileObject = Get-Content -Path $paramtersfile -Raw | ConvertFrom-Json

foreach($Key in $params.Keys){
    $ParameterFileObject.parameters.$Key.value = $params.Get_Item($Key)
}

$ParameterFileObject | ConvertTo-Json -Depth 100 | foreach { [System.Text.RegularExpressions.Regex]::Unescape($_) } | Set-Content -Path $paramtersfile

New-AzResourceGroupDeployment -ResourceGroupName diskencrypt -TemplateFile $templateFile -TemplateParameterFile $paramtersfile


Solution

  • The exception is slightly misleading. The real issue is, that ARM cannot make sense of your timestamp in the parameters file:

    "scheduleRunTimes": {
                "value": [
                    "20200309T110019Z"
                ]
            }
    

    There are two problems here:

    1. The formatting is wrong. ARM expects the UTC timestamp according to ISO-8601 with all dashes and colons: 2020-03-09T11:00:19Z
    2. You cannot specify seconds in your scheduleRunTimes. In fact only 30min steps are allowed.

    Remove the 19 seconds from the end in this example and you should be good:

    "scheduleRunTimes": {
                "value": [
                    "2020-03-09T11:00:00Z"
                ]
            }
    

    If the current hour is all you need, you can change the formatting of the timestamp in your powershell script like this:

    $CurrentTime = @(Get-Date -Format 'yyyy-MM-dd-THH:00:00Z')
    

    If you need to round to the closest half n hour, things get a little more complex with date time objects, as there is no build in way to round.

    Assuming, that you want to exclude timestamps that lie in the future, rounding down to the last 30min should be fine:

    $date = Get-Date
    $roundedDate = $date.AddMinutes(-($date.Minute % 30))
    $CurrentTime = Get-Date $roundedDate -Format 'yyyy-MM-ddTHH:mm:00Z'