Archive for category Poweshell

Azure Key Vault Access Policies

Azure-KeyVault_COLORAzure Key Vault is used to safeguard system critical data, such as keys, secrets and certificates that are part of your infrastructure core operations.

Key Vault access is managed through two interfaces: management plane – this dictates access to the Key Vault itself but not managing its content which is based on RBAC model, data plane – this enables granular control of keys/secrets/certificates, which relies on Access Policy.

This brings us nicely to Access Policies which is meat of this article. I have had to deal with a situation lately while applying access policy for a colleague while a restriction is imposed on my Azure AD account (see example below)




This would have limited access to my account (which is external) to AAD, which means I cant read or search AAD which is required when adding access policy via the GUI – Setting RBAC without access to AAD works (as an exception) if you know the full FQDN of the user you are adding.

The way around is to use PowerShell, but this requires a prerequisite which is the Azure AD object ID for the user you want to add, this can be achieved by adding them temporarily on management plane to access their user properties and copy object ID before deleting that rule.

Now to the command I used to apply that permission:

Set-AzKeyVaultAccessPolicy -ObjectId *** -VaultName **** -PermissionsToKeys **** -PermissionsToSecrets **** -PermissionsToCertificates **** -BypassObjectIdValidation 


Key property here is the BypassObjectIdValidation, if the Object ID exists in AAD then it will be linked and the user will have their access policy applied to Azure Key Vault.

, , ,

Leave a comment

Azure Custom Script Extension

It has been a while since I had the opportunity to blog. It has been a very busy period which is good in some ways …

Anyway, today I wanted to pick up on Azure CSE. Azure CSE is beneficial in many ways when it comes to configuring VM’s, installing application and making app configuration changes.

Normally, when running an Azure CSE for Windows, people do favour Powershell scripts which gives them the power (in the name) and functionality to do their configuration elements with ease.

The recent issue I faced with Powershell scripts are particularly around Invoke-Command which runs a script block inside the VM under VM System context. Those Invoke-Command statements were issued to install a sequence of applications and configure the app in a certain way.

My word of advice is to avoid using Invoke-Command and use Start-Process instead.

For example:

Invoke-Command -ScriptBlock { “C:\Temp\Setup.exe /q”}

You would think this would go and install that Setup.exe program, but it many cases it doesn’t and you find there is a missing element in your application sequence.

A better and more effective way of doing this is:

Start-Process “C:\Temp\Setup.exe” -ArgumentList “/q” -Wait

This would ensure running of the Setup.exe installer and waiting for finish flag before it continues with the rest of your Azure CSE script, which the Invoke-Command doesn’t offer.

Simple things like that would make you script neater especially in managing error/failure codes during the install of the application.

To be honest, I would prefer the DSC way if you have the time and knowledge.

, ,

Leave a comment

Application Gateway bug – Jan 2017

bug-512I have been working with Microsoft lately on an issue that I was experiencing with an Azure application gateway (appGW) deployment that require both internal and external interfaces handling traffic over HTTPS.

If you try to attach the same AppGW front end port to internal and external front end configuration, this would cause the appGW to misbehave. In my scenario I had a rule attached to external interface for handling incoming traffic but no rule attached on the internal interface and as a consequence the internal interface started processing traffic while the external interface was rejecting all connections (not even 502 error! would you believe!). Just to note that all my appGW deployments are scripted using PowerShell/JSON.

Microsoft managed to replicate this internally and issued a bug report, they are working on it as we speak but without ETA currently.

I had to drop my second listener (internal) in order to bring the appGW back to it’s expected behaviour!

, , , ,


The myth of Azure Application Gateways – Part 1

5db46fc5-d9c1-44ae-a0f6-4ae1d2301395Azure Application Gateways is a layer 7 reverse proxy service offered as a PaaS to general public. It supports SSL offloading, which means you can terminate your SSL connection at the Application Gateway and connect to the backend server using HTTP traffic or initiate a new SSL connection to your backend service.

This is all well and good, simple and painless if you have a single backend server with a single website. The complexity of the solution increases as the backend start leveraging more of the IIS functionalities such as Windows/NTLM authentication, SNI and host headers or various SSL certificates used for each sub-site (if you have multiple sites running on the same IIS server).

Before even starting to look at designing your Azure Application Gateway, there are few guidelines you will need to follow:

  • You should have an empty default site.
  • If using both HTTP/HTTPS protocols on any of the sub-sites, the default website should be listening on both 80 and 443.
  • In the case of HTTPS the default site will need to be loaded with a single SSL certificate that will primarily be used by the Application Gateway to authenticate against the server.
  • Not running SNI on default website.
  • If you are running NTLM or Windows authentication on any of the sites (except form based authentication) then you will need a site/page that allow anonymous authentication to be used for Application Gateway custom probe.
  • Use IP address for the backend pool rather than FQDN.

The above will save you a lot of hassle while implementing and configuring your Application Gateway to work with your backend web server.

Microsoft have fixed few issues we were experiencing recently with Application Gateways around SSL and custom probes.

There are two ways available to deploy an Application Gateway, Powershell or JSON template. The latter is preferable to ensure consistency at each deployment. This article is in two parts, in this article I will be using Powershell to deploy an Application Gateway.


  • SSL private key in PFX format for all sites using SSL
  • SSL public key in CER format for default site
  • IP address of the backend web server
  • Front and backend listening port
  • Site/page with anonymous access if requiring authentication

Powershell code below would deploy an Application Gateway listening on two ports (80,443). The backend consists of four sites with SNI and host headers enabled, two sites run under port 80, one of them require basic authentication. Another two sites run under port 443 bound with self-signed SSL cert for testing, one of the sites has basic authentication turned on. This would test the four common scenarios of a typical deployment.

Get-AzureRmSubscription | Select Subscription* | out-gridview -Title "Select your Azure Subscription" -OutputMode Single | Select-AzureRmSubscription 

$ApplicationGWName = "ApplicationGatewayName"
$AppGatwayPIPName = "ApplicationGatewayPublicIPName"
$vnetName = 'vNETName'
$VNetResourceGroup = 'vNETResourceGroup'
$AppGWSubnetName = 'ApplicationGatewaySubnetName'
$ResouceGroupName = "ApplicationGatewayResourceGroupName"
$Location = "UK South"
$BackendIPaddresses =  "BackendServerIP"

New-AzureRmResourceGroup -Name $ResouceGroupName -Location $Location

#Prompt for Certificate password
$SecurePassword = Read-Host -AsSecureString  "Enter Certificate password"
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

#Retrive Virtual Network and Application Gateway information
$vnet = Get-AzureRmvirtualNetwork -Name $VnetName -ResourceGroupName $VNetResourceGroup
$gwSubnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $AppGWSubnetName -VirtualNetwork $vnet

#Create Public IP address for Application Gateway
$publicip = New-AzureRmPublicIpAddress -ResourceGroupName $ResouceGroupName -Name $AppGatwayPIPName -Location $Location -AllocationMethod Dynamic
#$publicip = Get-AzureRmPublicIpAddress -Name $AppGatwayPIPName -ResourceGroupName $ResouceGroupName

#Create an application gateway IP configuration, this setting configures what subnet the application gateway uses
$gipconfig = New-AzureRmApplicationGatewayIPConfiguration -Name 'appGatewayIpConfig' -SubnetId $gwSubnet.Id -Verbose

#Create a front-end IP configuration, this setting maps the public ip address to the front-end of the application gateway
$fipconfig = New-AzureRmApplicationGatewayFrontendIPConfig -Name 'appGatewayFrontendIP' -PublicIPAddress $publicip

#Configure the back-end IP address pool with the IP addresses of the backend web servers
$pool = New-AzureRmApplicationGatewayBackendAddressPool -Name 'appGatewayBackendPool' -BackendIPAddresses $BackendIPaddresses

#Configure the front-end IP port for the public IP endpoint
$fp = New-AzureRmApplicationGatewayFrontendPort -Name 'appGatewayFrontendPorthttps' -Port 443
$fp1 = New-AzureRmApplicationGatewayFrontendPort -Name 'appGatewayFrontendPorthttp' -Port 80

#Configure the certificate for the application gateway
$cert = New-AzureRmApplicationGatewaySslCertificate -Name wildcard -CertificateFile '.\selfsignedcert.pfx'

#Create the HTTPS listener for the application gateway. Assign the front-end ip configuration, port, and ssl certificate to use
$listener1 = New-AzureRmApplicationGatewayHttpListener -Name authHTTPS -Protocol Https -FrontendIPConfiguration $fipconfig -FrontendPort $fp `
                                                       -HostName "" -RequireServerNameIndication true -SslCertificate $cert

$listener2 = New-AzureRmApplicationGatewayHttpListener -Name noauthHTTPS -Protocol Https -FrontendIPConfiguration $fipconfig -FrontendPort $fp `
                                                       -HostName "" -RequireServerNameIndication true -SslCertificate $cert

$listener3 = New-AzureRmApplicationGatewayHttpListener -Name authHTTP -Protocol Http -FrontendIPConfiguration $fipconfig `
                                                       -FrontendPort $fp1 -HostName ""

$listener4 = New-AzureRmApplicationGatewayHttpListener -Name noauthHTTP -Protocol Http -FrontendIPConfiguration $fipconfig `
                                                       -FrontendPort $fp1 -HostName ""

#Upload the certificate to be used on the ssl enabled backend pool resources - authentication certificate
$authcert = New-AzureRmApplicationGatewayAuthenticationCertificate -Name 'sanauthcert' -CertificateFile '.\publickey.cer'

#Configure the application gateway back-end http settings. Assign the certificate uploaded in the preceding command to the http settings
$poolSetting1 = New-AzureRmApplicationGatewayBackendHttpSettings -Name 'wildcard' -Port 443 -Protocol Https `
                                                                 -CookieBasedAffinity Enabled -AuthenticationCertificates $authcert

$poolSetting2 = New-AzureRmApplicationGatewayBackendHttpSettings -Name 'unsecured' -Port 80 -Protocol Http -CookieBasedAffinity Enabled

#Create a load balancer routing rule, Basic Round Robin
$rule1 = New-AzureRmApplicationGatewayRequestRoutingRule -Name 'authHTTPrule' -RuleType basic -BackendHttpSettings $poolSetting2 `
                                                         -HttpListener $listener3 -BackendAddressPool $pool
$rule2 = New-AzureRmApplicationGatewayRequestRoutingRule -Name 'noauthHTTPrule' -RuleType basic -BackendHttpSettings $poolSetting2 `
                                                         -HttpListener $listener4 -BackendAddressPool $pool
$rule3 = New-AzureRmApplicationGatewayRequestRoutingRule -Name 'authHTTPSrule' -RuleType basic -BackendHttpSettings $poolSetting1 `
                                                         -HttpListener $listener1 -BackendAddressPool $pool
$rule4 = New-AzureRmApplicationGatewayRequestRoutingRule -Name 'noauthHTTPSrule' -RuleType basic -BackendHttpSettings $poolSetting1 `
                                                         -HttpListener $listener2 -BackendAddressPool $pool

#Configure the instance size of the application gateway
$sku = New-AzureRmApplicationGatewaySku -Name Standard_Small -Tier Standard -Capacity 1

#Create the Application Gateway
$appgw = New-AzureRmApplicationGateway `
                -Name $ApplicationGWName `
                -SslCertificates $cert `
                -ResourceGroupName $ResouceGroupName `
                -Location $Location `
                -BackendAddressPools $pool `
                -BackendHttpSettingsCollection $poolSetting1,$poolSetting2 `
                -FrontendIpConfigurations $fipconfig `
                -GatewayIpConfigurations $gipconfig `
                -FrontendPorts $fp,$fp1 `
                -HttpListeners $listener1,$listener2,$listener3,$listener4 `
                -RequestRoutingRules $rule1,$rule2,$rule3,$rule4 `
                -Sku $sku `
                -AuthenticationCertificates $authcert `

To be continued …..


Azure Automation – Provision and Domain Join Azure ARM VM.

automation-930x620Automation has become a large part of any Ops team work stream. It reduces repetitive work and introduces a clear and effective method of ensuring consistency across your platforms, server estate and businesses.

In this article I will go through Azure Automation, especially automation of VM creation and joining the domain. This would lift some of the load of IT to provision and join those VM’s to the domain manually and allowing developers to take a much agile approach.

The automation process is based on Azure Runbook, utilising Powershell workflow and Runbook assets in fully automating the whole process.

You also should have a startup image (i.e. golden image) sysprep’ed and uploaded to a known and accessible storage account in that subscription. You need to ensure that the image was generalised and shutdown. This type of deployment will ensure all your applications and settings are packaged as part of that deployment – that’s if you don’t want to use Microsoft own images. You need to make sure you are covered by MSDN licenses if you are uploading client images and ensure your server image is appropriately licensed as well, plus any application you package as part of that image.

You are probably keen to get down to business …. few things you have to make sure of to ensure this whole process work for you. This automation task is based on creating an Azure ARM VM, you will need three credential assets created under your automation account which will be used with your script:

  1. Asset for local VM admin
  2. Asset with Azure co-admin rights – or at least VM creation rights
  3. Asset with domain admin rights

The vhd image of your packaged and generlised VM needs to be uploaded to a storage account. Make a note of that storage account, any VM created of that image will need to reside on same storage account. If you need to create  a VM on a different storage account then you will need to copy that image across first.

The script is split to two parts, the main body which is the Runbook – Powershell workflow

On Azure, create a Runbook called AzureVMDomainJoin and paste the code below:

workflow AzureVMDomainJoin
     param (
        [string] $subId,
        [string] $vmName,
        [string] $vmSize,
        [string] $domain,
        [string] $OU,
        [string] $vmRGName,
        [object] $vmNic,
        [string] $stgName,
        [string] $stgRGName,
        [string] $stgBlobstr,
        [string] $location


     # Enable verbose logging

     # Fetching credentials
     $LocalAdmin = Get-AutomationPSCredential -Name 'AzureLocalAdmin'
     $DomainAdmin = Get-AutomationPSCredential -Name 'AzureDomainJoin'
     $AZAutomationAccount = Get-AutomationPSCredential -Name 'AzureAutomationAccount'

     # Login to Azure and select Subscription
     Login-AzureRmAccount -Credential $AZAutomationAccount -SubscriptionId $subId

     $osDisk = $vmName + "-osDisk"
     $osDiskUri = $stgBlobstr + $vmName.ToLower() + '.vhd'
     $vmImageUri = ''
     InlineScript {
        # Create a new VM config
        $vmConfig = New-AzureRmVMConfig -VMName $Using:vmName -VMSize $Using:vmSize

     	# Add the new created interface to the VM
	$vm = Add-AzureRmVMNetworkInterface -VM $vmConfig -NetworkInterfaceId $Using:vmNic.Id

	# Setting Operating System configurations
     	$vm = Set-AzureRmVMOperatingSystem -VM $vmConfig -Windows -ComputerName $Using:vmName -Credential $Using:LocalAdmin -ProvisionVMAgent -EnableAutoUpdate

     	# Setting properties for OS disk
	$vm = Set-AzureRmVMOSDisk -VM $vmConfig -Name $Using:osDisk -Windows -VhdUri $Using:osDiskUri -Caching ReadWrite -CreateOption FromImage -SourceImageUri $Using:vmImageUri
	# Creating the new VM
     	New-AzureRmVM -VM $vm -ResourceGroupName $Using:vmRGName -Location $Using:location


     # Set and enable LocalAdmin account 
     Set-AzureRmVMAccessExtension -ResourceGroupName $vmRGName -VMName $vmName -UserName $LocalAdmin.UserName -Password $LocalAdmin.GetNetworkCredential().Password -Name "Enable_LocalAdmin"

     # Join VM to domain   
     Set-AzureRmVMExtension -ResourceGroupName $vmRGName -VMName $vmName -Name "JoinADv1" -Publisher "Microsoft.Compute" -ExtensionType "JsonADDomainExtension" -TypeHandlerVersion "1.3" -Location $location -Settings @{ "Name" = $domain; "OUPath" = $OU; "User" = $DomainAdmin.UserName; "Restart" = "true"; "Options" = 3} -ProtectedSettings @{"Password" = $DomainAdmin.GetNetworkCredential().Password}


Note: Change $vmImageUri string in the above code to reflect your environment.

In order to run this Runbook, ensure it’s published on Azure. Then use the script below to activate the Runbook from your client machine – need to have AzureRm Powershell module installed to be able to run it.

# Login to Azure

# Select subscription
$select = Get-AzureRmSubscription | Out-GridView -Title "Select your Azure subscription" -OutputMode Single
Select-AzureRmSubscription -SubscriptionId $select.SubscriptionId

# Setting VM variables
$size = 'Standard_A2'
$domainName = "domain.local"
$vmOU = "OU=AzureOU,DC=domain,DC=local"
$vnet = 'vNet Name'
$vnetrg = 'vNet Resource Group Name'
$stgName = 'Storage Account Name'
$stgRG = 'Storage Account Resource Group Name'
$blobStgStr = ""
$loc = 'westeurope'

# Taking VM name input
$vm = [Microsoft.VisualBasic.Interaction]::InputBox("Enter VM Name", "VM Name", "VM Machine Name") 

# Get VM destination Resource Group
$rgname = Get-AzureRmResourceGroup | Select ResourcegroupName | Out-GridView -Title "Select destination resource Group" -OutputMode Single

# Get VM destination subnet information
$sub = Get-AzureRmVirtualNetwork -Name $vnet -ResourceGroupName $vnetrg | select -ExpandProperty Subnets |select Name, AddressPrefix, Id | Out-GridView -Title "Select VM subnet" -OutputMode Single

# Building a new VM network interface - this command wasn't recongnised to run as part of Azure runbook
[object] $nic = New-AzureRmNetworkInterface -Name $vm -ResourceGroupName $vnetrg -Location $loc -SubnetId $sub.Id -Force

# Forming parameters hash table 
$param = @{subId=$select.SubscriptionId; vmName=$vm; vmSize=$size; domain=$domainName; OU=$vmOU; vmRGName=$rgname.ResourceGroupName; vmNic=$nic; stgName=$stgName; stgRGName=$stgRG; stgBlobStr=$blobStgStr; location=$loc}

# Submitting VM configuration and starting the runbook
Start-AzureRmAutomationRunbook -Name AzureVMDomainJoinv1 -ResourceGroupName MRL-AzureAutomation-RG -AutomationAccountName DomainJoin -Parameters $param

Make sure you fill out all variables according to your environment. This script will only utilise what’s already created on Azure, like storage accounts, networks and subnets. If you want a new resource group created or a new network/subnet then pre-stage it on Azure first before you run this script.

Happy scripting ….. 🙂

, ,

Leave a comment

Error 20400 – VMM 2012 R2

Error (20400)

1 parallel subtasks failed during execution.

 Error (2605)

Unable to connect to the VMM database because of a general database failure.

SQL error code: 547

Recommended Action

Ensure that the SQL Server is running and configured correctly, then try the operation again.

We have received this error while removing a Hyper-v cluster out of VMM 2012 R2. Even trying to reinstall VMM agent fails manually. Trying both Remove-SCVMHost and Remove-SCVMHostCluster with -Force also failed miserably!

I have found a good article that takes you through these steps of removing hosts/cluster from the DB end, just make sure you have a backup before you start.

You can find the article here.

Leave a comment

Azure Point-To-Site VPN – certificates

Vorhängeschloss und Schlüssel 01Let me set the expectation here, I am not going in depth on how to setup an Azure VPN as it has been referenced in many articles which could take you step by step on hot to configure your VPN tunnel to Azure cloud.

My main concern here are methods available in generating those certificates used in establishing that type of VPN. I have used a self signed certificate which works well in most instances but that could always be replaced by a publicly signed certificate to avoid uploading various root trusted certificates to Azure vNet.

The most common way is to use makecert.exe which comes as part of Windows SDK

Open a command prompt:

makecert.exe -sky exchange -r -n “CN=RootCertName” -pe -a sha1 -len 2048 -ss My

makecert.exe -n “CN=ClientCertName” -pe -sky exchange -m 96 -ss my -in “RootCertName” -is my -a sha1

With the introduction of new version of Powershell 4 with Windows 8.1 and Windows Server 2012 R2, we can now generate the self-signed certificate using a simple command without installing Windows SDK and makecert.exe

Using Powershell, run the following line:

New-SelfSignedCertificate -CertStoreLocation cert:\LocalMachine\My -DnsName CertName -KeyLength 2048 -KeySpec KeyExchange

You can then export the .cer certificate which you can place in your Trusted Root Certification Authorities and upload to Azure.

Both processes work but you will need one of the OS’s highlighted above in order to use the Powershell command, you can install Windows Management Framework but that command wont be available to you on older versions of Windows.



Azure resource re-allocation and Resource Groups

Azure-logoInfrastcuture in the cloud (IaaS) is such an evolving topic from the architectual point of view. As services do evolve and more functionalities get added in order to enable the end user to untilise these services in best forms, complexities do start to add to it.

IaaS require a lot of initial planning to minimise any downtime required to re-allocate services/servers for production (Prod).

If breaking to Azure services started as a proof of concept (PoC) initially and changed suddenly to being the business critical service that your business can’t function without – without the necessary transitional planning then we are on the same page here.

Microsoft Azure does add a lot of value to the business and continuity of its business operations.

In this article I will go over Azure different resources and the way they could be organised for ease of management and billing. Billing is an important topic if you want to understand how your services are being utilised in the cloud or in order to bill each business unit if your business is using the charge back model.

If you have just started building your infrastructure on Azure, ensure your business units use Azure Resource Groups to group their services/servers and that could save you a lot of time in the long run.

The way to move resources between different resource groups are a complex ‘PowerShell driven process’. First you need to understand the limitiation of resource move:

  1. vNet’s can’t be moved
  2. Re-allocated Azure resources will retain their source region, even if your destination resource group is in a different region.
  3. You can’t move a single VM attached to a cloud service, the cloud service and all VM’s attached to it will have to move together.
  4. From experience, move storage accounts seperately. When I try to move a storage account with the rest of resources I get error (“One resource move request can contain resources of only 1 provider.”) :storage-err
  5. If you would like to migrate the VM to a new vNet then the VM needs to be deleted and reprovisioned on the vNet – the VM will down for that duration.
  6. If you would like to move the VM to a new storage account, then the downtime will be much greater depending how big the VHD files are and the region. I won’t talk much about this process, you will find it detailed here.

Now we will talk about the interesting part, the move and re-allocation process.

  1. Download the latest Azure Powershell module (We will be using the latest Azure Resource Management module) as illustrated here
  2. Login to your subscription using Login-AzureRmAccount
  3. Get the content of your source resource group on Azure: Get-AzureRmResource
  4. Feed the output to Move-AzureRmResource

I have written a short script to demonstrate this process (MS Azure Resource Group Management(MS Azure Resource Group Management), I have added comments necessary to each of the steps in the script so you should be able to customize it to your needs.


Leave a comment

Couldn’t open backup file handle while performing Exchange DB seed via Powershell


The error above is the outcome of running Udate-MailboxDatabaseCopyStatus -Identity DB_NAME -DeleteExistingFiles and the DB status went to Failed and Suspended. The reason is that the backup was kicked off and the handle for the DB was no longer available.

You could check the status of the backup on the DB by running Get-MailboxDatabaseCopyStatus -Identity DB_NAME | fl *backup*



Two ways to get over this, either to wait for the backup to finish or to reboot the server and stop the backup and that should fix the issue, the seeding process needs to start from scratch.

, ,

1 Comment

Soft Deleted Mailbox in Exchange 2010 (Continued)

In my previous post I have talked about what happens behind the scenes when you disconnect a mailbox via EMC. Soft deleted mailboxes stay on the system for the whole retention period (by default 30 days) hence they still utilise space within Exchange DB, if you are running on low disk space then this might become an issue.

Luckily there is a solution to this issue, using Remove-StoreMailbox command in Powershell, follow the solution in this MS article


Leave a comment