Track IP addresses consumption with Azure Application Insights  -  Part 2
Published Feb 28 2023 11:27 PM 2,826 Views
Senior Member



In part 1 we saw how to send a custom event telemetry to an Azure Application Insights instance through PowerShell.


We did track our Azure Virtual Network IP addresses consumption, we will now automate this tracking every 30 minutes through a Timer Trigger Azure Function App.


The Azure Function will be deployed through Bicep. Bicep is a domain-specific language (DSL) that uses declarative syntax to deploy Azure resources. It provides concise syntax, reliable type safety, and support for code reuse. According to Microsoft documentation Bicep offers the best authoring experience for your infrastructure-as-code solutions in Azure.






Azure account

Before you begin, you must have an Azure account with an active subscription. Create an account for free.


Code repository

Download the sample code repository, run the following command in your local terminal window:



git clone
cd bicep-function-app-virtual-network-monitoring



Review the Bicep files and create your environment


Bicep file to create the Azure Function App



@description('The name of the function app that you wish to create.')
param appName string = 'fnapp${uniqueString(resourceGroup().id)}'

@description('Storage Account type')
param storageAccountType string = 'Standard_LRS'

@description('Location for all resources.')
param location string = resourceGroup().location

@description('Location for Application Insights')
param appInsightsLocation string

@description('The language worker runtime to load in the function app.')
param runtime string = 'powershell'

var functionAppName = appName
var hostingPlanName = appName
var applicationInsightsName = appName
var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions'
var functionWorkerRuntime = runtime

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: storageAccountType
  kind: 'Storage'

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: applicationInsightsName
  location: appInsightsLocation
  kind: 'web'
  properties: {
    Application_Type: 'web'
    Request_Source: 'rest'

resource hostingPlan 'Microsoft.Web/serverfarms@2021-03-01' = {
  name: hostingPlanName
  location: location
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
  properties: {}

resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp'
  identity: {
    type: 'SystemAssigned'
  properties: {
    siteConfig: {
      appSettings: [
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment()};AccountKey=${storageAccount.listKeys().keys[0].value}'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment()};AccountKey=${storageAccount.listKeys().keys[0].value}'
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower(functionAppName)
          value: '~4'
          value: functionWorkerRuntime
      ftpsState: 'FtpsOnly'
      minTlsVersion: '1.2'
    httpsOnly: true

output functionAppName string =
output principalId string = functionApp.identity.principalId



The following four Azure resources are created by this Bicep file:



Deploy the Bicep file using Azure CLI.



#create the resource group
az group create --name $resourceGroupName --location $location

#create the function app
az deployment group create                                  \
                --name function_app                         \
                --resource-group $resourceGroupName         \
                --template-file function_app.bicep          \
                --parameters appInsightsLocation=$location



When the deployment finishes, you should see a message indicating the deployment succeeded.



Bicep file to assign the Reader privilege to the Managed Identity of our Function App


@description('The principal Id of the object that will be granted the needed role.')
param principalId string

@description('This is the built-in Reader role. See')
resource readerRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  scope: subscription()
  name: 'acdd72a7-3385-48ef-bd42-f606fba81ae7'

targetScope = 'subscription'

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(, principalId,
  properties: {
    principalId: principalId
    principalType: 'ServicePrincipal'




The following Azure resource is created by this Bicep file:


Deploy the Bicep file using Azure CLI.


#assign the azure built-in role to the function app
principalId=$(az deployment group show                                      \
                            --resource-group $resourceGroupName             \
                            --name function_app                             \
                            --query properties.outputs.principalId.value    \
                            --output tsv                                    )

az deployment sub create                                    \
                --location $location                        \
                --template-file role_assignment.bicep       \
                --parameters principalId=$principalId



When the deployment finishes, you should see a message indicating the deployment succeeded.


Use Azure CLI to validate the deployment.


az resource list --resource-group $resourceGroupName



Perform a manual git deployment to the Azure Function App

Deploy the PowerShell code to the Function App using Azure CLI.


functionAppName=$(az deployment group show                                      \
                            --resource-group $resourceGroupName                 \
                            --name function_app                                 \
                            --query properties.outputs.functionAppName.value    \
                            --output tsv                                        )

az functionapp deployment source config             \
                --branch main                       \
                --manual-integration                \
                --name $functionAppName             \
                --resource-group $resourceGroupName \



View the audit result Azure Application Insights

You will then be able to monitor the Function App logs being inserted every 30 minutes by navigating to you Function App > Logs as illustrated in the following screenshot.





The query:


| where name == "dld_telemetry_azure_vnets_counter"
| extend SubnetAddressPrefix = customDimensions.SubnetAddressPrefix
| extend SubnetIPaddressesCount = toreal(customDimensions.SubnetIPaddressesCount)
| extend SubnetIPaddressesLimit = toreal(customDimensions.SubnetIPaddressesLimit)
| extend SubnetName = tostring(customDimensions.SubnetName)
| project timestamp, SubnetName, SubnetAddressPrefix, SubnetIPaddressesCount, SubnetIPaddressesLimit
| summarize max(SubnetIPaddressesCount) by timestamp, SubnetName
| render timechart



Clean up resources


az group delete --name $resourceGroupName




We saw in part 1 how to send a custom event telemetry to an Azure Application Insights instance through PowerShell, we did see in this article how to automate our audit, what about building an Azure Workbook in part 3?


Note: the complete source code we saw in this article is available here


See You in the Cloud


Version history
Last update:
‎Feb 09 2023 04:50 AM
Updated by: