Powershell

Azure Disk Encryption and Azure Backup

If you are looking to use Azure Disk Encryption and Azure Backup you need to follow a couple of additional steps to the standard encryption procedure.

The offical documentation can be found below:

How it works

There are two types of encryption keys to consider.

  • BEK – Bit Locker Encryption Key
  • KEK – Key Encryption Key

The encryption service uses Key Vault to manage the secrets, to do this we need an application in Azure AD that has permissions (Set by a Key Vault Access Policy) to operate inside of Key Vault.

This is used if you are just using BEK or setting up KEK for Azure Backup support.

For KEK a Key must be imported or created in the Key Vault. You reference this key when running the commands.

Finally, the Backup Management Service needs permissions to access the Key Vault and the keys.

Image 1: Example of Secrets inside of Key Vault

Procedure

Please note: You will need a Key Vault before you can complete this procedure. The Key Vault must be in the same region as the VM that will be encrypted.

1. Set up an Azure AD Application

In Azure Active Directory, select App registrations and create a new app registration. Enter a Name, select Web app / API and assign a sign-on URL (you will not use this so a default entry is adequate).


Image 2: App Registration in Azure Active Directory

Make a note of the Application ID and create and take note of the application Key. Please note that the Key will only be available to you after it is saved and only once on the page. After that it will be hidden.

2. Configure the permissions in the Key Vault for the new Azure AD Application

In the Key Vault set up an Access Policy for the new application.

      
Image 3: Setting up permissions in the Key Vault (an Access Policy)

Key Permissions need to be set to Wrap Key, Secret permissions to Set.


Image 4: Setting the Key Vault Access Policy for the Azure AD Application

3. Create a Key in Key Vault

This will be the key used to wrap the BEK, also known as the KEK


Image 5: Creating the KEK

4. Set permissions for the Backup Management Service

Select Access Policies and from the template select Azure Backup. The principal will be Backup Management Service.

    
Image 6: Creating the Access Policy for the Backup Management Service

5. Check the Advanced access policies to enable access to Azure Disk Encryption for volume encryption.


Image 7: Setting the Advanced Access policies for Disk Encryption

PowerShell commands for an existing VM


subscriptionName = "SUBSCRIPTION NAME"

$RGName = "RESOURCE GROUP NAME"

$VMName = "VM NAME"

$AADClientID = "AZURE AD APPLICATION ID"

$AADClientSecret = "AZURE AD APPLICATION SECRET"

$VaultName= "KEY VAULT NAME"

$keyName = "KEY NAME"

$keyEncryptionKeyUri = Get-AzureKeyVaultKey -VaultName $VaultName -KeyName $keyName

$KeyVault = Get-AzureRmKeyVault -VaultName $VaultName -ResourceGroupName $RGName

$DiskEncryptionKeyVaultUrl = $KeyVault.VaultUri

$KeyVaultResourceId = $KeyVault.ResourceId

Set-AzureRmVMDiskEncryptionExtension -ResourceGroupName $RGName -VMName $vmName -

AadClientID $AADClientID -AadClientSecret $AADClientSecret -

DiskEncryptionKeyVaultUrl $DiskEncryptionKeyVaultUrl -DiskEncryptionKeyVaultId

$KeyVaultResourceId -KeyEncryptionKeyUrl $keyEncryptionKeyUri.Id -

KeyEncryptionKeyVaultId $keyVaultResourceId

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Adding a Public IP to an Existing Azure ARM VM

If you are not running a jump host in your environment I find from time to time that I need to add a Public IP to a NIC and connect to my virtual machine.

PowerShell is by far the easiest way to complete this task. The small script below outlines how to do this.

# New-AzurePublicRmIAddress creates the new IP - Run this first. 

new-azurermpublicIPAddress -Name testip -ResourceGroupName wpbackup -AllocationMethod Static -Location "Southeast Asia"

# Set the variables but getting the properties you need 
$nic = Get-AzurermNetworkInterface -ResourceGroupName Nameof ResourceGroup -Name NameofNIC
$pip = Get-AzurermPublicIPAddress -ResourceGroupName wpbackup -Name testip
$nic.IPConfigurations[0].PublicIPAddress=$pip

# Finally set the IP address against the NIC
Set-AzureRmNetworkInterface -NetworkInterface $nic

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Audit number of VHDs per Storage Account | Azure

Time for some code.  I was recently asked by a customer to help them audit the number of active VHDs in a storage account.

As ever with a little digging around and some slight adjustment I was able to provide what they were after.

Original came from the very accomplished John Savill and was posted at Windows IT Pro.

$FindStorage = Get-AzurermStorageAccount 
$out = @()
 
Foreach ($Storage in $FindStorage)
{
$Name = $Storage.StorageAccountName
$ResourceGroupName = $Storage.ResourceGroupName
$Location = $Storage.Location

$AllBlobs = Get-AzureRMStorageAccount -Name $Name -ResourceGroupName $ResourceGroupName | 
    Get-AzureStorageContainer | where {$_.Name -eq 'vhds'} | Get-AzureStorageBlob | where {$_.Name.EndsWith('.vhd')} 

$VHDsinAct = 0

foreach ($Blob in $AllBlobs)
{

    if($Blob.ICloudBlob.Properties.LeaseState -eq 'Leased' -and $Blob.ICloudBlob.Properties.LeaseDuration -eq 'Infinite')
    {        
        $VHDsinAct++ 
    }
}

$props = @{

StorageAccount = $Name
VHDs = $VHDsinAct
ResourceGroup = $ResourceGroupName
Location =$Location
}
 #Write-Output "Total of $VHDsinAct VHDs in $Name"
 $out += New-Object PsObject -Property $props
}

$out | Format-Table -AutoSize -Wrap  StorageAccount, VHDs, ResourceGroup, Location 
$out | Out-GridView -Passthru

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Audit Azure ARM Networks

Consultants love to audit environments and there is no better use of a script than for this purpose.

This script lists out the virtual networks and subnets in a subscription.

Remember there is always a better way to do things and if you have a better way don’t forget to share.

$FindNetworks = Find-AzureRmResource | where {$_.ResourceType -like "Microsoft.Network/VirtualNetworks"}</code>

$out = @()

Foreach ($Network in $FindNetworks)
{
$Name = $Network.Name
$ResourceType = $Network.ResourceId
$ResourceGroupName = $Network.ResourceGroupName
$Location = $Network.Location

$VNetDetail = Get-AzureRmvirtualNetwork -Name $Network.Name -ResourceGroupName $Network.ResourceGroupName

$props = @{

VNetName = $Network.Name
ResourceGroup = $Network.ResourceGroupName
Location = $Network.Location
AddressSpace = $VNetDetail.AddressSpace.AddressPrefixes
Subnets = $VNetDetail.Subnets

}
$out += New-Object PsObject -Property $props
}
$out | Format-Table -AutoSize -Wrap  VNetName, AddressSpace, Subnets, ResourceGroup, Location
$out | Out-GridView -Passthru

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Hybrid Use Benefit from Image | Azure

Please see post Hybrid Use Benefit HUB | Azure for details on the Microsoft HUB process.

I have been using a slight edit on the process described so thought I would place the code I have been using below.

Please note HUB images are now available in Azure, therefore a generalised image is no longer required.

#login into azure and select the right subscription
Login-AzureRmAccount
Get-AzureRmSubscription
Select-AzureRmSubscription

#upload HUB file
$RGName = "Resource Group Name"
    $urlOfUploadedImageVhd = "https://storageaccountname.blob.core.windows.net/container/imagename.vhd"
    Add-AzureRmVhd -ResourceGroupName $rgName -Destination $urlOfUploadedImageVhd -LocalFilePath "C:\Source\imagename.vhd" 

#Create VM using image
$Cred = Get-Credential #Don't forget needs to be complex
$vmName = "Name of VM"
$StorageAccount = Get-AzureRmStorageAccount -ResourceGroupName $RGName -name "Resource Group Name"
$OSDiskName = "$vmName-C-01" 
$nicname = "Nic01-$vmName-Prod"
$OSDiskUri = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $OSDiskName + ".vhd" #Name & path of new VHD
$URIofuploadedImage = $StorageAccount.PrimaryEndpoints.Blob.ToString() + "image container/image.vhd" #location of template VHD
$Location= "Azure location"

#Networking 
$Vnet = Get-AzureRmVirtualNetwork -Name "Virtual Network Name" -ResourceGroupName $RGName
$SubnetProduction = Get-AzureRmVirtualNetworkSubnetConfig -Name "Sub-1" -VirtualNetwork $Vnet
$Nic = New-AzureRmNetworkInterface -ResourceGroupName $RGName -Name $Nicname -Subnet $SubnetProduction -Location $Location

#Define VM Configuration
$VMConfig = New-AzureRmVMConfig -VMName $vmName -VMSize "Standard_DS2" |
    Set-AzureRmVMOperatingSystem -Windows -ComputerName $vmName -Credential $Cred -ProvisionVMAgent -EnableAutoUpdate |
    Set-AzureRmVMOSDisk -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage -SourceImageUri $URIofuploadedImage -Windows |
    Add-AzureRmVMNetworkInterface -Id $Nic.ID -Primary

#Create VM
New-AzureRmVM -ResourceGroupName $RGName -Location $Location -LicenseType "Windows_Server" -VM $VMConfig

#Check license type of new VM
Get-AzureRmVM -ResourceGroupName $RGName -Name $vmName | Format-Table -AutoSize Name, LicenseType, Location, ProvisioningState

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Azure PowerShell Scripts

Creating a VM from an Azure Image | Azure – Existing Network

I recently created a script to create a VM from an existing disk in Azure, using the v2 or ARM model.

This script created a new network but in most instances a network will already exist and although you will create a new NIC you will want to place this VM into an existing subnet.

The extract below can be used to create a new NIC but add this to a named vNet and Subnet.
When you define the VM configuration you would use this to be the NIC.
Finally make sure this (if the first NIC) is set as -Primary


#Networking
$NicName = $vmName + "NIC-Prod"
$Vnet = Get-AzureRmVirtualNetwork -Name "hubsydvnet" -ResourceGroupName $RGName
$SubnetProduction = Get-AzureRmVirtualNetworkSubnetConfig -Name "Sub-1" -VirtualNetwork $Vnet
$Nic = New-AzureRmNetworkInterface -ResourceGroupName $RGName -Name $NicName -Subnet $SubnetProduction -Location $Location

#Define VM Configuration
$VMConfig = New-AzureRmVMConfig -VMName $vmName -VMSize "Standard_DS2_v2" |
Set-AzureRmVMOperatingSystem -Windows -ComputerName $vmName -Credential $Cred -ProvisionVMAgent -EnableAutoUpdate |
Set-AzureRmVMOSDisk -Name $OSDiskName -VhdUri $OSDiskUri -CreateOption FromImage -SourceImageUri $URIofuploadedImage -Windows |
Add-AzureRmVMNetworkInterface -Id $Nic.ID -Primary

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Tag Azure VMs and Resources

Tagging in Azure is a massively useful feature.  I have customers who are interested in identifying resources for billing but they are also a very useful tool for control.  Resources can be grouped by tag and then a script can be used to apply a function to all machines or services with the same tag.

In the example below I call a variable that looks for Azure resources where the type is identified as a Microsoft virtual machine.  Calling this function enables me to extract a range of information. (I fact this script then goes on and uses the ResourceId too)

As referenced in Using tags to organize your Azure resources tags are updated as a whole so if you want to add additional tags you first have to call the existing tags.  In the example below I am adding the new tag to my existing tags.

Finally we are looping this for each vm and applying via a set command.

Hope this is of use to you, happy tagging :-)!


$FindVMs = Find-AzureRmResource | where {$_.ResourceType -like "Microsoft.Compute/virtualMachines"}
$Tags = (Get-AzureRmResource -ResourceId $ResourceId).Tags
$Tags += @{ Owner = "wade" }

Foreach ($vm in $Findvms)
{
$ResourceId = $VM.ResourceId
Set-AzureRmResource -Tag $Tags -ResourceId $ResourceId -Force
}

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Creating a VM from an Azure Image | Azure

Working with Azure in the enterprise means you will quickly want to create your own custom images.  In this introductory article I will show you an example of how to create an image from an existing generalized imaged.

Please note:

  • This is utilising the ARM model and does not apply to Classic.
  • This assumes you have created a generalized image in Azure and know where it is!
  • This process is not considering on premises VMs.
  • This process uses Windows images.

The following documents and articles were used to create the script below.  Many thanks to the efforts and hard work of the authors.

Create a Virtual Machine from a User Image by Philo

Upload a Windows VM image to Azure for Resource Manager deployments by Cynthia Nottingham

Cynthia shows how to create the image and find the URL of the uploaded image.  She also gives detailed examples of the PowerShell scripts required to create the new VM.

Philo uses variables for existing networks which I found very useful and just comment out the pieces I do not need, e.g. when the vnet already exists.

Happy VM creating!


$cred = Get-Credential
$rgName = "ResourceGroupName"
$location = "Azure Location"
$pipName = "Public IP address Name"
$pip = New-AzureRmPublicIpAddress -Name $pipName -ResourceGroupName $rgName -Location $location -AllocationMethod Dynamic
$subnet1Name = "Subnet Name"
$vnetSubnetAddressPrefix = "Subnet address e.g. 10.1.0.0/24"
$vnetAddressPrefix = "vnet address e.g. 10.1.0.0/16"
$nicname = "Name of Nic"
$vnetName = "Name of vnet"
$subnetconfig = New-AzureRmVirtualNetworkSubnetConfig -Name $subnet1Name -AddressPrefix $vnetSubnetAddressPrefix
#$vnet = New-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName -Location $location -AddressPrefix $vnetAddressPrefix -Subnet $subnetconfig
$nic = New-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $rgName -Location $location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id
$vmName = "Name of VM"
$vmConfig = New-AzureRmVMConfig -VMName $vmName -VMSize "Standard_A4"
$computerName = "Nameof Cumputer"
$vm = Set-AzureRmVMOperatingSystem -VM $vmConfig -Windows -ComputerName $computerName -Credential $cred -ProvisionVMAgent -EnableAutoUpdate
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic.Id
$osDiskName = "Name of Disk"
$osDiskUri = '{0}vhds/{1}{2}.vhd' -f $storageAcc.PrimaryEndpoints.Blob.ToString(), $vmName.ToLower(), $osDiskName
$urlOfUploadedImageVhd = "URL to generaized image https://somename.blob.core.windows.net/system/Microsoft.Compute/Images/templates/name-osDisk.00aaaa-1bbb-2dd3-4efg-hijlkmn0123.vhd"
$vm = Set-AzureRmVMOSDisk -VM $vm -Name $osDiskName -VhdUri $osDiskUri -CreateOption fromImage -SourceImageUri $urlOfUploadedImageVhd -Windows
$result = New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vm
$result

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.

Auto Shutdown ARM Virtual Machines in Azure | Azure Automation

With the release of the RunAs feature in Azure Automation.  A service account can now be called in Azure Automation scripts to enable and run Resource Manager functions.

I think one of the most useful features of this is to auto shutdown virtual machines by TAG.

In the example below I have set up the following:

  • A TAG called “Environment” with and ID of “Lab” and applied to each VM I want to control.
  • A RunAs service account as part of my AzureAutomation resource.
  • A PowerShell Workflow script to scan for the TAGs applied to Windows virtual machines and to shut them all down in parallel.
  • An Azure Automation schedule to run Monday-Friday at 17:00 to call the published workflow.

When configuring a schedule through the browser it uses the browser’s local time zone.  This is stored in UTC but is converted for you.   You’ll need to consider this is managing multiple resources across the globe.

This workflow and process has been created via the Azure Portal.

The -Parallel feature is only available in Powershell Workflows.

workflow TestPowershellworkflow
{
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint

    $FindVMs = Find-AzureRmResource -TagName "Environment" -TagValue "Lab" | where {$_.ResourceType -like "Microsoft.Compute/virtualMachines"}

   Foreach -Parallel ($vm in $Findvms)

   {
    $vmName = $VM.Name
    $ResourceGroupName = $VM.ResourceGroupName

    Write-Output "Stopping $($vm.Name)";
    Stop-AzureRmVm -Name $vm.Name -ResourceGroupName $ResourceGroupName -Force;
    }
}

I’d be very interested in your feedback.  Happy automating.

Disclaimer:  Please note although I work for Microsoft the information provided here does not represent an official Microsoft position and is provided as is.