Publish a static website on Azure Static WebApps (Preview)

Hosting on ☁️ Azure Static WebApps (Preview) Azure Static WebApps 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  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 Full Name>" To set email address… C:\Sites\kpatnayakuni> git config --global "<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<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.

23 June 2020

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. 

4 February 2020

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 "" -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"

26 September 2019

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><FILE_NAME> Available through a Blob storage endpoint following this pattern: https://<ACCOUNT_NAME>$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 "" -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.

24 January 2019

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 $VNet = New-AzVirtualNetwork -ResourceGroupName $ResourceGroup.ResourceGroupName -Location $Location -Name $VirtualNetworkName -AddressPrefix -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. 

3 January 2019

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

2 January 2019

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 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

29 December 2018

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... #>

28 December 2018

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 = $ $NICResource = Get-AzureRmResource -ResourceId $NICId $PIPId = $ $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 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 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 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. 

20 December 2018