Override template parameter in the script - powershell

I am deploying VMs using a template and parameter file. I would like to override the parameter files virtualMachineName, so I can dynamically name each VM without needing 10 different parameter files. What is the correct syntax to do so?
Currently I have:
New-AzureRmResourceGroupDeployment -ResourceGroupName "myRSG" -TemplateFile $server1TmpFile -TemplateParameterFile $serverParamFile -virtualMachineName "AS1FTW12" -networkInterfaceName "AS1FTW12NIC" -networkSecurityGroupName "MyNSGName"
This will produce an error:
New-AzureRmResourceGroupDeployment : A parameter cannot be found that matches parameter name 'virtualMachineName'
I am authoring the script using PowerShell Tools for Visual Studio 2017. My installed PowerShell AzureRM version is 5.1.1 according to Get-Module AzureRM.

This Works with AzureRM 5.1.1, you can test with the following setup:
template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"paramTest": {
"type": "string"
}
},
"resources": [],
"outputs": {
"result": {
"type": "string",
"value": "[parameters('paramTest')]"
}
}
}
parameters:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"paramTest": {
"value": "GEN-UNIQUE"
}
}
}
Powershell:
New-AzureRmResourceGroupDeployment -ResourceGroupName rg -TemplateFile template.json -TemplateParameterFile param.json -paramTest somevalue
results in output value equal to the one passed from powershell
Your error indicates that the parameter name is wrong, doublé check it

Related

Automated way to convert azure powershell scripts to ARM templates

Let's say I have (way too) many *.ps1 scripts that I'd to convert to ARM templates
Is there a way (a script, command, whatever) I can automatically convert a azure powershell *.ps1 to an ARM template, without having to actually do the deployment to Azure?
I'm not looking for a bullet-proof solution. If there's indeed an automated way to do the conversion which fails if the ps1 script isn't correct, I'm OK with that.
No, there's no way to do that (unless you can automate deployment + export, which would create flawed templates anyway).
The closest you can get to this is run all cmdlets with -Debug switch and capture HTTP requests they are doing and convert those to ARM Templates (shouldn't be too hard, copy\paste and a bunch of editing)
You can run the "-Debug" flag on any of the Azure Powershell cmdlets that relate to creating resources, like New-AzureRmVM, and the output will show you the ARM template that it's going to create:
Be wary of using this as I have found that the Powershell cmdlets are NOT the way you should be automating your deployments. You should be strictly using ARM as the Powershell cmdlets sometimes do not output the correct parameters needed for successful deployment since the Powershell cmdlets do not have a method of specifying the version of the ARM API to use.
Example output using the "New-AzureRmVM" with the the "-Debug" flag:
New-AzureRmVM -ResourceGroupName $RGName -Location $Location -VM $VM -LicenseType "Windows_Server" -Debug
DEBUG: ============================ HTTP REQUEST ============================
HTTP Method:
PUT
Absolute Uri:
https://management.azure.com/subscriptions/<subscription>/resourceGroups/LL_SQL_Test/providers/Microsoft.Compute/virtualMachines/LLSQL3?api-version=2018-04-01
Headers:
x-ms-client-request-id : 5920b683-e8fe-455e-969a-63f4c6e246d7
accept-language : en-US
Body:
{
"properties": {
"hardwareProfile": {
"vmSize": "Standard_DS2_v2"
},
"storageProfile": {
"osDisk": {
"osType": "Windows",
"image": {
"uri": "https://<storageaccount>.blob.core.windows.net/vhds/<VM>.vhd"
},
"caching": "ReadWrite",
"writeAcceleratorEnabled": false,
"createOption": "FromImage",
"diskSizeGB": 127,
"managedDisk": {
"storageAccountType": "Standard_LRS"
}
}
},
"osProfile": {
"computerName": "<computername>",
"adminUsername": "<username>",
"adminPassword": "<Password>",
"windowsConfiguration": {
"provisionVMAgent": true,
"enableAutomaticUpdates": true
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "/subscriptions/<subscription>/resourceGroups/<resourcegroup>/providers/Microsoft.Network/networkInterfaces/<NIC>"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
},
"availabilitySet": {
"id": "/subscriptions/<subscription>/resourceGroups/<resourcegroup>/providers/Microsoft.Compute/availabilitySets/SQL_Availability_Set_Test"
},
"licenseType": "Windows_Server"
},
"location": "West US"
}
The above is a perfect example of "why not" to use Powershell, as currently, this will return an error:
Body:
{
"error": {
"code": "InvalidParameter",
"target": "osDisk.image",
"message": "Parameter 'osDisk.image' is not allowed."
}
}
As the API version (2018-04-01) the Powershell command is using to convert the Powershell input into a JSON ARM template doesn't allow for the parameter 'osDisk.Image" as it's expecting it to be formatted as:
"storageProfile": {
"imageReference": {
"id": "[resourceId('Microsoft.Compute/images', parameters('images_LL_SQL_IMG_name'))]"
},
"osDisk": {
"osType": "Windows",
Instead it's using
"storageProfile": {
"osDisk": {
"osType": "Windows",
"image": {
"uri": "https://<storageaccount>.blob.core.windows.net/vhds/LLSQL220180621090257.vhd"
},
As others have commented, there is no way to automatically convert PowerShell script to ARM templates. However, if you already have these resources deployed, you may consider using the ARM export feature to retrieve the ARM templates.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-export-template

Azure nested template deployment: Using template element (not templateLink) with PowerShell

In an attempt to make life easier (in the long run), I'm trying to use properties.template, as opposed to the well documented properties.templateLink. The former has very little documentation by passing the contents of child.json template file into the parent.json template, as a template' parameter.
From the MS documentation for Microsoft.Resources/deployments:
The template content. You use this element when you want to pass the template syntax directly in the request rather than link to an existing template. It can be a JObject or well-formed JSON string. Use either the templateLink property or the template property, but not both.
In my parent template, I am declaring the parameter childTemplates and referencing it in properties.template:
"parameters": {
"childTemplates": {
"type": "object",
"metadata": {
"description": "Child template"
}
}
}
other stuff...
"resources": [
{
"name": "[concat('linkedTemplate-VM-Net-',copyIndex(1))]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-06-01",
"dependsOn": [],
"copy": {
"name": "interate",
"count": "[parameters('vmQty')]"
},
"properties": {
"mode": "Incremental",
"template": "[parameters('childTemplates')]",
"parameters": {
"sharedVariables": { "value": "[variables('sharedVariables')]" },
"sharedTemplate": { "value": "[variables('sharedTemplate')]" },
"artifactsLocationSasToken": { "value": "[parameters('artifactsLocationSasToken')]" },
"adminPassword": { "value": "[parameters('adminPassword')]" },
"copyIndexValue": { "value": "[copyIndex(1)]" }
},
"debugSetting": {
"detailLevel": "both"
}
}
}
],
I then pass the child template to New-AzureRmResourceGroupDeployment -TemplateParameterObject to deploy the parent template:
$TemplateFileLocation = "C:\Temp\templates\parent.json"
$JsonChildTemplate = Get-Content -Raw (Join-Path ($TemplateFileLocation | Split-Path -Parent) "nestedtemplates\child.json") | ConvertFrom-Json
$TemplateParameters = #{
childTemplates = $JsonChildTemplate
...Other parameters...
}
New-AzureRmResourceGroupDeployment -TemplateParameterObject $TemplateParameters
This produces the following error:
Code : InvalidTemplate
Message : The nested deployment 'linkedTemplate-VM-Net-1' failed validation: 'Required property '$schema' not found in JSON. Path 'properties.template'.'.
Target :
Details :
If I look at $JsonChildTemplate, it gives me:
$schema : https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#
contentVersion : 1.0.0.0
parameters : #{sharedVariables=; sharedTemplate=; vhdStorageAccountName=; artifactsLocationSasToken=; adminPassword=; copyIndexValue=}
variables : #{seqNo=[padleft(add(parameters('copyIndexValue'),3),3,'0')]; nicName=[concat('NIC-',parameters('sharedVariables').role,'-', variables('seqNo'),'-01')];
subnetRef=[parameters('sharedVariables').network.subnetRef]; ipConfigName=[concat('ipconfig-', variables('seqNo'))]}
resources : {#{apiVersion=2016-03-30; type=Microsoft.Network/networkInterfaces; name=[variables('nicName')]; location=[resourceGroup().location]; tags=; dependsOn=System.Object[];
properties=}}
outputs : #{nicObject=; vmPrivateIp=; vmNameSuffix=; vmPrivateIpArray=}
To me, it looks like the $schema is there.
I have also tried removing | ConvertFrom-Json with the same error.
Above, I am showing the latest API version, but I have tried with others such as 2016-09-01, just in case there's a bug.
In my search for a solution, I found this issue on GitHub. The recomendation is to remove $schema and contentVersion, although this flies in the face of the error. I tried this with the following:
Function Get-ChildTemplate
{
$TemplateFileLocation = "C:\Temp\templates\nestedtemplates\child.json"
$json = Get-Content -Raw -Path $TemplateFileLocation | ConvertFrom-Json
$NewJson = #()
$NewJson += $json.parameters
$NewJson += $json.variables
$NewJson += $json.resources
$NewJson += $json.outputs
Return $NewJson | ConvertTo-Json
}
$JsonChildTemplate = Get-ChildTemplate
$TemplateParameters = #{
childTemplates = $JsonChildTemplate
...Other parameters...
}
$JsonChildTemplate returns:
[
{
"sharedVariables": {
"type": "object",
"metadata": "#{description=Object of variables from master template}"
}...
My guess is that I have done something wrong passing child.json's contents to New-AzureRmResourceGroupDeployment. That or it's not actually possible to do what I'm trying to do.
P.S.
get-command New-AzureRmResourceGroupDeployment
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet New-AzureRmResourceGroupDeployment 4.1.0 AzureRM.Resources
First of all, what you are doing makes 0 sense what so ever, that being said, lets try to help you.
Try splatting. so do New-AzureRmResourceGroupDeployment ... #TemplateParameters instead of what you are doing. (no idea, but somehow it works better in my experience)
If that doesn't work directly try simplifying you nested template to the bare minimum and see if it works if it does, check if your nested template is fine.
Try creating a deployment with -Debug switch and see where that goes.
Try the same deployment using Azure Cli (maybe it converts json to input object in a proper way)
Skip items 1-4 and do it the proper way. I would advice never do preprocessing\in flight generation of ARM Templates. They have enough of features already to accomplish anything if you are smart hacky enough. I have no idea what you are trying to achieve but I can bet my life on it you don't need that monstrosity you are trying to create
small template example:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": []
}
EDIT: I dug a bit more and found a solution. one way to do it would be using the json() function of the arm template that accepts a string and converts to valid json.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"inp": {
"type": "string"
}
},
"resources": [
{
"name": "NestedDeployment1",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"properties": {
"mode": "Incremental",
"template": "[json(parameters('inp'))]",
"parameters": {}
}
}
]
}
To deploy use something like this:
New-AzureRmResourceGroupDeployment ... -inp ((get-content path\to.json -raw) -replace '\s','')
# we minify the string so it gets properly converted to json
This is a bit of a hack, but the problem lies with how powershell converts your input to what it passes to the template, and you cannot really control that.
Another way to do that: (if you need output you can add another parameter)
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"input-param": {
"type": "object"
},
"input-resource": {
"type": "array"
}
},
"resources": [
{
"name": "NestedDeployment1",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": "[parameters('input-param')]",
"resource": "[parameters('input-resource')]"
},
"parameters": {}
}
}
]
}
and deploying like so:
New-AzureRmResourceGroupDeployment -ResourceGroupName zzz -TemplateFile path\to.json -input-param #{...} -input-resource #(...)
ps. don't mind walter, each time he says something can't be done or is impossible it actually is possible.

New-AzureRmResourceGroupDeployment Command not recognizing the JSON paramaters file

I have a JSON parameters file that looks like this.
"parameters": {
"field_1": {
"value": "abc"
},
"field_2": {
"value": 123
},
and I am using the below command to create resources in Azure
New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath
when I run it, for some reason it's not recognizing the parameters that are in the parameters file. It asks me to enter the parameters individually in powershell and then after I enter all of them I get the below error:
New-AzureRmResourceGroupDeployment : 4:07:58 PM - Error: Code=InvalidDeploymentParameterValue; Message=The value of deployment parameter 'parameters' is null. Please specify the value or use the parameter reference. See
https://aka.ms/arm-deploy/#parameter-file for details.
At line:52 char:4
+ New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGro ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDeploymentCmdlet
I am not sure what I am doing wrong. Any help would be greatly appreciated.
Well, it should not recognize it, if you look at the Azure Quickstart templates repository, most of those have parameter files, all of them have a proper structure, while yours don't, here's how a proper parameter file looks like:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"value": "ghuser"
},
"adminPassword": {
"value": "GEN-PASSWORD"
},
"dnsLabelPrefix": {
"value": "GEN-UNIQUE"
}
}
}
Reference: https://github.com/Azure/azure-quickstart-templates

Apply tags to Azure resource group within resource template file

I'm using Powershell to create an Azure resource group from a template file and parameter file.
New-AzureResourceGroup -Name $groupName `
-TemplateFile $templateFile `
-TemplateParameterFile $paramFile `
-Location $location `
-Force -Verbose
Within the template I'm setting some tags on the resources within the group.
resourcegroup.json
"parameters": {
"environment": {
"type": "string",
"allowedValues": [
"Dev",
"Test",
"QA",
"Prod"
]}
}
....
"resources": [
{
...
"tags": {
"Environment": "[parameters('environment')]",
}
}
I'd like to apply the same tag values to the resource group itself, but I don't see a way to do that within the schema of the template file. Am I missing something?
Now at least, this is possible:
{
"type": "Microsoft.Resources/tags",
"name": "default",
"apiVersion": "2020-06-01",
"dependsOn": [
"resource1"
],
"properties": {
"tags": {
"Tag1": "Value1",
"Tag2": "Value2"
}
}
}
Documentation reference here
AFAIK, you have to use the azure Powershell command-let to add tags to your Azure Resource group. It cannot be done through the Template file.

Azure powershell cmdlet for creating Azure Service bus queue and topics

Is there any Azure powershell cmdlets for creating and managing Azure Service bus Queue and Topics?
The following link does not provide this:
http://msdn.microsoft.com/library/windowsazure/jj983731.aspx
Microsoft is planning to release this soon?
There currently are not PowerShell cmdlets for Service Bus queues and topics. They do have Cmdlets for creating the namespaces and some of the ACS entities, but not brokered messaging yet. The Azure cross-platform command line tool has the same capabilities.
You can monitor what's in the PowerShell Cmdlets, or even see pre-release bits on Windows Azure SDK-Tools repo on GitHub. This is a public repo of the code that makes up the PowerShell Cmdlets.
I've seen no public announcements about if/when this functionality will be added to the Cmdlets or the CLI tools.
Some documentation about this scenario was recently added:
http://azure.microsoft.com/en-us/documentation/articles/service-bus-powershell-how-to-provision/
The summary is that there are only a limited number of PowerShell cmdlets that relate to Service Bus. However, you can reference the NuGet packages and use the types there to do anything that is available in the client libraries.
Save the given below template in json file and execute the given below powershell command
----------------------------------------------------------------
param(
[Parameter(Mandatory=$True)]
[string]
$resourceGroupName,
[string]
$resourceGroupLocation,
[Parameter(Mandatory=$True)]
[string]
$templateFilePath = "C:\ARM-ServiceBus\sb_template.json",
[string]
$parametersFilePath = "C:\ARM-ServiceBus\sb_parameters.json"
)
#***********************************************************************
# Script body
# Execution begins here
#***********************************************************************
$ErrorActionPreference = "Stop"
$subscriptionId ='1234-545-474f-4544-5454454545'
# sign in
Write-Host "Logging in...";
Login-AzureRmAccount;
# select subscription
Write-Host "Selecting subscription '$subscriptionId'";
Select-AzureRmSubscription -SubscriptionID $subscriptionId;
#Create or check for existing resource group
$resourceGroup = Get-AzureRmResourceGroup -Name $resourceGroupName -
ErrorAction SilentlyContinue
if(!$resourceGroup)
{
Write-Host "Resource group '$resourceGroupName' does not exist. To
create a new resource group, please enter a location.";
if(!$resourceGroupLocation) {
$resourceGroupLocation = Read-Host "resourceGroupLocation";
}
Write-Host "Creating resource group '$resourceGroupName' in location
'$resourceGroupLocation'";
New-AzureRmResourceGroup -Name $resourceGroupName -Location
$resourceGroupLocation
}
else{
Write-Host "Using existing resource group '$resourceGroupName'";
}
# Start the deployment
Write-Host "Starting deployment...";
if(Test-Path $parametersFilePath) {
New-AzureRmResourceGroupDeployment -ResourceGroupName
$resourceGroupName -TemplateFile $templateFilePath -
TemplateParameterFile $parametersFilePath;
} else {
New-AzureRmResourceGroupDeployment -ResourceGroupName
$resourceGroupName -TemplateFile $templateFilePath;
}
--------------Template(sb_template.json)--------------------------
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-
preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusQueueName": {
"type": "string",
"metadata": {
"description": "Name of the Queue"
}
},
"serviceBusApiVersion": {
"type": "string",
"defaultValue": "2015-08-01",
"metadata": {
"description": "Service Bus ApiVersion used by the template"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"sbVersion": "[parameters('serviceBusApiVersion')]",
"defaultSASKeyName": "RootManageSharedAccessKey",
"authRuleResourceId": "
[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules',
parameters('serviceBusNamespaceName'),
variables('defaultSASKeyName'))]"
},
"resources": [{
"apiVersion": "[variables('sbVersion')]",
"name": "[parameters('serviceBusNamespaceName')]",
"type": "Microsoft.ServiceBus/Namespaces",
"location": "[variables('location')]",
"kind": "Messaging",
"sku": {
"name": "StandardSku",
"tier": "Standard",
"capacity": 1
},
"resources": [{
"apiVersion": "[variables('sbVersion')]",
"name": "[parameters('serviceBusQueueName')]",
"type": "Queues",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceName'))]"
],
"properties": {
"path": "[parameters('serviceBusQueueName')]"
}
}]
}],
"outputs": {
"NamespaceConnectionString": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryConnectionString]"
},
"SharedAccessPolicyPrimaryKey": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryKey]"
}
}
}