Skip to main content
Version: 3.0.0-preview

Set up Maester in Azure DevOps

This guide will walk you through setting up Maester in Azure DevOps and automate the running of tests using Azure DevOps Pipelines.

Why Azure DevOps?โ€‹

Azure DevOps is a great way to automate the daily running of Maester tests to monitor your tenant. You can use Azure DevOps to run Maester tests on a schedule, such as daily, and view the results in the Azure DevOps interface.

Azure DevOps comes with a free tier that includes 1,800 minutes of Maester test runs per month (unlimited hours if you use a self-hosted agent).

Azure DevOps has native integration with Microsoft Entra including single sign on, user and group management as well as support for conditional access policies.

Set up the Maester repository in Azure DevOpsโ€‹

Pre-requisitesโ€‹

Create the repository for your pipelineโ€‹

The built-in Maester tests ship inside the Maester PowerShell module, so you don't need to import or copy any tests. The repository only holds your pipeline definition and, optionally, your own custom tests and maester-config.json.

  • Select Repos from the left-hand menu
  • In the Initialize main branch with a README or gitignore section, select Initialize to create the default repository for your project.
  • Optionally, to add your own tests and configuration, clone the repository and run Install-MaesterTests in it. This creates a custom folder and a starter maester-config.json that you can commit. See Writing custom tests and Run configuration.

Set up the Azure Pipelineโ€‹

There are many ways to authenticate with Microsoft Entra in Azure DevOps. We recommend using workload identity federation as it is more secure, requires less maintenance and is the easiest to set up.

If youโ€™re unable to use more advanced options like certificates stored in Azure Key Vault, which need an Azure subscription, thereโ€™s also guidance available for using client secrets.

  • Workload identity federation (recommended) uses OpenID Connect (OIDC) to authenticate with Microsoft Entra protected resources without using secrets.
  • Client secret uses a secret to authenticate with Microsoft Entra protected resources.

Pre-requisitesโ€‹

Create an empty Azure Resource Groupโ€‹

This empty resource group is required to set up workload identity federation authentication. No Azure resources will be created in this resource group and there are no costs associated with it.

  • Browse to the Azure portal and open the Resource groups blade.
  • Select + Create.
  • Enter a name for the resource group (e.g. Maester-Resource-Group)
  • Select any region
  • Select Review + create > Create

Create a new workload identity federation service connectionโ€‹

  • In the Azure DevOps project, go to Project settings > Service connections.
  • Select New service connection, and then select Azure Resource Manager.
  • Select Workload identity federation (automatic).
  • Specify the following parameters:
    • Subscription: Select an existing Azure subscription.
    • Resource Group: Select the resource group created in the previous step. (e.g. Maester Resource Group) Leaving this field empty will grant Contribute access to all resources in the subscription.
    • Service connection name: A name for this connection (e.g. Maester Service Connection)
  • Select Save to create the connection.

Grant permissions to Microsoft Graphโ€‹

  • Select the service connection you created in the previous step (e.g. Maester Service Connection)
    • Service connections are listed under Project settings > Service connections.
  • Select Manage Service Principal to open the Service Principal in the Entra portal.
  • Select API permissions > Add a permission
  • Select Microsoft Graph > Application permissions
  • Search for each of the permissions and check the box next to each permission:
    • AuditLog.Read.All
    • DeviceManagementConfiguration.Read.All
    • DeviceManagementManagedDevices.Read.All
    • DeviceManagementRBAC.Read.All
    • DeviceManagementServiceConfig.Read.All
    • Directory.Read.All
    • DirectoryRecommendations.Read.All
    • EntitlementManagement.Read.All
    • IdentityRiskEvent.Read.All
    • NetworkAccess.Read.All
    • OnPremDirectorySynchronization.Read.All
    • OrgSettings-AppsAndServices.Read.All
    • OrgSettings-Forms.Read.All
    • Policy.Read.All
    • Policy.Read.ConditionalAccess
    • Reports.Read.All
    • ReportSettings.Read.All
    • RoleEligibilitySchedule.Read.Directory
    • RoleManagement.Read.All
    • RoleManagementAlert.Read.Directory
    • SecurityIdentitiesSensors.Read.All
    • SecurityIdentitiesHealth.Read.All
    • SharePointTenantSettings.Read.All
    • ThreatHunting.Read.All
    • UserAuthenticationMethod.Read.All

    To run preview Agent ID tests, also grant these application permissions:

    • AgentIdentity.Read.All
    • AgentIdentityBlueprint.Read.All
    • AgentIdentityBlueprintPrincipal.Read.All
    • Application.Read.All
  • Optionally, search for each of the permissions if you want to allow privileged permissions:
    • ReportSettings.ReadWrite.All
      • Required to disable report obfuscation
  • Select Add permissions
  • Select Grant admin consent for [your organization]
  • Select Yes to confirm

Create Azure Pipelineโ€‹

  • Open your Azure DevOps project
  • Select Pipelines > New pipeline
  • Select Azure Repos Git as the location of your code
  • Select the repository you created earlier
  • Select Starter pipeline
  • Replace the content of the azure-pipelines.yml file with the code below
  • Verify the azureSubscription value is set to the service connection you created in the previous step (e.g. Maester Service Connection)
  • Select Validate and save > Save
  • Select Run to run the pipeline
  • Select Job to view the test results
# Maester Daily Tests

trigger:
- main

schedules:
- cron: "0 0 * * *"
displayName: Daily midnight build
branches:
include:
- main

pool:
vmImage: ubuntu-latest

steps:
- task: AzurePowerShell@5
displayName: "Run Maester"
inputs:
azureSubscription: "Maester Service Connection"
pwsh: true
azurePowerShellVersion: LatestVersion
ScriptType: InlineScript
Inline: |
# Connect to Microsoft Graph
$accessToken = (Get-AzAccessToken -ResourceTypeName MSGraph).Token
Connect-MgGraph $accessToken

# Install Maester
Install-Module Maester -Force

# Configure test results (Maester writes the NUnit XML file, Pester is not required)
$PesterConfiguration = @{
TestResult = @{
Enabled = $true
OutputPath = '$(System.DefaultWorkingDirectory)/test-results/test-results.xml'
OutputFormat = 'NUnitXml'
}
}

# Run Maester tests: the built-in tests run from the module, -Path adds any custom tests and maester-config.json in the repository
Invoke-Maester -Path '$(System.DefaultWorkingDirectory)' -PesterConfiguration $PesterConfiguration -OutputFolder '$(System.DefaultWorkingDirectory)/test-results'
- publish: $(System.DefaultWorkingDirectory)/test-results
displayName: Publish Maester Html Report
artifact: TestResults
- task: PublishTestResults@2
displayName: Publish Maester Test Results
inputs:
testResultsFormat: "NUnit"
testResultsFiles: "**/test-results.xml"
failTaskOnFailedTests: true

Viewing test resultsโ€‹

  • Select Pipelines > Runs to view the status of the pipeline
  • Select on a run to view the test results

Summary viewโ€‹

The summary view shows the status of the pipeline run, the duration, and the number of tests that passed, failed, and were skipped.

Screenshot of Azure DevOps Pipeline Run Summary Page

Maester reportโ€‹

The Maester report can be downloaded and viewed by selecting the Published artifact.

Screenshot of the downloaded Maester report

Tests viewโ€‹

The Tests tab shows a detailed view of each test, including the test name, duration, and status.

Screenshot of Azure DevOps Pipeline Tests Page

Logs viewโ€‹

In the Summary tab select on any of the errors to view the raw logs from Maester.

Screenshot of Azure DevOps Pipeline Logs Page

Keeping your Maester tests up to dateโ€‹

The Maester team adds new tests over time. The built-in tests ship inside the Maester PowerShell module, and the pipelines above run Install-Module Maester -Force, so every run uses the latest release and its tests. There is nothing to update in your repository, which only holds your own custom tests.

To control when you move to a new release, pin the version instead, for example Install-Module Maester -RequiredVersion 3.0.0 -Force, and raise it when you are ready.

tip

If you set up this pipeline with Maester 2.x by importing the maester-tests repository, see Upgrading from 2.x. The old pipeline keeps working, but you can remove the copied test folders from your repository and keep only your Custom folder and maester-config.json.

note

If your custom tests include Pester-format tests (*.Tests.ps1), add Install-Module Pester -MinimumVersion 5.7.1 -Force before Invoke-Maester. Pester is not needed for the built-in tests.