It’s not often that someone releases a new product that is, totally free, open source and awesome. When it first popped up in my feed, I stopped what I was doing, ran 5 lines of code and received a beautifully designed security report telling me everything I needed to improve in my Microsoft 365 tenant. Better yet, it’s just a PowerShell module, so I can automate it anyway I like.
The product is Maester. An open-source PowerShell tool developed by @Merill Fernando, @Fabian Bader & @Thomas Nuanheim.
Keep reading below to follow my experience from installing the module and running the report. Then automating the report using Azure Automation.
Page Contents
How to install the Maester PowerShell module
There are two dependencies for the Maester module, these are:
- Microsoft.Graph.Authentication (v2.2.0): Utilised for obtaining access tokens for Microsoft Graph.
- Pester (v5.5.0): A popular testing framework for PowerShell.
To install the Maester PowerShell module, run the following commands: (both dependencies will be deployed automatically if you skipped the first line)
Install-Module Pester -SkipPublisherCheck -Force -Scope CurrentUser
Install-Module Maester -Scope CurrentUser
md maester-tests
cd maester-tests
Install-MaesterTests .\tests
Run a Microsoft 365 security report
Running the pre-defined security assessment for your Microsoft 365 tenant could not be easier, simply connect to Microsoft Graph and invoke the primary script.
To connect to Microsoft Graph, Maester includes a custom cmdlet ‘Connect-Maester‘ which utilises the Connect-MgGraph cmdlet and some predefined scopes, these are:
- Directory.Read.All
- Policy.Read.All
- Reports.Read.All
- DirectoryRecommendations.Read.All
The Get-MtGraphScope cmdlet will also expose which permissions are consented to by default using the Connect-Maester cmdlet, this will be useful as the tool expands and hence the scopes change.
Connect to Maester using the provided commands
Use the below commands to connect to Microsoft Graph using the Maester option.
#Connect using the default scopes
Connect-Maester
#Connect using the default scopes + send mail as you permission
Connect-Maester -SendMail
Connect to Maester using the Microsoft Graph PowerShell SDK
Use the below command to connect to Microsoft Graph using the Graph SDK.
$Scopes = @(
"Directory.Read.All"
"Policy.Read.All",
"Reports.Read.All",
"DirectoryRecommendations.Read.All",
"Mail.Send"
)
Connect-MgGraph -Scopes $Scopes
Run the built-in security assessment
Use the below command to run the built-in security assessment. By default, the output will be located in the current path of your PowerShell session plus ./test-results.
Invoke-Maester
You can modify the output path with the following example
Invoke-Maester -OutputFolder C:\temp
After a minute or two, your report should automatically open and look like the following:
You can then select the info button next to each test to review detailed information on the test and test results.
Automating the report with Azure Automation
The great thing about Maester is that it is designed to be run using DevOps services, currently supporting Azure DevOps and GitHub Actions. (Both hyperlinks will take you to the relevant docs).
In this section, I will show you how to automate the report using Azure Automation. Follow the below steps to setup automated reporting with Maester using Azure Automation:
Step 1: Create an Automation Account
2. Click Create.
3. Select your subscription, and resource group, then define the account name and region.
4. Click Next, leave System assigned managed identity selected and click Next.
5. Complete the final pages and click Create.
Step 2: Assign permissions to the System-assigned managed identity
Now the Automation Account has been created, a service principal (or Managed Identity) will also have been created. To run the Maester report using this Managed Identity, the required permissions (as listed above) must be granted to it.
To grant the necessary permissions to the Managed Identity, use the below script and when prompted, sign in with a Global Administrator account.
Ensure you modify the first line with the name of the Automation Account you created earlier (this will match the name of the System-assigned managed identity that was created).
(Remember, the Mail.Send permission in the application context, applied to all mail users, consider creating an application access policies to limit the scope of Exchange access.).
$ManagedIdentityName = "M365SecurityAssessment"
Connect-MgGraph -Scopes $Scopes
$Scopes = @(
"Application.Read.All",
"AppRoleAssignment.ReadWrite.All"
)
$permissions = @(
"Directory.Read.All",
"Policy.Read.All",
"Reports.Read.All",
"DirectoryRecommendations.Read.All",
"Mail.Send"
)
$getPerms = (Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'").approles | Where {$_.Value -in $permissions}
$ManagedIdentity = (Get-MgServicePrincipal -Filter "DisplayName eq '$ManagedIdentityName'")
$GraphID = (Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'").id
foreach ($perm in $getPerms){
New-MgBetaServicePrincipalAppRoleAssignment -ServicePrincipalId $ManagedIdentity.Id `
-PrincipalId $ManagedIdentity.Id -ResourceId $GraphID -AppRoleId $perm.id
}
Step 3: Load the required PowerShell modules
2. Click Create.
3. Define a Name, select PowerShell as the language and Runtime version as 7.2.
4. Click Next.
5. On the Packages tab, click Add from gallery and select the following packages:
- Maester
- Microsoft.Graph.Authentication
- Pester
- Microsoft.Graph.Users.Actions (optional to send the Zipped report files via email)
6. Click Next and Create.
Step 4: Create a new Runbook
1. Under Process Automation click Create.
2. Select Create new next to Runbook, then define a name for the Runbook.
3. Next to Runbook type, select PowerShell, then choose the Runtime Environment you previously created.
4. Click Create. You will be taken to the Edit in portal page.
5. Copy and paste this essential code:
The below example will connect to Microsoft Graph using the managed identity, generate the report in a custom location and email said report to the recipient you define (ensure you update the $MailRecipient variable below).
Connect-MgGraph -Identity
#Define mail recipient
$MailRecipient = "Define Sender/Recipient"
#create output folder
$date = (Get-Date).tostring("yyyyMMdd-HHmm")
$FileName = "MaesterReport" + $Date + ".zip"
$TempOutputFolder = $env:TEMP + $date
if (!(Test-Path $TempOutputFolder -PathType Container)) {
New-Item -ItemType Directory -Force -Path $TempOutputFolder
}
#Run Maester report
cd $env:TEMP
md maester-tests
cd maester-tests
Install-MaesterTests .\tests
Invoke-Maester -MailUserId $MailRecipient -MailRecipient $MailRecipient -OutputFolder $TempOutputFolder
Once the Runbook has completed its first cycle, you will receive the security report via email.
The only issue is that the report utilises a simplified HTML replacement that cannot be interested in like the .HTML file output. To also receive a separate file with a Zipped copy of the source report file, add the following code to your Runbook.
#Compress output to Zip
Compress-Archive -Path $TempOutputFolder -DestinationPath "$TempOutputFolder\$FileName"
#Send Zip attachment with Microsoft Graph
$Attachment = "$TempOutputFolder\$FileName"
$MailAttachement = [Convert]::ToBase64String([IO.File]::ReadAllBytes($Attachment))
$body = @{
message = @{
subject = "Maester Test Results Files"
body = @{
contentType = "Text"
content = "Please see your Maester Test Results files attached"
}
toRecipients = @(
@{
emailAddress = @{
address = "$MailRecipient"
}
}
)
attachments = @(
@{
"@odata.type" = "#microsoft.graph.fileAttachment"
name = "$FileName"
contentType = "text/plain"
contentBytes = $MailAttachement
}
)
}
saveToSentItems = "false"
}
Send-MgUserMail -UserId $MailRecipient -BodyParameter $body
You will then receive a separate email with the source files attached.
Define a report schedule
The final step is to define how often you want the report to run. When you do this, you should ensure you schedule it at a frequency where you will have the time to meaningfully review and action any necessary changes. I recommended running it monthly. Follow the below steps to configure a monthly schedule.
2. Under Shared Resources, select Schedules.
3. Click Add a schedule and define a name.
4. Set the Recurrence to Recurring, select Recur every 1 Month and set Run on last day of month to Yes.
5. Click Create.
6. Under Process Automation, select Runbooks and open your Runbook.
7. Click Schedules > Add a schedule.
8. Choose your schedule and click OK.
You have now successfully deployed Maester using Azure Automation!