Skip to main content

IPv6 in Microsoft Azure

· 13 min read

With more support for IPv6 being added to native Azure products, its time to take a closer look into IPv6 and its use within Azure.

The deployment of IPv6, the latest version of the Internet Protocol (IP), has been in progress since the mid-2000s. IPv6 was designed as the successor protocol for IPv4 with an expanded addressing space. IPv4, which has been in use since 1982, is in the final stages of exhausting its unallocated address space but still carries most Internet traffic.

Azure Bicep - Principal does not exist in directory

· 2 min read

Recently, I was deploying an User Assigned Managed identity, and assigning the managed identity a role assignment with Azure Bicep, and ran into an issue, where the assignment would fail, but then after a rerun would work.

Principal e892476361114c90be141d9bf20cc94b does not exist in the directory 73160ae1-aa4a-48b5-a424-d5e43d808f53. Check that you have the correct principal ID. If you are creating this principal and then immediately assigning a role, this error might be related to a replication delay. In this case, set the role assignment principalType property to a value, such as ServicePrincipal, User, or Group. See


What was happening, was that the User Assigned Identity was created, and immediately after the role assignment was attempted, leaving no time for the role assignment API to be aware that the User Assigned Managed identity existed, even with a hard coded dependson!

The fix was to Set the: principalType into the Bicep, as ServicePrincipal, making sure that the Azure platform can wait for the replication to complete, before trying the role assignment.

The principalType property specifies whether the principal is a user, a group, or a service principal. Managed identities are a form of service principal.

resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: azUserAssignedManagedIdentity
location: location

resource uamiassignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, 'contributor')
properties: {
principalType: 'ServicePrincipal'
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor
scope: resourceGroup()

Microsoft Azure Management with PowerShell - Introduction

· 8 min read

To see a video of these commands in action, take a look at the following YouTube-hosted video: Microsoft Azure Management with PowerShell - Introduction


PowerShell is a powerful scripting and automation framework developed by Microsoft. It is designed for task automation and configuration management and is particularly useful for managing and automating Microsoft Windows environments. PowerShell uses a command-line interface with a scriptable approach, and it's built on the .NET Framework.

PowerShell and Microsoft Azure

When it comes to Microsoft Azure, PowerShell provides a robust set of cmdlets (pronounced "command-lets") that enable you to interact with and manage Azure resources, making it a valuable tool for working with Azure services.

When you run a PowerShell cmdlet to, for example, create a virtual machine or retrieve information about an Azure resource, the cmdlet translates your request into an HTTP request to the relevant Azure REST API endpoint.

There is an assumption, that you have access to an Azure environment, and the ability to create resources, within that environment.

Microsoft Azure Management with PowerShell

First up, let's verify the version of PowerShell we have, open a Powershell terminal and run:


A supported version of PowerShell version 7 or higher is the recommended version of PowerShell for use with the Az PowerShell module on all platforms including Windows, Linux, and macOS.

The Az PowerShell module is preinstalled in Azure Cloud Shell and in Docker images.

Setting up your Azure environment for PowerShell

First thigs first, lets installed the Azure (Azure Az PowerShell module)modules.

# Install Azure Modules
# The Set-PSRepository cmdlet is used to set values for a registered repository.
# The Install-Module cmdlet is used to download one or more modules from an online gallery and installs them on the local computer. In this case, the command is installing the Az module, which provides cmdlets for managing Azure resources.
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
Install-Module Az

If you don't have local administrator rights, you can install it into your user profile like below:

# Install Azure Module as Current User (as opposed to System)
# '-Scope CurrentUser` specifies that the module should be installed only for the current user. If you don't specify a scope, the default is `AllUsers`, which requires administrator permissions.

Install-Module -Name Az -Repository PSGallery -Scope CurrentUser

You can install a specific version of the Az module by specifying RequiredVersion, like below:

# Install specific version of Azure Modules

Install-Module -Name Az -RequiredVersion 7.1.0

You will find that the Azure powershell cmdlets will constantly get updated, to resolve bugs, offer new functionality, to update the modules to the ltest you can use:

# Update Azure Module
# The command Get-InstalledModule -Name Az* | Update-Module is used to update all installed PowerShell modules that start with "Az".
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
Get-InstalledModule -Name Az* | Update-Module

Az is a collection of different cmdlets, across multiple Azure resource types, to view a list of avaliable commands you use 'Get-Command', like below:

# Gets Az Commands
# Note: Will take a while for all the cmdlets to list.
Get-Command -Noun Az*

Getting started with Azure PowerShell module

Lets connect to Microsoft Azure

# Connect to Azure - Interactive will prompt for credentials

If your wanting to connect to Azure, from a device that doesn't supoport the credential prompt, like Azure Cloudshell you can connect using another device, using a device code:

# Connect to Azure
Connect-AzAccount -UseDeviceAuthentication

If you have a Service principal, you can use this to authenticate, commonly used for automation scripts, Azure DevOps agents and GitHub runners.

# Connect to Azure using Service Principal authentication
$SecurePassword = ConvertTo-SecureString -String "Password123!" -AsPlainText -Force
$TenantId = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyy'
$ApplicationId = 'zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzz'
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ApplicationId, $SecurePassword
Connect-AzAccount -ServicePrincipal -TenantId $TenantId -Credential $Credential

Once, connected - its time to check what Azure subscriptions you can use.

# Get Azure Subscriptions

Once you have selected the right Azure subscription to connect to, you can set your Subscription context (modify/delete resources). Add your subscription ID, from the earlier step in between ''.

# Select Azure Subscription
$subid = ''
Set-AzContext -SubscriptionId $subid

Now you have connected to your, Azure subscription, it is time to get your Azure resources and Resource Groups

# Get Azure resource groups and resources
Get-AzResourceGroup | Format-Table
Get-AzResource | Format-Table
# Get Azure resource
# Get Azure resource by ResourceType
Get-AzResource | Where-Object {$_.ResourceType -eq 'Microsoft.Network/virtualNetworks'}
# Sort Azure resource by Name and Resource Group
Get-AzResource | Where-Object {$_.ResourceType -eq 'Microsoft.Storage/storageAccounts'} | Sort-Object Name
Get-AzResource | Sort-Object ResourceGroupName
# Working with Variables

# Working with variables and data types in PowerShell
$resourceType = 'Microsoft.Network/virtualNetworks'
Get-AzResource | Where-Object {$_.ResourceType -eq $resourceType}
# Using PowerShell operators for comparisons and calculations

$resources = Get-AzResource
$count = $resources.Count
Write-Host "You have $count resources in your Azure subscription."
# Scripting constructs: loops and conditional statements
$resources = Get-AzResource

foreach ($resource in $resources) {
if ($resource.ResourceType -eq 'Microsoft.Network/virtualNetworks') {
Write-Host "Found a virtual network: $($resource.Name)"
Write-Host "This virtual network is in $($resource.ResourceGroupName)" -ForegroundColor Green
# Scripting constructs: loops and conditional statements
$subscriptions = Get-AzSubscription

foreach ($subscription in $subscriptions) {
$resource = Get-AzResource | Where-Object {$_.ResourceType -eq 'Microsoft.Network/virtualNetworks'}

if ($resource.ResourceType -eq 'Microsoft.Network/virtualNetworks') {
Write-Host "Found a virtual network: $($resource.Name)" -BackgroundColor Black -ForegroundColor White
Write-Host "This virtual network is in $($resource.ResourceGroupName)" -ForegroundColor Green
Write-Host "This Virtual Network is in $($subscription.Name)" -ForegroundColor Green
# Error handling in PowerShell
try {
Get-AzResource -ResourceGroupName "NonexistentResourceGroup" -ErrorAction Stop
} catch {
Write-Host "An error occurred: $_. Make sure you have selected the right Resource Group" -ForegroundColor Red

Resource Creation

# Import Module
Import-Module Az -Verbose
#Create Azure Resource Group
New-AzResourceGroup -Name "MyResourceGroup" -Location "West US"
# Get Regions
Get-AzLocation | Select-Object -First 1
Get-AzLocation | Select-Object DisplayName, Location, PhysicalLocation, GeographyGroup | Format-Table
ate Azure Resource Group
$region = 'AustraliaEast'
New-AzResourceGroup -Name "MyResourceGroup$region" -Location $region
# Create a storage account
$uniqueId = [guid]::NewGuid().ToString().Substring(0,4)
$region = 'AustraliaEast'
$ResourceGroupName = "MyResourceGroup$region"
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name "mystgacc$uniqueId" -Location $region -SkuName Standard_LRS -AllowBlobPublicAccess $false -verbose
#Remove Azure Storage account
$region = 'AustraliaEast'
$ResourceGroupName = $ResourceGroupName
Remove-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name "mystgacc$uniqueId" -Force -verbose
Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name "mystgacc$uniqueId" -verbose
# Create an Azure Virtual Network
$region = 'AustraliaEast'
$ResourceGroupName = 'network-prod-rg'
$VNetname = 'vnet-prod'
$subnetname = 'infraservers'
$subnetAddressPrefix = ''

# Create a resource group
$ResourceGroup = Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue

if ($null -eq $ResourceGroup)
Write-Host "Creating Resource Group $ResourceGroupName in $region" -ForegroundColor Yellow
$ResourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $region -Force
Write-Host "Resource Group $ResourceGroupName already exists in $region" -ForegroundColor Green

# Create a virtual network
$AzVNET = New-AzVirtualNetwork -ResourceGroupName $ResourceGroupName -Name $VNetname -AddressPrefix '' -Location $region

# Create a subnet
$subnetConfig = Add-AzVirtualNetworkSubnetConfig -Name $subnetname -AddressPrefix $subnetAddressPrefix -VirtualNetwork $AzVNET
# Get full object output
# Alias (This is a pipeline to the Format-List cmdlet (fl is an alias for Format-List). It formats the output as a list of properties for each object. This can make it easier to read the details of the virtual network.)

Get-AzVirtualNetwork -ResourceGroupName $ResourceGroupName -Name $VNetname # | fl
# Alias

Get-Alias | Select-Object -First 2

$configData = @{
ResourceGroupName = "MyResourceGroup"
Location = "West US"
StorageAccountName = "stgacctest100"

try {
New-AzStorageAccount -ResourceGroupName $configData.ResourceGroupName -Name $configData.StorageAccountName -Location $configData.Location -SkuName Standard_LRS
} catch {
Write-Error "Failed to create storage account: $_"
#splat as parameters

$configData = @{
"ResourceGroupName" = "MyResourceGroup"
"Location" = "West US"
"StorageAccountName" = "stgacctest100"
"SkuName" = "Standard_LRS"


try {
New-AzStorageAccount @configData
} catch {
Write-Error "Failed to create storage account: $_"
# Tags
$ResourceGroupName = 'TagTestRG'
New-AzResourceGroup -Name $ResourceGroupName -Location 'AustraliaEast'
Set-AzResourceGroup -Name $ResourceGroupName -Tag @{ Department = "Finance"; Project = "Q1" }
# Get Tag Resource Group
$ResourceGroupName = 'TagTestRG'
(Get-AzResourceGroup -Name $ResourceGroupName).Tags
$ResourceGroupName = 'TagTestRG'
$tags = (Get-AzResourceGroup -Name $ResourceGroupName).Tags
Set-AzResourceGroup -Name $ResourceGroupName -Tag $tags

Private Endpoint traffic not appearing in Azure Firewall

· 3 min read

You may have a situation where you have implemented Private endpoints and the traffic from on-premises to those Private Endpoints, either doesn't work, even though on-premises firewalls say otherwise, or is working, but doesn't appear in the Azure Firewall.

I had this recently with Azure Arc, where the endpoints failed to connect once a site-to-site VPN connection (which was working) was replaced with an expressroute connection, but going through the Azure Firewall logs, was unable to see any 443 traffic for Arc, hitting the Firewall even when the connection was working.

Private Endpoint traffic not appearing in Azure Firewall

Traffic flow: Onpremises -- (ER Circuit) -- ER gateway -- Secured hub Azure Firewall -- (Vnet Connection) -- PE (Private Endpoint)

The issue was related to how private endpoint traffic is routed differently.

If the traffic has reached the Expressroute gateway from on-premises, with routing intent, normal traffic will be forced to the AzFW first before reaching its destination, as you would think and expect.

However, for the private endpoint scenario, once a Private Endpoint is deployed to any VNET, there will be an automatic system route with the PE IP and prefix /32 installed on all of the linked NICs. The next hop for this route will be InterfaceEndpoint. This route will allow the traffic to go directly to the PE, bypassing the routing intent and other user-defined routes that are larger than /32. The /32 route propagates to these areas: Any VPN or ExpressRoute connection to an on-premises system.

See: Considerations for Hub and Spoke topology.

In an Azure Virtual Wide Area Network (VWAN), you could see this route in the virtual hub effective routes and which gets propagated to the expressroute gateway.

My traffic from on-premises to the Azure Arc went directly to the private endpoints (bypassing the Azure Firewall). Still, the route back via the Azure Firewall was completely different, leading to asymmetric routing (a packet traverses from a source to a destination in one path and takes a different path when it returns to the source).

To resolve this, we need to enable network security policies for User-Defined Routes on the subnet of the private endpoint(s):

Azure Portal - Private Endpoint - Routes

Once enabled, you should see the traffic connect and flow through your Azure Firewall almost immediately.