Azure IoT Raspberry PI Temperature Sensor

Internet of Things refers to a collection of physical devices that are connected to the internet. Typically for collecting data, sharing data, controlling and monitoring devices. Microsoft has developed a number of managed IoT services that provide users with an endpoint to send data, manage and output data to other services.

This blog will be specifically covering the Azure IoT Hub, which is a managed service that acts as a central message hub for bi-directional communication between IoT application and devices it manages.

Raspberry Pi IoT Sensor Demo

For the purpose of a demo, I have created a simple application in Python that sends a message of the current temperature and humidity to an Azure IoT Hub. This simple lab requires the following:

Hardware Setup

The sensor I am using is a WaveShare DHT11 3 pin sensor, the pin layout is as follows:

Pin NumbersSymbolDescriptionPi Pin
1DOUTCommunication Port11 (GPIO17)
2GRNGround6 or 9
3VCCPositive Power Supply (3.3v-5.5v)1

Software Setup (Raspberry PI)

To start, update the package list and install the following python libraries:

sudo apt-get update
sudo apt-get install build-essential python-dev

Clone the Adafruit Library from their repository:

git clone
cd Adafruit_Python_DHT

Then install the Adafruit library for Python 2 and Python 3:

sudo python install
sudo python3 install

Now test the sensor is working correctly, by running the below command:

cd examples
python 11 17

This should output Temp={Temperature reading} Humidity={Humidity Reading}

Once the sensor reading has been verified, we will require additional Python Libraries for the Azure IoT Hub:

sudo pip3 install azure-iot-device  
sudo pip3 install azure-iot-hub  
sudo pip3 install azure-iothub-service-client  
sudo pip3 install azure-iothub-device-client  

Azure IoT Hub Deployment

Within Azure CLI run the following commands:

az extension add --name azure-iot

az group create -n IOTHUBRG -l westeurope

az iot hub create --resource-group IOTHUBRG --name raspberrypiblogtemp --location westeurope

az iot hub device-identity create -n raspberrypiblogtemp -d RaspberryPi --ee

az iot hub device-identity connection-string show --hub-name raspberrypiblogtemp --device-id RaspberryPi

Make a note of the connection string (output of last command).

Sensor Application

On the Raspberry Pi, Clone my blog repo:

git clone

cd blog

cd IoT

cd temperature_sensor/


Modify the CONNECTION_STRING = “”, with the Connection String from the previous step:

import random  
import Adafruit_DHT
import time
from azure.iot.device import IoTHubDeviceClient, Message  
sensor = Adafruit_DHT.DHT11
pin = 17

MSG = '{{"temperature": {temperature},"humidity": {humidity}}}'

while True:
    humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
    def iothub_client_init():  
        client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING)  
        return client  
    def iothub_client_telemetry_sample_run():  
            client = iothub_client_init()  
            print ( "Sending data to IoT Hub, press Ctrl-C to exit" )  
            while True:  
                msg_txt_formatted = MSG.format(temperature=temperature, humidity=humidity)  
                message = Message(msg_txt_formatted)  
                print( "Sending message: {}".format(message) )  
                print ( "Message successfully sent" )  
        except KeyboardInterrupt:  
            print ( "IoTHubClient stopped" )  
    if __name__ == '__main__':  
        print ( "Press Ctrl-C to exit" )  

Exit and save from nano, then run the following command:


Example output:

Run the following command to monitor the messages being received by the IoT Hub:
az iot hub monitor-events --hub-name raspberrypiblogtemp --device-id RaspberryPi

I hope you find this introduction to the world IoT devices and Azure IoT services informative. If you have any questions or ideas for any future IoT posts, please reach out in the comments.

AZ-700 Designing and Implementing Microsoft Azure Networking Solutions Study Guide

I have recently taken the AZ-700 (Designing and Implementing Microsoft Azure Networking Solutions Beta). and wanted to share some of the resources I used preparing for this exam.

Note – This exam was in beta at the time of writing this blog.

Exam Audience Profile

Candidates for this exam should have subject matter expertise in planning, implementing, and
maintaining Azure networking solutions, including hybrid networking, connectivity, routing,
security, and private access to Azure services.
Responsibilities for the Azure Network Engineer include recommending, planning, and
implementing Azure networking solutions. Professionals in this role manage the solution for
performance, resiliency, scale, and security. They deploy networking solutions by using the Azure Portal and other methods, including PowerShell, Azure Command-Line Interface (CLI), and Azure Resource Manager templates (ARM templates).
The Azure Network Engineer works with solution architects, cloud administrators, security
engineers, application developers, and DevOps engineers to deliver Azure solutions.
Candidates for this exam should have expert Azure administration skills, in addition to extensive experience and knowledge of networking, hybrid connections, and network security.

Skills Measured

For this exam, you will be measured on the below subjects:

  • Design, Implement, and Manage Hybrid Networking (10% to 15%)
  • Design and Implement Core Networking Infrastructure (20% to 25%)
  • Design and Implement Routing (25% to 30%)
  • Secure and Monitor Networks (15% to 20%)
  • Design and Implement Private Access to Azure Services (10% to 15%)


Microsoft Learn

My first recommendation is to complete the free Microsoft Learning Path “AZ-700 Designing and Implementing Microsoft Azure Networking Solutions“. This path will guide you through the following subjects:

  • Introduction to Azure virtual networks
  • Design and implement hybrid networking
  • Design and implement Azure ExpressRoute
  • Load balance non-HTTP(S) traffic in Azure
  • Load balance HTTP(S) traffic in Azure
  • Design and implement network security
  • Design and implement private access to Azure Services
  • Design and implement network monitoring

Microsoft Documentation

Another brilliant resource is the Microsoft Docs. I have compiled a list of links that are relevant to the content within this exam:

Design, Implement, and Manage Hybrid Networking

Design, implement, and manage a site-to-site VPN connection

  • design a site-to-site VPN connection for high availability

  • select an appropriate virtual network (VNet) gateway SKU

  • identify when to use policy-based VPN versus route-based VPN

  • create and configure a local network gateway

  • create and configure an IPsec/IKE policy

  • create and configure a virtual network gateway

  • diagnose and resolve VPN gateway connectivity issues

Design, implement, and manage a point-to-site VPN connection

  • select an appropriate virtual network gateway SKU

  • plan and configure RADIUS authentication

  • plan and configure certificate-based authentication

  • plan and configure OpenVPN authentication

  • plan and configure Azure Active Directory (Azure AD) authentication

  • implement a VPN client configuration file

  • diagnose and resolve client-side and authentication issues

Design, implement, and manage Azure ExpressRoute

  • choose between provider and direct model (ExpressRoute Direct)

  • design and implement Azure cross-region connectivity between multiple ExpressRoute locations

  • select an appropriate ExpressRoute SKU and tier

  • design and implement ExpressRoute Global Reach

  • design and implement ExpressRoute FastPath

  • choose between private peering only, Microsoft peering only, or both

  • configure private peering

  • configure Microsoft peering

  • create and configure an ExpressRoute gateway

  • connect a virtual network to an ExpressRoute circuit

  • recommend a route advertisement configuration

  • configure encryption over ExpressRoute

  • implement Bidirectional Forwarding Detection

  • diagnose and resolve ExpressRoute connection issues

Design and Implement Core Networking Infrastructure

Design and implement private IP addressing for VNets

  • create a VNet

  • plan and configure subnetting for services, including VNet gateways, private endpoints

  • firewalls, application gateways, and VNet-integrated platform services

  • plan and configure subnet delegation

Design and implement name resolution

  • design public DNS zones

  • design private DNS zones

  • design name resolution inside a VNet

  • configure a public or private DNS zone

  • link a private DNS zone to a VNet

Design and implement cross-VNet connectivity

  • design service chaining, including gateway transit

  • design VPN connectivity between VNets

  • implement VNet peering

Design and implement an Azure Virtual WAN architecture

  • design an Azure Virtual WAN architecture, including selecting SKUs and services

  • connect a VNet gateway to Azure Virtual WAN

  • create a hub in Virtual WAN

  • create a network virtual appliance (NVA) in a virtual hub

  • configure virtual hub routing

  • create a connection unit

Design and Implement Routing

Design, implement, and manage VNet routing

  • design and implement user-defined routes (UDRs)

  • associate a route table with a subnet

  • configure forced tunneling

  • diagnose and resolve routing issues

Design and implement an Azure Load Balancer

  • choose an Azure Load Balancer SKU (Basic versus Standard)

  • choose between public and internal

  • create and configure an Azure Load Balancer (including cross-region)

  • implement a load balancing rule

  • create and configure inbound NAT rules

  • create explicit outbound rules for a load balancer

Design and implement Azure Application Gateway

  • recommend Azure Application Gateway deployment options

  • choose between manual and autoscale

  • create a back-end pool

  • configure health probes

  • configure listeners

  • configure routing rules

  • configure HTTP settings

  • configure Transport Layer Security (TLS)

  • configure rewrite policies

Implement Azure Front Door

  • choose an Azure Front Door SKU

  • configure health probes, including customization of HTTP response codes

  • configure SSL termination and end-to-end SSL encryption

  • configure multisite listeners

  • configure back-end targets

  • configure routing rules, including redirection rules

Implement an Azure Traffic Manager profile

  • configure a routing method (mode)

  • configure endpoints

  • create HTTP settings

Design and implement an Azure Virtual Network NAT

  • choose when to use a Virtual Network NAT

  • allocate public IP or public IP prefixes for a NAT gateway

  • associate a Virtual Network NAT with a subnet

  • other useful links

Secure and Monitor Networks

Design, implement, and manage an Azure Firewall deployment

  • design an Azure Firewall deployment

  • create and implement an Azure Firewall deployment

  • configure Azure Firewall rules

  • create and implement Azure Firewall Manager policies

  • create a secure hub by deploying Azure Firewall inside an Azure Virtual WAN hub

  • integrate an Azure Virtual WAN hub with a third-party NVA

Implement and manage network security groups (NSGs)

  • create an NSG

  • associate an NSG to a resource

  • create an application security group (ASG)

  • associate an ASG to a NIC

  • create and configure NSG rules

  • interpret NSG flow logs

  • validate NSG flow rules

  • verify IP flow

Implement a Web Application Firewall (WAF) deployment

  • configure detection or prevention mode

  • configure rule sets for Azure Front Door, including Microsoft managed and user defined

  • configure rule sets for Application Gateway, including Microsoft managed and user defined

  • implement a WAF policy

  • associate a WAF policy

Monitor networks

  • configure network health alerts and logging by using Azure Monitor

  • create and configure a Connection Monitor instance

  • configure and use Traffic Analytics

  • configure NSG flow logs

  • enable and configure diagnostic logging

  • configure Azure Network Watcher

Design and Implement Private Access to Azure Services

Design and implement Azure Private Link service and Azure Private Endpoint

  • create a Private Link service

  • plan private endpoints

  • create private endpoints

configure access to private endpoints

  • integrate Private Link with DNS

  • integrate a Private Link service with on-premises clients

Design and implement service endpoints

  • create service endpoints

  • configure service endpoint policies

  • configure service tags

  • configure access to service endpoints

Configure VNet integration for dedicated platform as a service (PaaS) services

  • configure App Service for regional VNet integration

  • configure Azure Kubernetes Service (AKS) for regional VNet integration

  • configure clients to access App Service Environment


I would also recommend completing the AZ-700 labs. These will require an active Azure Subscription. If you don’t already have a test/dev subscription, you can activate a trail subscription here:

AZ-700-Designing-and-Implementing-Microsoft-Azure-Networking-Solutions (

John Savill- Youtube

John has produced a helpful exam-cram video for AZ-700, which covers all the topics within the exam. Additionally, he has deep-dive sessions on individual Azure services covered in the AZ-700 exam. If you haven’t already, I would highly recommend subscribing and supporting John’s channel.

AZ-700 Study Playlist:

I hope this exam guide for AZ-700 Designing and Implementing Microsoft Azure Networking Solutions has been helpful. If you feel I have missed anything in this blog post, please do reach out. Your feedback would be greatly appreciated.

Azure Functions + Private Certificates

While implementing Azure Functions running on App Service Environment I came across an error “SSL Connection could not be established”. This issue occurred when performing a HTTP request from the Azure Function  to another internal service which was utilising private certificates. As the certificate has been created internally and the Azure Function is a Microsoft managed PaaS service which is outside of the domain. Although not widely documented, this approach is actually supported.


Below is a simplified architecture of the Function App:

Certificate Revocation List (CRL)

After discussing this with Microsoft, the approach is only supported if the CRL distribution point has been implemented as http endpoint. If distribution point is implemented as a LDAP endpoint then this is not supported. However, I cannot find this documented anywhere publicly.

Firstly, we must identity if the CRL HTTP endpoint is reachable from the Azure Function. If you don’t have the CRL endpoint to hand this can be pulled from the certificate properties under CRL Distribution Points:

Ref, Example Google Public Certificate

 The CRL must be reachable from the Function App. To confirm this, I used the Kudu console from the App Service Environment and ran the following PowerShell command:

Invoke-RestMethod -Uri ""

If HTTP 400 errors are returned then the CRL is not reachable and this will need to be resolved first.

The Resolution

Once the above has been validated, we now need to obtain a copy of the private root CA certificate (.CER):

Ref, Example Google Public Certificate

Navigate to the Azure Portal and select the Azure Function then select TLS/SSL Settings Blade:

Select Upload Certificate, Local Machine provide a name and select the certificate. Finally, click upload:

Make a note of the certificate thumbprint and navigate to the Configuration blade:

Add a new Application Setting with the following name WEBSITE_LOAD_ROOT_CERTIFICATES and paste the Thumbprint as the value, then click Okay, then Save. Warning this will restart the Azure Function.

The Function should now be able to reach the internal service.

Azure Bicep

What is Azure Bicep

Azure Bicep is a new Domain Specific Language (DSL) for deploying Azure resources. It has clearer syntax which makes it easier for reading and writing, than the current alternative JSON ARM templates. Bicep is a transparent abstraction over JSON ARM templates, treating ARM as a Intermediate Language (IL).

Why use Azure Bicep

  • Simpler syntax for easier reading and writing.
  • Doesn’t require any updates to the underlying platform when a new type or apiversion is introduced.
  • Increased template validation with the introduction of a compiler.
  • Better for copy and pasting as variables, resources and outputs can be declared anywhere.
  • Automatic dependency management, in some deployment scenarios dependsOn will be added to the ARM template.

Current Limitations

  • No support for the copy or condition property [#185#186]
  • No explicit support for deployments across scopes (though this can be done by using the Microsoft.Resources/deployments resource and using the templateLink or template property to insert the full ARM template) [#187]
    • Bicep assumes you are deploying to a resource group, though the generated template can be deployed to any scope
  • Single line object and arrays (i.e. ['a', 'b', 'c']) are not yet supported
  • You still need to deploy the compiled template yourself, though we plan to build native support for bicep into the powershell Az deployment cmdlets and az cli deployment commands
  • No IntelliSense whatsoever [#269]
  • Minimal resource schema validation. Other than basic validations like correct resource type structure and requiring a name, you will not get errors for missing or incorrect properties in a resource declaration
  • No support for string interpolation in property names [#267]
    • From what we know, this only affects using managed identities for resources. You can still include a hardcoded managed identity resource ID (i.e. '/subscriptions/.../resourceGroups/.../providers/Microsoft.ManagedIdentity/...': {})
  • Bicep is currently not covered by Azure support plans as it is still in early development stages. Expect Bicep to be covered by all support plans starting on the 0.3 version.

Reference Sept 2020

Installing Azure Bicep


# Create the install folder
$installPath = "$env:USERPROFILE\.bicep"
$installDir = New-Item -ItemType Directory -Path $installPath -Force
$installDir.Attributes += 'Hidden'
# Fetch the latest Bicep CLI binary
(New-Object Net.WebClient).DownloadFile("", "$installPath\bicep.exe")
# Add bicep to your PATH
$currentPath = (Get-Item -path "HKCU:\Environment" ).GetValue('Path', '', 'DoNotExpandEnvironmentNames')
if (-not $currentPath.Contains("%USERPROFILE%\.bicep")) { setx PATH ($currentPath + ";%USERPROFILE%\.bicep") }
if (-not $env:path.Contains($installPath)) { $env:path += ";$installPath" }
# Verify you can now access the 'bicep' command.
bicep --help
# Done!


# Fetch the latest Bicep CLI binary
curl -Lo bicep
# Mark it as executable
chmod +x ./bicep
# Add Gatekeeper exception (requires admin)
sudo spctl --add ./bicep
# Add bicep to your PATH (requires admin)
sudo mv ./bicep /usr/local/bin/bicep
# Verify you can now access the 'bicep' command
bicep --help
# Done!


# Fetch the latest Bicep CLI binary
curl -Lo bicep
# Mark it as executable
chmod +x ./bicep
# Add bicep to your PATH (requires admin)
sudo mv ./bicep /usr/local/bin/bicep
# Verify you can now access the 'bicep' command
bicep --help
# Done!

Installing VSCode Extension

The Bicep extension isn’t currently in the Visual Studio Code Extension marketplace. Download the following file:

Open VScode and select Extensions then .... . Select install from VSIX, then select the above downloaded file.

Azure Bicep Breakdown

  • param – is used to declare parameters within the template. Unlike ARM this can be declared anywhere throughout the template.
  • var – is used for declaring variables. Similar to parameters these can be declared anywhere throughout the template.
  • resource – a manageable item that is available through Azure. This declares the block of code which defines the resource and its deployment properties.
  • symbolic-name – a unique name that can be referenced throughout the rest of the template.
  • type – the type of resource you wish to deploy for example, Microsoft.Storage/storageAccounts
  • API Version – the version of the REST API for the deployment. 

Functions and Expressions

Azure Bicep supports the same functions and expressions as ARM templates.

Bicep Function Example

// Set parameter to Resource Id for existing Web App in Azure
param webAppResourceId string = resourceId('Microsoft.Web/sites', 'b59webapp')

// Set variable to default location for the Resource Group deployed to
var location = resourceGroup().location

// Set output variable to uppercase of 'storageAccountName' value
output upperName string = toUpper(storageAccountName)

String Interpolation

The below is the equivalent to the concat() function within ARM templates:

param namePrefix string = 'unique'

var storageAccountName = '${namePrefix}storage001'

Symbolic Name

Symbolic Name is separate to the Azure resource name and is used as a reference to a resource within Bicep, exampled below:

param location string = resourceGroup().location
param namePrefix string = 'stg'

param globalRedundancy bool = true // defaults to true, but can be overridden

var storageAccountName = '${namePrefix}${uniqueString(resourceGroup().id)}'

resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' = {
    name: storageAccountName
    location: location
    kind: 'Storage'
    sku: {
        name: globalRedundancy ? 'Standard_GRS' : 'Standard_LRS' // if true --> GRS, else --> LRS

output storageId string =
output computedStorageName string =


Example of Storage Account deployment using Azure Bicep:

resource mystorage 'Microsoft.Storage/storageAccounts@2019-06-01' = {
  name: 'bicepstorage2063'   // Globally unique storage account name
  location: 'northcentralus' // Azure Region
  kind: 'Storage'
  sku: {
    name: 'Standard_LRS'
bicep build .\main.bicep

New-AzResourceGroup -Name Bicep-RG -Location northcentralus

New-AzResourceGroupDeployment -Name bicep -ResourceGroupName Bicep-RG -TemplateFile .\main.json

Wrap Up

Currently Azure Bicep is in preview so its not recommended for production. However, even within early stages of its development Bicep is proving to be easier to read and write over current alternatives. Microsoft is looking for feedback to help shape this product as it develops.

Azure DevOps + Ansible Configuration Management

What is Ansible?

Ansible is an open-source configuration management tool maintained by Red Hat. Ansible enables you to define server configuration as Infrastructure as Code, which within the Ansible world is known as Playbooks and is written in YAML. Ansible is completely agentless therefore, it operates over SSH (Linux) or WINRM (Windows).

What is Azure DevOps?

Azure DevOps is the evolution of Visual Studio Team Services, bringing Cloud hosted SaaS platform which continually improves. Azure DevOps is Cloud agnostic and integrates into most market-leading tooling.

Azure DevOps + Ansible

The below section is a technical guide on how to integrate Ansible and Azure DevOps.

To follow this, I would recommend installing the following:

Ansible requires a Linux server that can communicate to nodes you desire to configure. For this blog, I have created an Azure ARM Template which will provision a single Azure CentOS VM with Ansible pre-installed:

git clone

cd .\blog\Ansible\Ansible-ARM


Select-AzSubscription -SubscriptionId <SubscriptionID>

New-AzResourceGroup -Name <ResourceGroupName> -Location <AzureRegion>

New-AzResourceGroupDeployment -Name ansible -ResourceGroupName <ResourceGroupName> -TemplateFile .\azuredeploy.json -TemplateParameterFile .\azuredeploy.parameters.json

Additionally, Ansible requires WINRM on Windows Server. Therefore, I have also created an Azure ARM template that provisions a Windows Server that has WINRM pre-configured using CREDSSP:

git clone

cd .\blog\Ansible\WindowsServer


Select-AzSubscription -SubscriptionId <SubscriptionID>

New-AzResourceGroup -Name <ResourceGroupName> -Location <AzureRegion>

New-AzResourceGroupDeployment -Name ansible -ResourceGroupName <ResourceGroupName> -TemplateFile .\azuredeploy.json -TemplateParameterFile .\azuredeploy.parameters.json

Also, you will require an Azure Key Vault, run the below PowerShell to deploy:

$ResourceGroupName = "<ResourceGroupName>"
$KeyVaultName = "<KeyVaultName>"
$Location = "<AzureRegion>"

$RG = Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue
if (!$RG) {
    New-AzResourceGroup -Name $ResourceGroupName -Location $Location

New-AzKeyVault -Name $KeyVaultName -ResourceGroupName RGEUWKV01 -Location $Location

Once, the above has been deployed. Sign up to Azure DevOps and create a new project. Select “Project Settings” at the bottom left:

Then select Agent Pools:

Select “New Agent”:

Select “Self Hosted” and enter an Agent pool name. I would recommend, naming it Ansible as this will be a used for the Ansible hosts:

Now select the settings button at the top right. Select “Personal Access Tokens”:

Name the Personal Access Tokens (PAT). Specify an expiry date and ensure that “Deployment Groups” has Read & Manage Permissions are selected:

Azure DevOps will now display the PAT token in plain text. Copy the token and save it to the Azure Key Vault, as this token won’t be stored:

Now back to the Azure Portal, select the deployed Key Vault then select Access Policy and add Access Policy:

Enter your Azure Active Directory identity, then select the required permissions:

Now add the below secrets into your Azure Key Vault:

Now we need to link the Azure Key Vault Secrets to an Azure Dev Ops Variable Group so that they can be used throughout the Azure DevOps Pipeline. Login to the Azure DevOps, select Pipelines then Library. Within this section create a Variable Group:

Enter a variable group name then select “Link secrets from an Azure Key Vault as variables”. Authorize your Azure Subscription:

Once the Azure Subscription has been authorized, select the Key Vault and select Authorize:

Select the stored local admin username, local admin password and domain username and domain password (If Domain Joining is a requirement for your deployment.)

Now SSH to the Ansible Server deployed earlier and run the following SSH commands:

# Create Agent Directory
mkdir myagent && cd myagent

# Download Agent


# Extract Agent 
tar zxvf vsts-agent-linux-x64-2.171.1.tar.gz

# Install required dependencies
sudo ./bin//

# Run Configuration Shell Script

# Step through the Wizard
# Accept License Agreement
# Enter<organisationname>
# Auth = PAT
# Enter Personal Access Token
# Enter Pool Name Ansible
# Enter Name of Agent
# Enter path for work folder

# Install agent as systemctl service
sudo ./ install

# Start Service
sudo ./ start

Once completed, navigate back to the Azure DevOps Agent Pools, to check the status of the Azure DevOps private agent. Provided everything went okay in the last step, it should report as “Online”:

The next step is to import my blog repository from the GitHub. Select Repos then select “Import”, under the “Import a repository” section:

Enter my GitHub Blog Repo URL:

Within Azure DevOps, select Pipelines then Pipelines again. Within this section we will create an Azure Build Pipeline. Select Create Pipeline:

Select Azure Repos Git:

Select, the Repo we imported earlier:

Select “Existing Azure Pipelines YAML file”

Select the following path /Ansible/Build-Pipeline/azure-pipelines.yml

Below is an example of the Pipeline:

- master

 vmImage: 'windows-latest'

- task: CopyFiles@2
    SourceFolder: 'Ansible'
    Contents: '**'
    TargetFolder: '$(build.artifactstagingdirectory)/Ansible'
- task: PublishBuildArtifacts@1
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

The above pipeline will copy/publish the files within the repository to the “build.artifactstagingdirectory”, when a new commit is made. This will enable the files within the Repo to be used during the Release Pipeline, in the next step.

Navigate to Pipelines, Releases then select “Create Pipeline”:

If prompted for a template selection, select “Empty Job”. Next we need to add an artifact to be used throughout the pipeline. Select “Add an artifact” . Select “Build” then select Build Pipeline and accept the defaults:

Under Stage 1, select “1 job”:

Select “Agent Job” and change the Agent Pool to the pool containing the Ansible server:

Ansible requires credentials to the nodes that you desire to configure. Earlier within the blog, we imported these credentials into the Azure Key Vault, then linked them to an Azure DevOps pipeline. For these credentials to be used throughout the pipeline we need to link the Variable Group to the Pipeline. To do this select “Variables”, “Variables groups” then select Link variable groups:

Select the Variable Group we created earlier then select “Link”:

Select the plus button on the Agent Job, and search for Ansible. If you haven’t used Ansible within your DevOps organisation, you will require to install the extension into your DevOps organisation. If so, select “Get it free” and follow the guidance within the Azure Marketplace:

If the Ansible extension is already installed, then search for Ansible and select “Add”. Set the path to the following:


This Playbook, will set Windows Server region and time/date settings to UK. Additionally the template will join the server to a domain, domain settings can be specified within the variable file:

domainname: blog.local
OU: "OU=Servers,DC=blog,DC=local"

Under “Inventory location” section, select “Inline” and paste the below:

ServerName ansible_host=<ServerIP>


The following varibles are being securely passed in from the Azure Key Vault using Variable Groups:

  • $(AnsibleUser)
  • $(AnsiblePassword)
  • $(DomainUser)
  • $(DomainPassword)

Once completed, save the pipeline and browse to Pipelines, Releases, <Pipeline name>. Then select “Create Release”:

If this was successful, create another release pipeline with the following settings:

File path:


Inventory Inline:

ServerName ansible_host=<server-ip>


The above template will install the web server IIS Windows server role. Once completed. Navigate back to Pipelines, Releases and create a release:

This image has an empty alt attribute; its file name is image-35.png


Azure DevOps pipelines are a perfect way to deliver environments in Azure using Infrastructure as code with tooling such as ARM Templates or Terraform. This can also be extended to configuration management using tools such as Ansible. Using Azure DevOps to orchestrate Ansible in this way, enables additional functionality outside of the standard version of Ansible, such as storing passwords securely within Azure Key Vault then passing them in via Azure DevOps Variable Groups.


Blog at

Up ↑