About Me

My photo
I am an MCSE in Data Management and Analytics, specializing in MS SQL Server, and an MCP in Azure. With over 19+ years of experience in the IT industry, I bring expertise in data management, Azure Cloud, Data Center Migration, Infrastructure Architecture planning, as well as Virtualization and automation. I have a deep passion for driving innovation through infrastructure automation, particularly using Terraform for efficient provisioning. If you're looking for guidance on automating your infrastructure or have questions about Azure, SQL Server, or cloud migration, feel free to reach out. I often write to capture my own experiences and insights for future reference, but I hope that sharing these experiences through my blog will help others on their journey as well. Thank you for reading!

ARM Template overview and How to DEMO : ARM Template Deployment with Powershell and JSON.

How to deploy a Virtual machine using ARM Template



ARM Template Overview


 What is ARM Template
 ARM Template is means of specifying the orchestration/configuration of deployments to an Azure resource group
ARM Template is based on JSON
It Allows us to declare the resources we intend to apply to a particular solution.

Through ARM Template we can do single grouping of explicit instructions vs a series of commands.
     
  •         It Enforces dependencies
  •         It eliminates misconfigurations
  •         No real support for conditionals
  •         It runs in parallel where ever possible 

Configuration can be made in the template or through parameters password to the template via command line or a parameter file
ARM Template runs in Powershell, CLI, REST API,portal as a visual studio project or via VS Code

ARM Template Features
-------------------------------
Current resources can be exported to the ARM template from the portal
Template can be linked, allowing you to repeat parts of a deployment task among several deployment template
   e.g. a linked, default virtual network template
    You can pass state between templates

Templates can run functions(e.g do math) and set dynamic variables at runtime
Templates can accept secrets from key Vault
Resources can be moved from one group to another
Output parameters

ARM Template deployment Modes
--------------------------------------------

1. Increment
      Default mode
      Does not remove or modify existing resources not mentioned in the template
      Provides Support for versioning and rolling back deployments

2. Complete
      Deletes any resource not mentioned in the template
      It is best for "starting fresh"or refactoring a solution
There are various elements in an ARM Template
  1.schema -- Required
  2.contentversion  -- Required
  3.parameters
  4.variables
  5.resources   --> Required
  6.outputs

Q. What is New-AzureRmResourcegroupDeployment
Ans:-
The New-AzureRmResourceGroupDeployment cmdlet adds a deployment to an existing resource group. This includes the resources that the deployment requires.

An Azure resource is a user-managed Azure entity, such as a database server, database, website, virtual machine, or Storage account.
An Azure resource group is a collection of Azure resources that are deployed as a unit, such as the website, database server, and databases that are required for a financial website.
 A resource group deployment uses a template to add resources to a resource group and publishes them so that they are available in Azure. To add resources to a resource group without using a template, use the New-AzureRmResource cmdlet.

To add a resource group deployment, specify the name of an existing resource group and a resource group template.
A resource group template is a JSON string that represents a resource group for a complex cloud-based service, such as a web portal.
 The template includes parameter placeholders for required resources and configurable property values, such as names and sizes. You can find many templates in the Azure template gallery or you can create your own templates. You can use the Get-AzureRmResourceGroupGalleryTemplate cmdlet to find a template in the gallery.

To use a custom template to create a resource group, specify the TemplateFile parameter or TemplateUri parameter.
 Each template has parameters for configurable properties.
 To specify values for the template parameters, specify the TemplateParameterFile parameter or the TemplateParameterObject parameter.

Example:-

New-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateFilePath -TemplateParameterFile $parametersFilePath;


Now our objective is to deploy one Virtual machine using ARM Template! 
So lets start


1. open a notepad file and save file as parameters.json in C:\temp folder
 copy below content in the file.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "value": "southcentralus"
        },
        "virtualMachineName": {
            "value": "win2k1602"
        },
        "virtualMachineSize": {
            "value": "Standard_D2s_v3"
        },
        "adminUsername": {
            "value": "admin"
        },
        "virtualNetworkName": {
            "value": "devrg1-vnet"
        },
        "networkInterfaceName": {
            "value": "win2k1601473"
        },
        "networkSecurityGroupName": {
            "value": "win2k1601-nsg"
        },
        "adminPassword": {
            "value": "P@$$word!@123"
        },
        "storageAccountName": {
            "value": "win2k16osstor"
        },
        "storageAccountType": {
            "value": "Standard_LRS"
        },
        "addressPrefix": {
            "value": "10.1.0.0/16"
        },
        "subnetName": {
            "value": "dbsubnet"
        },
        "subnetPrefix": {
            "value": "10.1.0.0/24"
        },
        "publicIpAddressName": {
            "value": "win2k1602-ip"
        },
        "publicIpAddressType": {
            "value": "Dynamic"
        },
        "publicIpAddressSku": {
            "value": "Basic"
        },
        "autoShutdownStatus": {
            "value": "Enabled"
        },
        "autoShutdownTime": {
            "value": "19:00"
        },
        "autoShutdownTimeZone": {
            "value": "UTC"
        },
        "autoShutdownNotificationStatus": {
            "value": "Disabled"
        },
        "sqlConnectivityType": {
            "value": "Private"
        },
        "sqlPortNumber": {
            "value": 1433
        },
        "sqlStorageDisksCount": {
            "value": 1
        },
        "sqlStorageWorkloadType": {
            "value": "GENERAL"
        },
        "sqlStorageDisksConfigurationType": {
            "value": "NEW"
        },
        "sqlStorageStartingDeviceId": {
            "value": 2
        },
        "sqlStorageDeploymentToken": {
            "value": 51206
        },
        "sqlAutopatchingDayOfWeek": {
            "value": "Sunday"
        },
        "sqlAutopatchingStartHour": {
            "value": "2"
        },
        "sqlAutopatchingWindowDuration": {
            "value": "60"
        },
        "sqlAuthenticationLogin": {
            "value": "admina"
        },
        "sqlAuthenticationPassword": {
            "value": "P@$$word!@123"
        },
        "rServicesEnabled": {
            "value": "false"
        }
    }
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.open a notepad file and save file as Template.json in C:\temp folder

 copy below content in the file.

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string"
        },
        "virtualMachineName": {
            "type": "string"
        },
        "virtualMachineSize": {
            "type": "string"
        },
        "adminUsername": {
            "type": "string"
        },
        "virtualNetworkName": {
            "type": "string"
        },
        "networkInterfaceName": {
            "type": "string"
        },
        "networkSecurityGroupName": {
            "type": "string"
        },
        "adminPassword": {
            "type": "securestring"
        },
        "storageAccountName": {
            "type": "string"
        },
        "storageAccountType": {
            "type": "string"
        },
        "addressPrefix": {
            "type": "string"
        },
        "subnetName": {
            "type": "string"
        },
        "subnetPrefix": {
            "type": "string"
        },
        "publicIpAddressName": {
            "type": "string"
        },
        "publicIpAddressType": {
            "type": "string"
        },
        "publicIpAddressSku": {
            "type": "string"
        },
        "autoShutdownStatus": {
            "type": "string"
        },
        "autoShutdownTime": {
            "type": "string"
        },
        "autoShutdownTimeZone": {
            "type": "string"
        },
        "autoShutdownNotificationStatus": {
            "type": "string"
        },
        "sqlConnectivityType": {
            "type": "string"
        },
        "sqlPortNumber": {
            "type": "int"
        },
        "sqlStorageDisksCount": {
            "type": "int"
        },
        "sqlStorageWorkloadType": {
            "type": "string"
        },
        "sqlStorageDisksConfigurationType": {
            "type": "string"
        },
        "sqlStorageStartingDeviceId": {
            "type": "int"
        },
        "sqlStorageDeploymentToken": {
            "type": "int"
        },
        "sqlAutopatchingDayOfWeek": {
            "type": "string"
        },
        "sqlAutopatchingStartHour": {
            "type": "string"
        },
        "sqlAutopatchingWindowDuration": {
            "type": "string"
        },
        "sqlAuthenticationLogin": {
            "type": "string"
        },
        "sqlAuthenticationPassword": {
            "type": "securestring"
        },
        "rServicesEnabled": {
            "type": "string"
        }
    },
    "variables": {
        "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
        "subnetRef": "[concat(variables('vnetId'), '/subnets/', parameters('subnetName'))]"
    },
    "resources": [
        {
            "name": "[parameters('virtualMachineName')]",
            "type": "Microsoft.Compute/virtualMachines",
            "apiVersion": "2017-03-30",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Network/networkInterfaces/', parameters('networkInterfaceName'))]",
                "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
            ],
            "properties": {
                "osProfile": {
                    "computerName": "[parameters('virtualMachineName')]",
                    "adminUsername": "[parameters('adminUsername')]",
                    "adminPassword": "[parameters('adminPassword')]",
                    "windowsConfiguration": {
                        "provisionVmAgent": "true"
                    }
                },
                "hardwareProfile": {
                    "vmSize": "[parameters('virtualMachineSize')]"
                },
                "storageProfile": {
                    "imageReference": {
                        "publisher": "MicrosoftSQLServer",
                        "offer": "SQL2017-WS2016",
                        "sku": "SQLDEV",
                        "version": "latest"
                    },
                    "osDisk": {
                        "createOption": "fromImage",
                        "vhd": {
                            "uri": "[concat(concat(reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2015-06-15').primaryEndpoints['blob'], 'vhds/'), parameters('virtualMachineName'), '20180405142317.vhd')]"
                        },
                        "name": "[parameters('virtualMachineName')]"
                    },
                    "dataDisks": [
                        {
                            "createOption": "empty",
                            "lun": 0,
                            "diskSizeGB": "1023",
                            "caching": "ReadOnly",
                            "name": "[concat(parameters('virtualMachineName'), '-disk-1')]",
                            "vhd": {
                                "uri": "[concat(concat(reference(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2015-06-15').primaryEndpoints['blob'], 'vhds/'), parameters('virtualMachineName'), '-disk-1-20180405142317', '.vhd')]"
                            }
                        }
                    ]
                },
                "networkProfile": {
                    "networkInterfaces": [
                        {
                            "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('networkInterfaceName'))]"
                        }
                    ]
                }
            }
        },
        {
            "apiVersion": "2015-06-15",
            "type": "Microsoft.Compute/virtualMachines/extensions",
            "name": "[concat(parameters('virtualMachineName'), '/SqlIaasExtension')]",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachineName'))]",
                "[concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachineName'))]"
            ],
            "properties": {
                "type": "SqlIaaSAgent",
                "publisher": "Microsoft.SqlServer.Management",
                "typeHandlerVersion": "1.2",
                "autoUpgradeMinorVersion": "true",
                "settings": {
                    "AutoTelemetrySettings": {
                        "Region": "[parameters('location')]"
                    },
                    "AutoPatchingSettings": {
                        "PatchCategory": "WindowsMandatoryUpdates",
                        "Enable": true,
                        "DayOfWeek": "[parameters('sqlAutopatchingDayOfWeek')]",
                        "MaintenanceWindowStartingHour": "[parameters('sqlAutopatchingStartHour')]",
                        "MaintenanceWindowDuration": "[parameters('sqlAutopatchingWindowDuration')]"
                    },
                    "KeyVaultCredentialSettings": {
                        "Enable": false,
                        "CredentialName": ""
                    },
                    "ServerConfigurationsManagementSettings": {
                        "SQLConnectivityUpdateSettings": {
                            "ConnectivityType": "[parameters('sqlConnectivityType')]",
                            "Port": "[parameters('sqlPortNumber')]"
                        },
                        "SQLWorkloadTypeUpdateSettings": {
                            "SQLWorkloadType": "[parameters('sqlStorageWorkloadType')]"
                        },
                        "SQLStorageUpdateSettings": {
                            "DiskCount": "[parameters('sqlStorageDisksCount')]",
                            "NumberOfColumns": "[parameters('sqlStorageDisksCount')]",
                            "StartingDeviceID": "[parameters('sqlStorageStartingDeviceId')]",
                            "DiskConfigurationType": "[parameters('sqlStorageDisksConfigurationType')]"
                        },
                        "AdditionalFeaturesServerConfigurations": {
                            "IsRServicesEnabled": "[parameters('rServicesEnabled')]"
                        }
                    }
                },
                "protectedSettings": {
                    "SQLAuthUpdateUserName": "[parameters('sqlAuthenticationLogin')]",
                    "SQLAuthUpdatePassword": "[parameters('sqlAuthenticationPassword')]"
                }
            }
        },
        {
            "name": "[concat('shutdown-computevm-', parameters('virtualMachineName'))]",
            "type": "Microsoft.DevTestLab/schedules",
            "apiVersion": "2017-04-26-preview",
            "location": "[parameters('location')]",
            "properties": {
                "status": "[parameters('autoShutdownStatus')]",
                "taskType": "ComputeVmShutdownTask",
                "dailyRecurrence": {
                    "time": "[parameters('autoShutdownTime')]"
                },
                "timeZoneId": "[parameters('autoShutdownTimeZone')]",
                "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]",
                "notificationSettings": {
                    "status": "[parameters('autoShutdownNotificationStatus')]",
                    "timeInMinutes": "30"
                }
            },
            "dependsOn": [
                "[concat('Microsoft.Compute/virtualMachines/', parameters('virtualMachineName'))]"
            ]
        },
        {
            "name": "[parameters('storageAccountName')]",
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2015-06-15",
            "location": "[parameters('location')]",
            "properties": {
                "accountType": "[parameters('storageAccountType')]"
            }
        },
        {
            "name": "[parameters('virtualNetworkName')]",
            "type": "Microsoft.Network/virtualNetworks",
            "apiVersion": "2017-08-01",
            "location": "[parameters('location')]",
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "[parameters('addressPrefix')]"
                    ]
                },
                "subnets": [
                    {
                        "name": "[parameters('subnetName')]",
                        "properties": {
                            "addressPrefix": "[parameters('subnetPrefix')]"
                        }
                    }
                ]
            }
        },
        {
            "name": "[parameters('networkInterfaceName')]",
            "type": "Microsoft.Network/networkInterfaces",
            "apiVersion": "2016-09-01",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]",
                "[concat('Microsoft.Network/publicIpAddresses/', parameters('publicIpAddressName'))]",
                "[concat('Microsoft.Network/networkSecurityGroups/', parameters('networkSecurityGroupName'))]"
            ],
            "properties": {
                "ipConfigurations": [
                    {
                        "name": "ipconfig1",
                        "properties": {
                            "subnet": {
                                "id": "[variables('subnetRef')]"
                            },
                            "privateIPAllocationMethod": "Dynamic",
                            "publicIpAddress": {
                                "id": "[resourceId('Microsoft.Network/publicIpAddresses', parameters('publicIpAddressName'))]"
                            }
                        }
                    }
                ],
                "networkSecurityGroup": {
                    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]"
                }
            }
        },
        {
            "name": "[parameters('publicIpAddressName')]",
            "type": "Microsoft.Network/publicIpAddresses",
            "apiVersion": "2017-08-01",
            "location": "[parameters('location')]",
            "properties": {
                "publicIpAllocationMethod": "[parameters('publicIpAddressType')]"
            },
            "sku": {
                "name": "[parameters('publicIpAddressSku')]"
            }
        },
        {
            "name": "[parameters('networkSecurityGroupName')]",
            "type": "Microsoft.Network/networkSecurityGroups",
            "apiVersion": "2017-06-01",
            "location": "[parameters('location')]",
            "properties": {
                "securityRules": [
                    {
                        "name": "default-allow-rdp",
                        "properties": {
                            "priority": 1000,
                            "protocol": "TCP",
                            "access": "Allow",
                            "direction": "Inbound",
                            "sourceAddressPrefix": "*",
                            "sourcePortRange": "*",
                            "destinationAddressPrefix": "*",
                            "destinationPortRange": "3389"
                        }
                    }
                ]
            }
        }
    ],
    "outputs": {
        "adminUsername": {
            "type": "string",
            "value": "[parameters('adminUsername')]"
        }
    }
}


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3. Go to Powershell Windows PowerShell ISE Console

 copy and paste below scripts to the console
Script will ask 5 inputs

1.  SubscriptionId --> This will be your Subscription ID
2.  ResourceGroupName --> This will be name of your resourcegroup, you can give any string value
3.  DeploymentName --> Here you can pass mydeployment01
4.  Then it will ask for your azure credentail
5.  Then it will ask for location : <kindly put your location which has less latency from your location>





<#
 .SYNOPSIS
    Deploys a template to Azure

 .DESCRIPTION
    Deploys an Azure Resource Manager template

 .PARAMETER subscriptionId
    The subscription id where the template will be deployed.

 .PARAMETER resourceGroupName
    The resource group where the template will be deployed. Can be the name of an existing or a new resource group.

 .PARAMETER resourceGroupLocation
    Optional, a resource group location. If specified, will try to create a new resource group in this location. If not specified, assumes resource group is existing.

 .PARAMETER deploymentName
    The deployment name.

 .PARAMETER templateFilePath
    Optional, path to the template file. Defaults to template.json.

 .PARAMETER parametersFilePath
    Optional, path to the parameters file. Defaults to parameters.json. If file is not found, will prompt for parameter values based on template.
#>

param(
 [Parameter(Mandatory=$True)]
 [string]
 $subscriptionId,

 [Parameter(Mandatory=$True)]
 [string]
 $resourceGroupName,

 [string]
 $resourceGroupLocation,

 [Parameter(Mandatory=$True)]
 [string]
 $deploymentName,

 [string]
 $templateFilePath = "C:\Temp\template.json",

 [string]
 $parametersFilePath = "C:\Temp\parameters.json"
)

<#
.SYNOPSIS
    Registers RPs
#>
Function RegisterRP {
    Param(
        [string]$ResourceProviderNamespace
    )

    Write-Host "Registering resource provider '$ResourceProviderNamespace'";
    Register-AzureRmResourceProvider -ProviderNamespace $ResourceProviderNamespace;
}

#******************************************************************************
# Script body
# Execution begins here
#******************************************************************************
$ErrorActionPreference = "Stop"

# sign in
Write-Host "Logging in...";
Login-AzureRmAccount;

# select subscription
Write-Host "Selecting subscription '$subscriptionId'";
Select-AzureRmSubscription -SubscriptionID $subscriptionId;

# Register RPs
$resourceProviders = @("microsoft.compute","microsoft.devtestlab","microsoft.storage","microsoft.network");
if($resourceProviders.length) {
    Write-Host "Registering resource providers"
    foreach($resourceProvider in $resourceProviders) {
        RegisterRP($resourceProvider);
    }
}

#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;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This will create a normal a Normal -- Standard_D2s_v3 machine. if you want to change the machine virtualMachineSize

 execute below powershell script the get another machine size.


If you want to configure similar machine in existing resource group and in same subnet, then you need to make 3 changes in parameter.json file.


1. Virtual Machine Name   
"virtualMachineName": {
            "value": "win2k1603"
        },

2.  Network InterfaceName
"networkInterfaceName": {
            "value": "win2k1601474"
        },

3. PublicIpAddressName

"publicIpAddressName": {
            "value": "win2k1602-ip"
        },


and then execute powershell script which i provided in step -3.

Now you are done. In this way you can install many servers in Azure portal at a time..


Now you can Monitor and update a Windows Virtual Machine with Azure PowerShell


  1. Enable boot diagnostics on a VM
  2. View boot diagnostics
  3. View VM host metrics
  4. Install the diagnostics extension
  5. View VM metrics
  6. Create an alert
  7. Manage Windows updates
  8. Monitor changes and inventory
  9. Set up advanced monitoring


Refer this link for doing all these tasks

https://docs.microsoft.com/en-us/azure/virtual-machines/windows/tutorial-monitoring



Thanks for Reading..