Azure

PowerShell: 101-loadbalancer-with-nat-rule

This is a conversion of ARM template 101-loadbalancer-with-nat-rule from the GitHub repository azure\azure-quickstart-templates to PowerShell Script, and this script will deploy following the resources...


PowerShell: 101-loadbalancer-with-multivip

This is a conversion of ARM template 101-loadbalancer-with-multivip from the GitHub repository azure\azure-quickstart-templates to PowerShell Script, and this script will deploy following the resources...


Terraform: 101-vnet-two-subnets

This is a conversion of ARM template 101-vnet-two-subnets from the GitHub repository azure\azure-quickstart-templates to Terraform configuration, and this configuration will deploy following the resources...


PowerShell: 101-vnet-two-subnets

This is a conversion of ARM template 101-vnet-two-subnets from the GitHub repository azure\azure-quickstart-templates to PowerShell Script, and this script will deploy following the resources...


Copy Security Rules From One Azure Network Security Group To Another Using PowerShell

Network Security Group Azure Network Security Group is used to manage the flow of the network traffic and the direction as well, besides the default inbound and outbound security rules there can be none or many security rules to define the security within in the Azure Virtual Network. Purpose of copying Security Rules There are many scenarios where you need to clone Network Security Group and its security rules to a new Network Security Group or copy the security rules to an existing Network Security Group, it could be as part of the migration, testing, cloning the same security measures for different project, or for a disaster recovery site and etc., You can’t move the Network Security Group from one region to an another. You can only use the method of copy, paste and delete. Copy Security Rules using PowerShell I have created a PowerShell script to copy the security rules from one Network Security Group to another and also it has some other abilities like… Copy security rules from one Network Security Group to another. Creates a new Network Security Group and copy the security rules. Accepts the Network Security Group by name or as an object as well. By default the script merges the security rules, and it has an option to overwrite the existing NSG security rules. Code  View the code in GitHub   Syntax This function will accept the following Parameter Sets… Copy-AzNSGSecurityRules -SourceResourceGroupName <string> -SourceNSGName <string> -TargetResourceGroupName <string> -TargetNSGName <string> [<CommonParameters>] Copy-AzNSGSecurityRules -SourceResourceGroupName <string> -SourceNSGName <string> -TargetResourceGroupName <string> -TargetNSGName <string> -TargetLocation <string> [<CommonParameters>] Copy-AzNSGSecurityRules -SourceNSG <psobject> -TargetResourceGroupName <string> -TargetNSGName <string> -TargetLocation <string> [<CommonParameters>] Copy-AzNSGSecurityRules -SourceNSG <psobject> -TargetNSG <psobject> [-Overwrite] [<CommonParameters>] Example 01 To copy security rules from the existing source NSG to existing target NSG using NSG name… PS C:\> . .\Scripts\Copy-AzNSGSecurityRules.ps1 PS C:\> Copy-AzNSGSecurityRules -SourceResourceGroupName 'rg1' -SourceNSGName 'nsg1' -TargetResourceGroupName 'rg2' -TargetNSGName 'nsg2' Output: Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer Example 02 To create a new NSG and then copy security rules from the existing source NSG PS C:\> . .\Scripts\Copy-AzNSGSecurityRules.ps1 PS C:\> Copy-AzNSGSecurityRules -SourceResourceGroupName 'rg1' -SourceNSGName 'nsg1' -TargetNSGName 'nsg2' -TargetResourceGroupName 'rg2' -TargetLocation 'southindia' Output: New NSG 'nsg2' has been created in resource group 'rg2' in 'southindia' location. Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer If the target NSG is already existed… The NSG 'nsg2' is already existed, so vomiting the '-TagetLocation' parameter value and skiping the NSG creation. Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer Example 03 To copy security rules from the existing source NSG to existing target NSG (When direct NSG objects are provided) PS C:\> . .\Scripts\Copy-AzNSGSecurityRules.ps1 PS C:\> $nsg1 = Get-AzNetworkSecurityGroup -ResourceGroupName 'rg1' -Name 'nsg1' PS C:\> $nsg2 = Get-AzNetworkSecurityGroup -ResourceGroupName 'rg2' -Name 'nsg2' PS C:\> Copy-AzNSGSecurityRules -SourceNSG $nsg1 -TargetNSG $nsg2 Output: Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer Example 04 To create a new NSG and then copy security rules from the existing source NSG (When direct source NSG object is provided) PS C:\> . .\Scripts\Copy-AzNSGSecurityRules.ps1 PS C:\> $nsg1 = Get-AzNetworkSecurityGroup -ResourceGroupName 'rg1' -Name 'nsg1' PS C:\> Copy-AzNSGSecurityRules -SourceNSG $nsg1 -TargetNSGName 'nsg2' -TargetResourceGroupName 'rg2' -TargetLocation 'southindia' Output: New NSG 'nsg2' has been created in resource group 'rg2' in 'southindia' location. Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer If the target NSG is already existed… The NSG 'nsg2' is already existed, so vomiting the '-TagetLocation' parameter value and skiping the NSG creation. Following 2 security rule(s) is/are copied from source NSG 'rg1\nsg1' to target NSG 'rg2\nsg2' Deny_Internet, Allow_SqlServer Code  View the code in GitHub  


Find Azure Resources By Tags Using PowerShell

Recently, I have been requested to write a small PowerShell script to fetch all the Azure resources with no tags at all, but I thought of writing a comprehensive script that is not only to find all the resources with no tags but also to find resources with specific tag name(s), tag value(s), tag(s), or with all tags. Tagging in Azure I have already covered Tagging Microsoft Azure Resources Using Powershell (Az)  in my previous post, but just to brief… Tags in Azure play pivotal role in managing the resources, predominantly in the cost governance strategies and much useful for automation and maintain environment hygiene. More than a resource name, tagging is very crucial and it must be consistent and appropriate across the resources in all the resource groups and subscriptions. Many organizations leverage the tagging effectively and consistently using the Azure policies or some automation techniques. Find-AzResource However, finding the resources in Azure is also crucial, and especially finding all the resources of all types from multiple subscriptions or resource groups. So I have come up with a PowerShell script to find all the Azure tagged/not tagged resources, and you can find the script in my GitHub repo…  View the code in GitHub   The script comes with an in-build help, and if you run the script without any parameters it will display the help as below… C:\Users\kiran\PSScripts> . .\Find-AzResource.ps1 C:\Users\kiran\PSScripts> Find-AzResource Output: NAME Find-AzResource SYNOPSIS Find-AzResource gets all the Azure tagged/not tagged resources, SYNTAX Find-AzResource [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] [<CommonParameters>] Find-AzResource -ResourceGroupName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -Tag <Hashtable> [<CommonParameters>] Find-AzResource -ResourceGroupName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -TagValue <String[]> [<CommonParameters>] Find-AzResource -ResourceGroupName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -TagName <String[]> [<CommonParameters>] Find-AzResource -ResourceGroupName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -WithNoTag [<CommonParameters>] Find-AzResource -ResourceGroupName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -AllTagged [<CommonParameters>] Find-AzResource -SubscriptionName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -Tag <Hashtable> [<CommonParameters>] Find-AzResource -SubscriptionName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -TagValue <String[]> [<CommonParameters>] Find-AzResource -SubscriptionName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -TagName <String[]> [<CommonParameters>] Find-AzResource -SubscriptionName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -WithNoTag [<CommonParameters>] Find-AzResource -SubscriptionName <String[]> [-ResourceName <String[]>] [-Location <String[]>] [-ResourceType <String[]>] -AllTagged [<CommonParameters>] DESCRIPTION Find-AzResource gets all the Azure resources with... > All tags > No tags > Specific tag name(s) > Specific tag value(s) > Specific tag(s) ... from one or more resourcegroup(s) or subscripttion(s) and optionally filter the resources by location, name and type as well. ... output truncated ... -------------------------- EXAMPLE 1 -------------------------- PS > Find-AzResource Displays full help -------------------------- EXAMPLE 2 -------------------------- PS > Find-AzResource -SubscriptionName Sub1, Sub2 -AllTagged Finds all the resources with tags in the given Subscriptions. it even works with ResourceGroupName as well. Optionally, you can even filter the resources by Name, Location and Type. -------------------------- EXAMPLE 3 -------------------------- PS > Find-AzResource -SubscriptionName Sub1, Sub2 -WithNoTag Finds all the resources with no tags in the given Subscriptions. It even works with ResourceGroupName as well. Optionally, you can even filter the resources by Name, Location and Type. -------------------------- EXAMPLE 4 -------------------------- PS > Find-AzResource -ResourceGroupName RG1, RG2 -TagName Status Finds all the resources with given tag name in the given resource groups. It even works with the subscriptions as well. Optionally, you can even filter the resources by Name, Location and Type. -------------------------- EXAMPLE 5 -------------------------- PS > Find-AzResource -ResourceGroupName RG1, RG2 -TagValue HR, Finance Finds all the resources with given tag values in the given resource groups. It even works with the subscriptions as well. Optionally, you can even filter the resources by Name, Location and Type. -------------------------- EXAMPLE 6 -------------------------- PS > Find-AzResource -ResourceGroupName RG1, RG2 -Tag @{Dept='IT'; Status="Expired"} Finds all the resources with given tags in the given resource groups. It even works with the subscriptions as well. Optionally, you can even filter the resources by Name, Location and Type.  View the code in GitHub  


Publish a static website on Azure Static WebApps (Preview)

Hosting on ☁️ Azure Static WebApps (Preview) Azure Static WebApps https://docs.microsoft.com/en-in/azure/static-web-apps/overview Microsoft announced Azure Static WebApps preview in the Build 2020 virtual event. Azure Static WebApps is a service from the Azure to host a web app directly from the source code repository with Azure managed CI/CD pipelines. As of now it is supporting only from GitHub and uses GitHub Actions Workflows for CI/CD and Azure Functions for backend support, the moment when you commit the code in the repository it builds the site and deploys to the associated Azure Static WebApp. At the time of I was writing this post Azure Static WebApps in still in public preview with a free plan offering. Image from Microsoft Docs Key Features Web Hosting - Hosts static content like HTML, CSS, JavaScript, and images. Azure Functions for backend support. Azure Managed CI/CD - Every commit to the code triggers build and deploy the site CDN Support - Globally distributed static content, putting content closer to your users. Free SSL certificates, which are automatically renewed. Supports custom domains to your website. Pull requests enabling preview versions of your site before publishing. Prerequisites Ready to deploy website Git Installed GitHub Account Azure Account with valid subscription. This post is in continuation to my previous post Create and Build A Static Website With Hugo,  and if you don’t have a ready to deploy website and want to build a new site using Hugo then you can refer to that post to create a new static website with in a few minutes. If you have not installed the git already then you can go to Git  website and install it. Push the site to GitHub repository Once you are done with site customization, added the content and built the site, you can push your site to GitHub Repository. You can go to site’s root directory in your favorite command line terminal and then run the following commands, in my case C:\Sites\kpatnayakuni is my site’s root directory. To initialize the local repository… C:\Sites\kpatnayakuni> git init To add the changes… C:\Sites\kpatnayakuni> git add . To commit the changes… C:\Sites\kpatnayakuni> git commit -m "Initial Commit" If you already have a GitHub account then login and create a repository with the same name as the local repository name, and in my case it is kpatnayakuni. If you don’t have a GitHub account then login into https://github.com/  and sign up with your email id and create the repository . First time if you are using the git then you need to set some global settings to work with the remote repositories… To set user name… C:\Sites\kpatnayakuni> git config --global user.name "<User Full Name>" To set email address… C:\Sites\kpatnayakuni> git config --global user.email "<User Email Address>" You need to use your name and email in the above examples. To add remote repository… C:\Sites\kpatnayakuni> git remote add origin https://github.com/<user_name>/<repository_name>.git To push the site onto GitHub C:\Sites\kpatnayakuni> git push -u origin master With our site is up in the GitHub repository, now let’s create a Static WebApp in the Azure Portal. If you don’t have an Azure account then you can login using your GitHub credentials, or create a new account  then get your subscription. However, as of now Azure Static WebApps service comes with a free plan to start with. Login into the Azure Portal , then click on the search box and type the search word static then click on the Static Web Apps (Preview) service… In the Azure Portal When the Static Web Apps (Preview) blade is opened then click on Add button to create a new static web app… In the Azure Portal And as shown in the image below, please select the subscription and the resource group where you want to host your static website and then enter the app name and select the region near to your location, and then click on Sign in with GitHub to select the GitHub repository from where our static site is coming from. In the Azure Portal Once the GitHub login is successful, then please select the username/organizationname as organization, repository and branch then click next… In the Azure Portal If you have your only built site in the github repository then you can set root / as your App Location else if you have your complete site along with the build folder then you can set the build folder in the App Location, in my case it is /public. Api and Artifacts locations you can leave it for now, and if you want to add Azure Functions and configure artifacts then you can refer to the Microsoft Docs  for the same. In the Azure Portal Click on Review + create and if the review is successful then click on Create to deploy the Static Web App. Once the deployment is successful then click on Go to resource to go to the Static Web App blade. In the Azure Portal Now, your site up and you will land up on the Static Web App (Preview) overview page with all the necessary info like URL, Workflow file and etc., and you can click on the url link to browse your site. In the Azure Portal Azure Static WebApp creates a random url for our site, but you can add a custom domain  to your webapp. Azure Static WebApp allows you to create a staging environment by creating a pull request  and when the pull request is merged then the staging environment will be moved to production environment. In the Azure Portal Recently, I have migrated my WordPress site to a static website using Hugo and currently this site is being hosted in the Azure Static WebApps, and till now I have not seen/experienced any issues with this preview hosting platform, however I have my backup plan ready to switch to GitHub Pages just in case of any hurdles.


Setup Azure VM with user assigned managed identity to access Azure KeyVault

Azure Key Vault is to secure the secrets safely and access them securely as needed without hard-coding them in our code to authenticate to various applications on various environments, but the main challenge here is to authenticate to Key Vault, and if it is compromised then the entire secrets in the vault will be compromised so it should be handled properly. To overcome this and handle the secrets securely, Azure has come up with a concept called Managed Identities for Azure Resources as a feature in Azure Active Directory, which will help us to authenticate between the azure resources with a trusted relationship. There are two types of managed identities, one is System Assigned Managed Identity (SAMI) and the other is User Assigned Managed Identity (UAMI), however I am not going to discuss more about the Managed Identities here, you can refer to the Microsoft Docs.  In this demo, I am going to enable User Assigned Managed Identity between Azure Virtual Machine and Azure Key Vault using PowerShell to access the Key Vault from the VM and retrieve the secrets with a trusted relationship. You can enable the User Assigned Managed Identity while creating the VM itself, but for our demo I am going to enable it after the VM is created, and the steps are as follows… Create a new Virtual Machine Create a Managed Identity Create a Key Vault Add a secret to Key Vault Grant Reader IAM role on Key Vault to Managed Identity Grant access policy to Managed Identity on Key Vault to get the secrets from Enable User Assigned Managed Identity on Virtual Machine Test the access on the Virtual Machine Create a new Virtual Machine For our demo I am going to create a simple windows VM with all default values using the New-AzVM CmdLet… # Create a Resource Group $rgName = 'Test-RG' $location = 'westus' $null = New-AzResourceGroup -Name $rgName -Location $location # Create a Virtual Machine $vmName = 'Test-VM' $userName = 'sysadmin' $plainTextPassword = 'P@ssw0rd!' $securePassword = $plainTextPassword | ConvertTo-SecureString -AsPlainText -Force $credential = [pscredential]::new($userName, $securePassword) $vm = New-AzVM -ResourceGroupName $rgName -Name $vmName ` -Location $location -Credential $credential The above code will create a brand new VM with all defaults and allow the RDP (3389) and PowerShell Remoting (5985) ports. If you want to create a fully configured VM of your choice then you can refer to the script on my GitHub Repo.  Users with Contributor role can create & manage Virtual Machines. Create a Managed Identity Install and import the module Az.ManagedServiceIdentity to create managed identity using New-AzUserAssignedIdentityCmdLet, and this module is not part of Az PowerShell module. # Install and Import the module $moduleName = 'Az.ManagedServiceIdentity' Install-Module -Name $moduleName -Force Import-Module -Name $moduleName # Create User Assugned Managed Identity $identityName = 'amuai' $identity = New-AzUserAssignedIdentity -Name $identityName ` -ResourceGroupName $rgName -Location $location The above command will create a User Assigned Managed Identity named amuai. Create a Key Vault Create an Azure Key Vault to store secrets, which we will access it from the Virtual Machine using the Managed Identity… # Create Azure Key Vault $keyVaultName = 'testakv99' $keyVault = New-AzKeyVault -ResourceGroupName $rgName ` -Name $keyVaultName -Location $location The above command will create an Azure Key Vault named testakv99, and now we will add a secret to it. Add a secret to Key Vault For this demo, we will add the same password that was used to create our test VM. # Add a secret to Key Vault $null = Set-AzKeyVaultSecret -VaultName $keyVaultName ` -Name $userName -SecretValue $securePassword Users having the access to Key Vault will have the same access on all the secrets in the vault, so please add the secrets only required to the user. Grant Reader IAM role on Key Vault to Managed Identity For this demo, the managed identity is required to read the credentials from the Key Vault, so we need to grant the Reader role on the Key Vault to the Managed Identity. # Grant Reader role to Managed Identity on Key Vault $null = New-AzRoleAssignment -ApplicationId $identity.ClientId ` -RoleDefinitionName Reader -Scope $keyVault.ResourceId  IAM role is limited to the Key Vault resource only and has no effect on accessing the secrets. You need to grant Key Vault access policy to get the secret. Grant access policy to Managed Identity on Key Vault to get the secrets from Since this is a demo and we only need to get the secret to be used in our code on the managed identity enabled VM, we will grant GETAccess Policy on Key Vault to managed identity. # Grant GET permissions to secrets on Key Key Vault to managed identity Set-AzKeyVaultAccessPolicy -ResourceGroupName $rgName -VaultName $keyVaultName ` -ServicePrincipalName $identity.ClientId -PermissionsToSecrets get Now we need to assign this identity and enable User Assigned Managed Identity on Virtual Machine. Enable User Assigned Managed Identity on Virtual Machine Since we have already created a VM and have that VM object in $vm, we will use the same variable for our demo or else you can get the existing VM using Get-AzVM CmdLet. # Assign the identity and enable User Assigned Managed Identity on Virtual Machine. $null = Update-AzVM -ResourceGroupName $rgName -VM $vm ` -IdentityType UserAssigned -IdentityID $identity.Id All done, now let’s test this on the Managed Identity enabled VM. Test the access on the Virtual Machine Now let’s test the access to Key Vault from the VM without an explicit authentication and get the secret from the Key Vault. Since I want to use the secret in the PowerShell code, I will test the access and retrieve the secret using the PowerShell itself, so I will install Az module on the VM for our testing purpose. If you are not using this secret in the PowerShell, you can use the REST methods to get the secrets from the Key Vault, please refer to the Microsoft Docs  for the same. Get the public ip of the VM and connect to it… # Get the public ip of the new VM $vmPIP = Get-AzPublicIpAddress -ResourceGroupName $rgName -Name $vmName | % IpAddress  Now let’s install the Az module and authenticate to Azure using the Identity flag and access the secret… ## On the NEW VM in which User Assigned Managed Identity enabled # Enter-PSSession -ComputerName $vmPIP -Credential $credential # Install NuGet package provider where Az module is available Install-PackageProvider -Name NuGet -Force # Install the Az module Install-Module -Name Az -Force # Login to Azure with managed identity Login-AzAccount -Identity # Get the secret from the Key Vault $kvName = 'testakv99' $keyName = 'sysadmin' $Secret = Get-AzKeyVaultSecret -VaultName $kvName -Name $keyName | % SecretValueText # You can use this secret in your code, since it is a demo I am writing it to screen Write-Host "The password is: $Secret" You can take a glance of the complete script from my GitHub Repo. 


Know Your Azure VM Created Date Using PowerShell & AZCli

Do you want know when was your Azure VM created? Then this script will retrieve date time created for the given Azure VM(s). Not sure whether there is direct way to retrieve the VM created date, but I couldn’t find any CmdLet to know the VM created date. However, I have written a PowerShell function to know the VM created date by considering the VM OS disk creation date as VM creation date. The function accepts the combination of Resource Group Name and VM Name as mandatory parameters or VM object(s), and you will see the output as below… And even I have tried the same using Azure Cli as well, and you get the output like this… And, here’s the script… PowerShell AZCli <# This script pulls the date and the time on which the Azure VM(s) created. This script accepts Resource Group & VM Name as mandatory parameters and accepts VM object(s) optionally. Since there is no direct Cmdlet to fetch the create date, it is considered the disk create date as VM create date. #> Function Get-AzVMCreateDate { [CmdletBinding()] param ( [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string] $ResourceGroupName, # Resource Group Name [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string] $Name, # VM Name [parameter(Mandatory=$false, ValueFromPipeline=$true)] [System.Object[]] $VMObject # VM Object ) Begin { # Check if the VM Object is from the pipeline $IsItVMObject = $null -ne $VMObject # Checking login, if not asking for the login if (($IsItVMObject -eq $false) -and ($null -eq $(Get-AzContext -ErrorAction SilentlyContinue))) { Login-AzAccount } # Output array object $VMArray = @() } Process { # Fetching the VM details from Resource Group Name and VM Name if provided if ($IsItVMObject -eq $false) { $VMObject = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $Name } foreach ($VM in $VMObject) { # Get the OS Disk Name $VMDiskName = $VM.StorageProfile.OsDisk.Name # Get the Disk Info $VMDiskInfo = Get-AzDisk -ResourceGroupName $VM.ResourceGroupName -DiskName $VMDiskName # Get disk create date & time $VMCreatedDate = $VMDiskInfo.TimeCreated # Add result to the output array $VMArray += New-Object -TypeName psobject -Property @{ ResourceGroup = $VM.ResourceGroupName VMName = $VM.Name CreateDate = $VMCreatedDate } } } End { # Output return ($VMArray | Select-Object ResourceGroup, VMName, CreateDate) } } <# Load the function PS /> . ./Get-AzVMCreateDate.ps1 # on Linux PS \> . .\Get-AzVMCreateDate.ps1 # on Windows #> <# Calling the function PS > Get-AzVMCreateDate #> # Login to your Azure Subscription #az login # Declare variables resourceGroupName='LINUX-RG' vmName='ubuntu01' # Get VM OS disk name vmdiskname=$(az vm show --resource-group $resourceGroupName --name $vmName -d --query "storageProfile.osDisk.name" -o tsv) # Get VM OS disk create date createDate=$(az disk show --resource-group LINUX-RG --name $vmdiskname --query "timeCreated" -o tsv) # Convert the date to readable format createDatef=$(date -d $createDate '+%Y/%m/%d %T') # Output printf "%-20s | %-20s | %-20s\n" "$resourceGroupName" "$vmName" "$createDatef"


Host A Static Website In A Azure Storage Account

What is a static website? By the definition, the static website contains web pages with fixed content and displays the same content to every user on every visit, and static websites are very basic and easy to create. Now static websites can be built using HTML, CSS and JavaScript and hosted on Azure Storage, and support client-side script execution but not server-side, if the static website needs some data processing or manipulation on server-side you can leverage it to Azure Cognitive Services or Azure Functions. What is the use? Static websites are very useful when it doesn’t require high bandwidth, backend support and targeted to limited audiences and mostly for the shorter duration of time. Some useful areas are… Explain about the project and the road map. Just for the sake of presentation in the meeting, create some html documents with the necessary content, upload them to the Azure blob storage and simply access the url from anywhere in the world. Showcase about the products, events and promotions. Sales and marketing teams require nice and colorful web pages to walk through the concepts, so build a website using CSS & HTML, publish it on to Azure blob storage and share the link with the intended audience. Technical Documents & Manuals Host some technical documentation and manuals relating to your project, and share it with the team across the globe for their perusal. How it works? When the static website service is enabled on a Azure storage account you need to enter the default document name; and error document name as optional and when the feature is enabled a container named $web will be created if it doesn’t already exist to upload your website files. Files in the $web container are read only, case sensitive and available to access anonymously… How to access? Available to the public web following this pattern: https://<ACCOUNT_NAME>.<ZONE_NAME>.web.core.windows.net/<FILE_NAME> Available through a Blob storage endpoint following this pattern: https://<ACCOUNT_NAME>.blob.core.windows.net/$web/<FILE_NAME> It can also available with CDN and SSL support  and custom domain name  as well. What is the pricing? Azure Static website feature is free; the pricing is only for storage. But in addition to the storage costs, data egress will apply and in case Azure CDN is enabled to use a custom domain with an SSL certificate, that will also be applicable. How to enable the Static Website feature and host a website using Azure PowerShell? All you need is a valid Azure subscription and follow the steps (in PowerShell)… Login into Azure account. Select the required subscription. Select/Create a Resource Group. Select /Create a Storage Account (StorageV2). Set the current storage account to enable the Static Website feature. Enable the Static Website feature on the current storage account. Upload the website files to the blob storage container ($web). Verify the files uploaded successfully. Retrieve the URL to access the static website. #requires -Module Az ## Ensure logged into your Azure account if([string]::IsNullOrEmpty($(Get-AzContext))) { Add-AzAccount } ## Define the required variables $SubscriptionId = '<SubscriptionId>' # This is your subscription id (ex: 'f34d6539-c45b-4a93-91d9-0b4e6ffb6030') $ResourceGroupName = 'static-websites-rg' # Resource Group $Location = 'southindia' # Location $StorageAccountName = 'staticwebsitesa999' # Storage Account $WebpagePath = "C:\wwwroot\" # Static website files ## Select the required subscription, in case there multiple subscriptions Select-AzSubscription -Subscription $SubscriptionId ## Select/Create Azure resource group # Parameters $ParamList = @{ Name = $ResourceGroupName Location= $Location } # Create the resource group if it doesn't exist $ResourceGroup = Get-AzResourceGroup @ParamList -ErrorAction SilentlyContinue if ($null -eq $ResourceGroup) { New-AzResourceGroup @ParamList } ## Select/Create storage account # Parameters $ParamTable = @{ Name = $StorageAccountName ResourceGroupName = $ResourceGroupName } # Create the storage account if it doesn't exist $StorageAccount = Get-AzStorageAccount @ParamTable -ErrorAction SilentlyContinue if ($null -eq $StorageAccount) { $ParamTable.Location = $Location $ParamTable.SkuName = 'Standard_LRS' $ParamTable.Kind = 'StorageV2' $ParamTable.AccessTier = 'Hot' New-AzStorageAccount @ParamTable } ## Parameters required to use with storage Cmdlets $ParamTable = @{ Name = $StorageAccountName ResourceGroupName = $ResourceGroupName } ## Set the storage account to enable the static website feature Set-AzCurrentStorageAccount @ParamTable ## Enable the static website feature for the selected storage account # Ensure the documents are created with the names mentioned Enable-AzStorageStaticWebsite -IndexDocument "index.html" -ErrorDocument404Path "error.html" ## Upload the website pages to the azure blob container Get-ChildItem -Path $WebpagePath -Recurse | Set-AzStorageBlobContent -Container '$web' ## Verify the files uploaded to the azure blob container Get-AzStorageContainer -Name '$web' | Get-AzStorageBlob ## Retrieve the public URL to access the static website (Get-AzStorageAccount @ParamTable).PrimaryEndpoints.Web ## Add custom domain to your static website, but need to add CNAME record in your domain dns server Set-AzStorageAccount @ParamTable -CustomDomainName "www.yourdomain.com" -UseSubDomain $True With the glory of GitHub public repositories, I have cloned a simple website and created my profile page just like that and hosted it on my Azure Storage.


Create New Azure VM Using PowerShell(Az)

Deploying the Virtual Machines in the Azure cloud using the templates is the best way to create the VM to satisfy the attributes like quick, consistent, reusable and handles the dependency among the resources. However PowerShell has the flexibility to deploy the VMs with ease and allows the user to choose the required parameters necessary for the particular deployment alone without even touching the code. Ofcourse this approach is also quick and reusable, but the user has to ensure the consistency and dependency among the resources if required while creating the resources in the Azure cloud. Since the new Azure PowerShell Module Az 1.0.1 is released, I have written the scripts using the Az module CmdLets. So please install Az module on Windows PowerShell or PowerShell Core, import the module and connect to Azure account using Connect-AzAccount. Add required parameters to the script… #requires -Modules Az param ( [Parameter(Mandatory=$true)] [string] $ResourceGroupName, # Resource Group [Parameter(Mandatory=$true)] [string] $VMName, # VM Name [Parameter(Mandatory=$true)] [string] $Location, # Location [Parameter(Mandatory=$true)] [ValidateSet('Windows','Linux')] [string] $OSType, # OS Type (Windows/Linux) [Parameter(Mandatory=$true)] [string] $VirtualNetworkName, # VNet [Parameter(Mandatory=$true)] [string] $SubnetName, # Subnet [Parameter(Mandatory=$true)] [string] $SecurityGroupName, # NSG [Parameter(Mandatory=$false)] [string] $VMSize, # VM Size [Parameter(Mandatory=$false)] [switch] $AssignPublicIP, # Assign PIP [Parameter(Mandatory=$false)] [pscredential]$VMCredential, # VM login credential [Parameter(Mandatory=$false)] [Int[]] $AllowedPorts # NSG rules ) Ensure you are connected to Azure subscription, if the script exits then connect to Azure subscription using Connect-AzAccount CmdLet, and this is a browser-based authentication. # Verify Login if( -not $(Get-AzContext) ) { return } Ensure that there is no existing vm with the same name in the resource group. If there is a VM already exists then exit the script. # Verify VM doesn't exist $VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -ErrorAction SilentlyContinue if($null -ne $VM) { return } Create VM login credentials, if not provided along with the script… # Create user object if (-not $PSBoundParameters.ContainsKey('VMCredential')) { [pscredential] $VMCredential = Get-Credential -Message 'Please enter the vm credentials' } # Verify credential if ($VMCredential.GetType().Name -ne "PSCredential") { return } The script identifies the existing resources with the names provided, if exist then they will be used and if they don’t exist then will be created with different names. Two things that you need to choose based on your requirements, one is the VM Size and the other is OS Image (Sku)… # Lists all the VM Sizes available in South India region PS C:\> Get-AzVMSize -Location southindia To retrieve the OS Skus, I have written an another post List of available Azure VM Image skus using new Azure PowerShell module Az  , please refer to it… Now the main block starts from here… # Verify/Create a resource group $ResourceGroup = Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue if ($null -eq $ResourceGroup) { $ResourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $Location } # Verify the virtual network $VNet = Get-AzVirtualNetwork -Name $VirtualNetworkName -ResourceGroupName $ResourceGroup.ResourceGroupName -ErrorAction SilentlyContinue if ($null -eq $VNet) { [Microsoft.Azure.Commands.Network.Models.PSSubnet] $SubnetConfig = New-AzVirtualNetworkSubnetConfig -Name $SubnetName -AddressPrefix 192.168.1.0/24 $VNet = New-AzVirtualNetwork -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -Name $VirtualNetworkName -AddressPrefix 192.168.0.0/16 -Subnet $SubnetConfig } else { $Subnets = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $VNet $SubnetConfig = $Subnets | Where-Object -FilterScript {$_.Name -eq $SubnetName} if ($null -eq $SubnetConfig) { $VNetAddressPrefixes = $VNet.AddressSpace.AddressPrefixes $AddressPrefix = @($VNetAddressPrefixes.Split('.')) $AddressPrefix[2] = [int]($Subnets.AddressPrefix|Measure-Object -Maximum).Maximum.ToString().Split('.')[2] + 1 $AddressPrefix = $AddressPrefix -join '.' $VNet | Add-AzVirtualNetworkSubnetConfig -Name $SubnetName -AddressPrefix $AddressPrefix | Set-AzVirtualNetwork } } $Subnet = Get-AzVirtualNetworkSubnetConfig -Name $SubnetName -VirtualNetwork $VNet # Create a public IP address and specify a DNS name if ($PSBoundParameters.ContainsKey('AssignPublicIP')) { [string] $PipName = $VMName + '-pip' $VerifyPip = Get-AzPublicIpAddress -Name $PipName -ResourceGroupName $ResourceGroup.ResourceGroupName -ErrorAction SilentlyContinue if ($null -ne $VerifyPip) { $PipName = $VMName + '-pip-' + $(Get-Random).ToString() } $PublicIP = New-AzPublicIpAddress -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -Name $PipName -AllocationMethod Static -IdleTimeoutInMinutes 4 } # Create/Select a network security group $NSG = Get-AzNetworkSecurityGroup -Name $SecurityGroupName -ResourceGroupName $ResourceGroup.ResourceGroupName -ErrorAction SilentlyContinue if ($null -eq $NSG) { # Create an inbound network security group rules if ($PSBoundParameters.ContainsKey('AllowedPorts')) { [System.Array] $NsgRules = @() [int] $Priority = 1000 foreach ($Port in $AllowedPorts) { $Rule = New-AzNetworkSecurityRuleConfig -Name "Allow_$Port" -Protocol Tcp -Direction Inbound -Priority $Priority -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange $Port -Access Allow $Priority++ $NsgRules += $Rule } $NSG = New-AzNetworkSecurityGroup -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -Name $SecurityGroupName -SecurityRules $NsgRules } else { $NSG = New-AzNetworkSecurityGroup -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -Name $SecurityGroupName } } else { # Add an inbound network security group rules, if missing any if ($PSBoundParameters.ContainsKey('AllowedPorts')) { $NSGAllowedPorts = $NSG.SecurityRules | Where-Object -FilterScript {$_.Access -eq "Allow"} | Select-Object -ExpandProperty DestinationPortRange $PortsToAllow = $AllowedPorts | Where-Object -FilterScript {$_ -notin $NSGAllowedPorts} $Priority = ($NSG.SecurityRules.Priority|Measure-Object -Maximum).Maximum + 100 if ($PortsToAllow.Count -gt 0) { foreach($Port in $PortsToAllow) { $NSG | Add-AzNetworkSecurityRuleConfig -Name "Allow_$Port" -Protocol Tcp -Direction Inbound -Priority $Priority -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange $Port -Access Allow | Set-AzNetworkSecurityGroup } } } } # Create a virtual network card and associate with public IP address and NSG $NICName = "$VMName-nic" $NIC = Get-AzNetworkInterface -Name $NICName -ResourceGroupName $ResourceGroup.ResourceGroupName -ErrorAction SilentlyContinue if ($null -ne $NIC) { $NICName = $VMName + "-nic-" + $(Get-Random).ToString() } $NIC = New-AzNetworkInterface -Name $NICName -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -SubnetId $Subnet.Id -NetworkSecurityGroupId $NSG.Id if ($PSBoundParameters.ContainsKey('AssignPublicIP')) { $NIC | Set-AzNetworkInterfaceIpConfig -Name $NIC.IpConfigurations[0].Name -PublicIpAddressId $PublicIP.Id -SubnetId $Subnet.Id | Set-AzNetworkInterface | Out-Null } # VM Size if($PSBoundParameters.ContainsKey('VMSize') -eq $false ) { $VMSize = 'Standard_A1' } # OS Type $VMSourceImage = @{PublisherName='';Offer='';Sku=''} switch ($OSType) { 'Windows' { $VMSourceImage.PublisherName = 'MicrosoftWindowsServer' $VMSourceImage.Offer = 'WindowsServer' $VMSourceImage.Sku = '2016-Datacenter' } 'Linux'{ $VMSourceImage.PublisherName = 'Canonical' $VMSourceImage.Offer = 'UbuntuServer' $VMSourceImage.Sku = '18.10-DAILY' } } # Create a virtual machine configuration $VMConfig = New-AzVMConfig -VMName $VMName -VMSize $VMSize if ($OSType -eq 'Windows') { $VMConfig | Set-AzVMOperatingSystem -Windows -ComputerName $VMName -Credential $VMCredential | Out-Null } else { $VMConfig | Set-AzVMOperatingSystem -Linux -ComputerName $VMName -Credential $VMCredential | Out-Null } $VMConfig | Set-AzVMSourceImage -PublisherName $VMSourceImage.PublisherName -Offer $VMSourceImage.Offer -Skus $VMSourceImage.Sku -Version latest | Out-Null $VMConfig | Add-AzVMNetworkInterface -Id $NIC.Id | Out-Null $VMConfig | Set-AzVMBootDiagnostic -Disable | Out-Null # Create a virtual machine New-AzVM -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -VM $VMConfig To create a Windows VM… .\Create-AzVM.ps1 -ResourceGroupName test-rg ` -VMName testvm -Location southindia ` -OSType Windows ` -VirtualNetworkName test-vnet ` -SubnetName testnet ` -SecurityGroupName test-nsg ` -AssignPublicIP ` -AllowedPorts 3389 ` -VMCredential $cred ` -Verbose To create a Linux VM… .\Create-AzVM.ps1 -ResourceGroupName test-rg ` -VMName testvm -Location southindia ` -OSType Linux ` -VirtualNetworkName test-vnet ` -SubnetName testnet ` -SecurityGroupName test-nsg ` -AssignPublicIP ` -AllowedPorts 22 ` -VMCredential $cred ` -Verbose You can find the complete source code on my git repository. 


Tagging Microsoft Azure Resources Using Powershell (Az)

In Azure Cloud, Tags play a major role to manage resources in an easy way, in an other words Tags are an additional meta data associated with the Azure resources. We can assign the tags to the individual resources like VM, Storage Account, VNet and etc., and we can also assign the tags to the Resource Groups as well. Resource groups allow us to organize the related resources together and facilitate the management, but tags are used to group the resources beyond the resource groups including the resource groups, and at the same time resources inside the resource group do not inherit the tags associated with the resource group. Tags are Key and Value combination that can be assigned to the resources in the Azure cloud, for example… Tag Key Tag Value ResourceType VM Project MyProject Department Marketing Environment Production CostCenterCode 123456 Do bear in mind that each individual resource can have up to 15 tags max (Microsoft keeps updating the numbers time to time, so please refer the Microsoft Docs for the exact number), and ensure the tags are unique and consistent naming convention among Azure resources. Tags are used to organize the deployed resources in the Azure cloud, we could search the resources by tag key/value, for example search the resources with the tags associated {Key:Value} Type:VM and Environment:Production, then the search results all the production VMs across the resource groups within a subscription. Tags are also used to view the related resources, like all the resources tagged to a specific project or a specific cost center and to facilitate the billing and cost management. Tags can be created at the time of creating resources or at the later time by using the Azure portal or any command line tools like PowerShell or Azure CLI. Let’s see how we can create and manage the tags using PowerShell… #requires -Module Az # Connect-AzAccount ### Add new tags to an existing resource # Get the resource $Resource = Get-AzResource -Name testvm -ResourceGroupName test-rg # Resource tags [hashtable] $Tags = $Resource.Tags # Ensure not to overwrite the tags if ($null -eq $Tags) { [hashtable] $Tags = @{Type="VM"; Environment="Test"} } else { $Tags += @{Type="VM"; Environment="Test"} } # Add new tags to the resource (-Force to override the confirmation if there are any existing tags) Set-AzResource -ResourceId $Resource.Id -Tag $Tags -Force ### Remove an existing tag / remove all tags from a resource # Get the resource $Resource = Get-AzResource -Name testvm -ResourceGroupName test-rg # Resource tags [hashtable] $Tags = $Resource.Tags # Remove the specific tag $Tags.Remove("Type") # Overwrite the remaining tags to the resource (-Force to override the confirmation if there are any existing tags) Set-AzResource -ResourceId $Resource.Id -Tag $Tags -Force ## Remove all tags Set-AzResource -ResourceId $Resource.Id -Tag @{} -Force ### List all the resources with a specific tag key Get-AzResource -TagName "Environment" ### List all the resources with a specific tag value Get-AzResource -TagValue "Test" ### List all the resources with a specific tag key and value Get-AzResource -Tag @{Environment="Test"} ### List all the tags and number of resources associated in a subscription. Get-AzTag


Create And Assign A Public IP To An Azure Virtual Machine

Sometimes deliberately we don’t create and assign a public ip to an Azure Virtual Machine to not to expose to the internet as a safety measure, but later at some point of time we may require the VM to be accessed via internet and we definitely need a public ip to access the VM, the script below will help to create and assign a public ip address to an Azure VM… If no Network Security Group is associated with Virtual Machine, by default all ports are open to the internet, and please be careful. #requires -Module Az # Function to create and assign a public ip address # to an Azure Virtual Machine using Az PowerShell module. Function Assign-AzVMPublicIP2 { Param ( # Resource Group Name [Parameter(Mandatory=$true)] [string] $ResourceGroupName, # Virtual Machine Name [Parameter(Mandatory=$true)] [string] $VMName ) # Retrieve the Virtual Machine details $VM = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VMName -ErrorAction SilentlyContinue # Checking the VM existance if($null -eq $VM) { Write-Error "Please enter a valid and existing Resource Group Name and Virtual Machine Name" return } $Location = $VM.Location # Location to create a public ip $NICId = $VM.NetworkProfile.NetworkInterfaces.Id # Network Interface resource id $NICResource = Get-AzResource -ResourceId $NICId # Retrieve the NIC resource details # Retrive the NIC Object $NIC = Get-AzNetworkInterface -Name $NICResource.Name -ResourceGroupName $NICResource.ResourceGroupName $NICIPConfigName = $NIC.ipConfigurations[0].Name # IP Config Name to be used with Set-AzNetworkInterfaceIpConfig CmdLet $NICSubnetId = $NIC.ipConfigurations[0].subnet.id # Subnet id to be used with Set-AzNetworkInterfaceIpConfig CmdLet # Create a public ip $PublicIP = New-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Location $Location -Name "$VMName-pip" -AllocationMethod Static -IdleTimeoutInMinutes 4 # Warn the user if no NSG is associated with this VM if ($null -eq $NIC.NetworkSecurityGroup) { Write-Warning "Since no Network Security Group is associated with this Virtual Machine, by default all ports are open to the internet." } # Assign the public ip to the VM NIC $NIC | Set-AzNetworkInterfaceIpConfig -Name $NICIPConfigName -SubnetId $NICSubnetId -PublicIpAddressId $PublicIP.Id | Set-AzNetworkInterface } Assign-AzVMPublicIP2 -ResourceGroupName test-rg -VMName test-vm


List Of Available Azure VM Image Skus Using New Azure PowerShell Module Az

As you might already know, Microsoft has released a new Azure PowerShell module Az to replace with AzureRM module in future. As of now both the versions are available for Windows PowerShell and PowerShellCore. But no further developments for AzureRM module except for bg fixes and all the updates and feature enchantments come along with the new modules Az itself. Just to start with the Az module, lets retrieve the list of Azure VM Images (skus) available in a given location from the mentioned publisher with the offerings… #requires -Module Az # Please connect to Azure using Connect-AzAccount # Get the complete list of Azure service locations Get-AzLocation <# Get-AzLocation | Where-Object -FilterScript {$_.Location -match 'india'} Location : southindia DisplayName : South India Providers : {Microsoft.Batch, Microsoft.ClassicCompute, Microsoft.ClassicNetwork, Microsoft.ClassicStorage...} Location : centralindia DisplayName : Central India Providers : {Microsoft.Automation, Microsoft.Batch, Microsoft.ClassicCompute, Microsoft.ClassicNetwork...} Location : westindia DisplayName : West India Providers : {Microsoft.ClassicCompute, Microsoft.ClassicNetwork, Microsoft.ClassicStorage, Microsoft.Compute...} #> # Select Location [string] $Location = 'South India' # Get the complete list of VM Image publishers Get-AzVMImagePublisher <# Get-AzVMImagePublisher -Location "South India" | Where-Object -FilterScript {$_.PublisherName -in ('MicrosoftWindowsServer','Canonical')} PublisherName Location Id ------------- -------- -- Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical MicrosoftWindowsServer SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/MicrosoftWindowsServer #> # Select Publisher [string] $Publisher = 'Canonical' # Get the list of offering from the publisher with in the location Get-AzVMImageOffer -Location $Location -PublisherName $Publisher <# Get-AzVMImageOffer -Location $Location -PublisherName $Publisher | Format-List * Offer PublisherName Location Id ----- ------------- -------- -- UbuntuServer Canonical SouthIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/VMImage/Offers/Ubun... Ubuntu_Core Canonical SouthIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/VMImage/Offers/Ubun... #> # Select the offering [string] $Offer = 'UbuntuServer' # Get the list of image skus available in the given location from the given publisher with the given offerings Get-AzVMImageSku -Location $Location -PublisherName $Publisher -Offer $Offer <# Get-AzVMImageSku -Location $Location -PublisherName $Publisher -Offer $Offer Skus Offer PublisherName Location Id ---- ----- ------------- -------- -- 12.04.5-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.0-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.1-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.2-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.3-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.4-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.5-DAILY-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 14.04.5-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 16.04-DAILY-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 16.04-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 16.04.0-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 18.04-DAILY-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 18.04-LTS UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 18.10 UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 18.10-DAILY UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... 19.04-DAILY UbuntuServer Canonical SouthIndia /Subscriptions/<subscription_id>/Providers/Microsoft.Compute/Locations/SouthIndia/Publishers/Canonical/ArtifactTypes/V... #> # For Windows Server $Location = 'Central India' $Publisher = 'MicrosoftWindowsServer' $Offer = 'WindowsServer' Get-AzVMImageSku -Location $Location -PublisherName $Publisher -Offer $Offer <# Get-AzVMImageSku -Location $Location -PublisherName $Publisher -Offer $Offer Skus Offer PublisherName Location Id ---- ----- ------------- -------- -- 2008-R2-SP1 WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2008-R2-SP1-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2008-R2-SP1-zhcn WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-Datacenter WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-Datacenter-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-Datacenter-zhcn WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-R2-Datacenter WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-R2-Datacenter-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2012-R2-Datacenter-zhcn WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-Server-Core WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-Server-Core-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-with-Containers WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-with-RDSH WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2016-Datacenter-zhcn WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-Core WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-Core-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-Core-with-Containers WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-Core-with-Containers-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-with-Containers WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-with-Containers-smalldisk WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... 2019-Datacenter-zhcn WindowsServer MicrosoftWindowsServer CentralIndia /Subscriptions/899041ff-5768-4e79-931b-a9e9e9bad5fd/Providers/Microsoft.Compute/Locations/Centra... #>


Retrieve Azure Vm Public Ip And Establish The Rdp Session

I don’t know for some reason Microsoft doesn’t provide some solutions directly, directly as in cannot achieve the outcome with a single command in PowerShell, for example to get the public ip address of an Azure VM, in fact I expected it to be as simple as this… Get-AzureRmPublicIpAddress -ResourceGroupName lab-rg -Name Workstation However there is no such command with those parameters, but still it’s not very complicated. I have written a small PowerShell wrapper to retrieve the public ip address of Azure VM and added few more functionalities as well apart from getting only the public ip address it will start the VM if it is not running by enabling the -StartIfVMIsNotRunning flag and connect to RDP session with -ConnectRDP flag. Note: Most of the organizations use either private ip or dns name to connect to the VM from their network, and this is only useful for small businesses or where there is no need of domain authentication and access from outside the local network. The script has two parameter sets Name and Object, which accepts ResourceGroupName and VMName or VMObject along with the other common parameters, and the parameters are as below… [Parameter(Mandatory=$true,ParameterSetName='Name')] [string] $ResourceGroupName, # ResourceGroup Name when the ParameterSetName is 'Name' [Parameter(Mandatory=$true,ParameterSetName='Name')] [string] $VMName, # Virtual Machine Name when the ParameterSetName is 'Name' [Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName='Object')] [Microsoft.Azure.Commands.Compute.Models.PSVirtualMachine] $VMObject, # VM Object when the ParameterSetName is 'Object' [Parameter(Mandatory=$false,ParameterSetName='Name')] [Parameter(Mandatory=$false,ParameterSetName='Object')] [switch] $StartIfVMIsNotRunning, # Start the VM, if it is not running [Parameter(Mandatory=$false,ParameterSetName='Name')] [Parameter(Mandatory=$false,ParameterSetName='Object')] [switch] $ConnetRDP, # Connect Remote Desktop Session [Parameter(Mandatory=$true,ParameterSetName='Help')] [switch] $H # Get Help Since the latest AzureRM (6.13.1) PowerShell module has some significant changes in the outcome of some CmdLets, ensuring the latest module is loaded… # Ensure the 6.13.1 version AzureRM module is loaded, # because some commands output have been changed in this version [System.Version] $RequiredModuleVersion = '6.13.1' [System.Version] $ModuleVersion = (Get-Module -Name AzureRM).Version if ($ModuleVersion -lt $RequiredModuleVersion) { Write-Verbose -Message "Import latest AzureRM module" break } Login into Azure account, if not logged in already… # Login in into the Azure account, if it is not already logged in if([string]::IsNullOrEmpty($(Get-AzureRmContext))) { $null = Add-AzureRmAccount } Retrieve the VM running state and ensure it is running, if -StartIfVMIsNotRunning flag is enabled then the VM will be started if it is not running. If VM is not running and ‘PublicIPAllocationMethod’ is set to static then still public ip can be retrieved, but if it is dynamic then the VM should be in running state itself… # Retrieve the virtual machine running status try { if ($PSCmdlet.ParameterSetName -eq 'Name') { $VM = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMName -Status } elseif ($PSCmdlet.ParameterSetName -eq 'Object') { $VM = Get-AzureRmVM -ResourceGroupName $VMObject.ResourceGroupName -Name $VMObject.Name -Status } } catch { Write-Verbose -Message $_.Exception.Message break } # Check whether the vm PowerState is running $VMStatus = $VM.Statuses | Where-Object { $_.Code -match 'running' } if ([string]::IsNullOrEmpty($VMStatus)) { [bool] $ISVMRunning = $false } else { [bool] $ISVMRunning = $true } # If VM is not running and -StartIfVMIsNotRunning flag is enabled, then start the VM if ($ISVMRunning -eq $false -and $StartIfVMIsNotRunning -eq $true) { $null = Start-AzureRMVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name $ISVmRunning = $true } Now retrieve the public ip address of an Azure VM… # Get Public IP address $VirtualMachine = Get-AzureRMVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name $NICId = $VirtualMachine.NetworkProfile.NetworkInterfaces.id $NICResource = Get-AzureRmResource -ResourceId $NICId $PIPId = $NICResource.Properties.ipConfigurations.properties.publicIPAddress.id $PIPResource = Get-AzureRmResource -ResourceId $PIPId $PIP = $PIPResource.Properties.ipAddress Exit the script if the VM is not running and PublicIPAllocationMethod is Dynamic or public ip is not assigned… # Exit the script if the VM is not running and PublicIPAllocationMethod is Dynamic or public ip is not assigned [string] $PublicIPAllocationMethod = $PIPResource.Properties.publicIPAllocationMethod if ([string]::IsNullOrEmpty($PIP.IPAddressToString) -and $ISVMRunning -eq $false -and $PublicIPAllocationMethod -eq 'Dynamic') { Write-Verbose -Message $("Since {0} VM is not running and 'Public IP Allocation Method is Dynamic', unable to determine the Public IP.`nRun the command with -StartIfVMIsNotRunning flag" -f $VMName) break } elseif ([string]::IsNullOrEmpty($PIP.IPAddressToString) -and $ISVMRunning -eq $true) { Write-Verbose -Message $("No public ip id assigned to this {0} VM." -f $VMName) break } If the ‘-ConnectRDP’ flag is enabled then the remote desktop connection will be established (only when the default port for RDP is allowed in the inbound security rules) otherwise it simply returns the public ip address… # Connect the VM when -ConnectRDP flag is enabled and VM is running if ($ConnetRDP -and $ISVMRunning) { Invoke-Expression "mstsc.exe /v $($PIP.IPAddressToString)" break } # Just return the IP address when no flags are enabled return, $PIP.IPAddressToString And lets see some examples… .EXAMPLE C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation xxx.xxx.xxx.xxx Returns the public ip address when the VM is running or the VM is deallocated but the publicIPAllocationMethod is set to 'Static'. .EXAMPLE C:\GitRepo> $VM = Get-AzureRmVM -ResourceGroupName lab-rg -Name Workstation C:\GitRepo> $VM | .\Get-ARMVMPIP.ps1 xxx.xxx.xxx.xxx Returns the public ip address when the VM is running or the VM is deallocated but the publicIPAllocationMethod is set to 'Static'. .EXAMPLE C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -StartIfVMIsNotRunning xxx.xxx.xxx.xxx Returns the public ip address when the VM is running or starts the VM if it is not running and returns the public ip. .EXAMPLE C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -ConnectRDP # Doesn't return any output simply connects to RDP session Connect to RDP session when the VM is running .EXAMPLE C:\GitRepo> .\Get-ARMVMPIP.ps1 -ResourceGroupName lab-rg -Name Workstation -ConnectRDP # Doesn't return any output simply connects to RDP session Connect to RDP session when the VM is running and if the VM is not running it will start and establish the RDP session. The complete code is available in my git repository. 


Build & Publish A Static Website on Azure (Presentation)

Are you under an impression that you should be skilled in HTML, CSS and JavaScript to create a website or a blog, and want to create a website/blog of your own, and because of that perception you are not able to create one, and also wondering about other overheads such as hosting platform, security, domain mapping and etc.?


Azure PowerShell - Getting Started (Presentation)

Azure PowerShell is used to automate, manage and administrate the Microsoft Azure Services. It is a PowerShell module used with the command line interface with vast support of Azure services and huge collection of cmdlets.