Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
"language": "en",
"words": [
"Contoso",
"Delicensing",
"Docusaurus",
"Entra",
"Maester",
"MOERA",
"passwordless",
"SSPR",
"XSPM"
Expand Down
215 changes: 120 additions & 95 deletions powershell/public/maester/exchange/Test-MtExoMoeraMailActivity.ps1
Original file line number Diff line number Diff line change
@@ -1,95 +1,120 @@
<#
.SYNOPSIS
Checks the sent mail activity for MOERA addresses in the past 7 days.

.DESCRIPTION
This command retrieves the mail actiivty for the past 7 days, and checks
for any sent mail from MOERA addresses.

.EXAMPLE
Test-MtExoMoeraMailActivity

Returns true if no sent mail activity from MOERA addresses in past 7 days.

.LINK
https://maester.dev/docs/commands/Test-MtExoMoeraMailActivity
#>
function Test-MtExoMoeraMailActivity {
[CmdletBinding()]
[OutputType([bool])]
param()

if (!(Test-MtConnection Graph)) {
Add-MtTestResultDetail -SkippedBecause NotConnectedGraph
return $null
}

try {
Write-Verbose "Checking current report obfuscation"
$reportSettings = Invoke-MgGraphRequest -Method Get -Uri "v1.0/admin/reportSettings"
} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
}

if ($reportSettings.displayConcealedNames -and !((Get-MgContext).Scopes -contains "ReportSettings.ReadWrite.All")) {
Add-MtTestResultDetail -SkippedBecause LimitedPermissions
return $null
} elseif ($reportSettings.displayConcealedNames) {
try {
Write-Verbose "Disabling report obfuscation"
Invoke-MgGraphRequest -Method PATCH -Uri "v1.0/admin/reportSettings" -Body (@{displayConcealedNames = $false}|ConvertTo-Json)
} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
}
}
$file = "$([System.IO.Path]::GetTempPath())maester-EmailActivityUserDetail.csv"

try {
Write-Verbose "Downloading report"
$oProgressPreference = $ProgressPreference # save progressPreference
$ProgressPreference = 'SilentlyContinue'
Invoke-MgGraphRequest -Uri "v1.0/reports/getEmailActivityUserDetail(period='D7')" -OutputFilePath $file
} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
} finally {
# Always restore progressPreference, even if exception occurs
$ProgressPreference = $oProgressPreference
}
$results = Import-Csv $file
$filteredResults = $results|Where-Object {
$_."User Principal Name" -like "*.onmicrosoft.com" -and `
$_."Send Count" -gt 0
}

$testResult = ($filteredResults|Measure-Object).Count -gt 0
if (!$testResult){
$testResultMarkdown = "Well Done. Microsoft Online Exchange Routing Addresses (MOERA) are not in use for sending email in the past 7 days.`n`n"
} else {
$testResultMarkdown = "Microsoft Online Exchange Routing Addresses (MOERA) are in use for sending email in the past 7 days.`n`n"
$testResultMarkdown += "| User Principal Name | Send Count |`n"
$testResultMarkdown += "| --- | --- |`n"
foreach ($result in $filteredResults){
$testResultMarkdown += "| $($result."User Principal Name") | $($result."Send Count") |`n"
}
}

if ($reportSettings.displayConcealedNames) {
try {
Write-Verbose "Enabling report obfuscation"
Invoke-MgGraphRequest -Method PATCH -Uri "v1.0/admin/reportSettings" -Body (@{displayConcealedNames = $true}|ConvertTo-Json)
} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
}
}
Write-Verbose "Removing temp report file"
Remove-Item $file

Write-Verbose $testResultMarkdown|ConvertTo-Json -Compress
Add-MtTestResultDetail -Result $testResultMarkdown

return !$result
}
function Test-MtExoMoeraMailActivity {
<#
.SYNOPSIS
Checks the sent mail activity for MOERA addresses in the past 7 days.

.DESCRIPTION
This command retrieves the mail activity for the past 7 days, and checks
for any sent mail from MOERA addresses.

.EXAMPLE
Test-MtExoMoeraMailActivity

Returns true if no sent mail activity from MOERA addresses in past 7 days.

.LINK
https://maester.dev/docs/commands/Test-MtExoMoeraMailActivity
#>
[CmdletBinding()]
[OutputType([bool])]
param()

begin {
if (!(Test-MtConnection Graph)) {
Add-MtTestResultDetail -SkippedBecause NotConnectedGraph
return $null
}

# Prepare temp file for report download
$file = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "Maester-EmailActivityUserDetail-$(Get-Date -Format yyMMddHHmmss).csv"

# Track if we disabled obfuscation to re-enable it later
$obfuscationWasDisabled = $false
}

process {
try {
Write-Verbose 'Checking current report obfuscation'
$reportSettings = Invoke-MgGraphRequest -Method Get -Uri 'v1.0/admin/reportSettings'
} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
}

# Check if report obfuscation is enabled (displayConcealedNames) and if we have the necessary permissions to disable it
# Note: This endpoint requires ReportSettings.ReadWrite.All permission (application permission, not delegated)
# and the application identity must have appropriate admin roles assigned (Reports Administrator or Security Administrator)
if ($reportSettings.displayConcealedNames -and ((Get-MgContext).Scopes -contains 'ReportSettings.ReadWrite.All')) {
try {
Write-Verbose 'Disabling report obfuscation'
[void](Invoke-MgGraphRequest -Method PATCH -Uri 'v1.0/admin/reportSettings' -Body (@{displayConcealedNames = $false } | ConvertTo-Json))
$obfuscationWasDisabled = $true
} catch {
Write-Verbose "Failed to disable report obfuscation: $_. Continuing with obfuscated data."
}
} elseif ($reportSettings.displayConcealedNames) {
Write-Verbose 'Report obfuscation is enabled but insufficient permissions to disable it. Continuing without de-obfuscating user details.'
}

try {
Write-Verbose 'Downloading report'
$previousProgressPreference = $ProgressPreference # save progressPreference
$ProgressPreference = 'SilentlyContinue'
Invoke-MgGraphRequest -Uri "v1.0/reports/getEmailActivityUserDetail(period='D7')" -OutputFilePath $file
} catch {
# Unable to download report
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
} finally {
# Always restore progressPreference, even if exception occurs
$ProgressPreference = $previousProgressPreference
}
$results = Import-Csv $file -ErrorVariable ImportCsvError

if (-not $results) {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError "Failed to import CSV report: $ImportCsvError"
return $null
}

# Filter for MOERA addresses (*.onmicrosoft.com) that have sent mail
# MOERA addresses are not intended for sending email and should not be used
$filteredResults = $results | Where-Object {
$_.'User Principal Name' -like '*.onmicrosoft.com' -and `
$_.'Send Count' -gt 0
}

# Return true (pass) if no results found; false (fail) if any results found.
[bool]$testResult = ($filteredResults | Measure-Object).Count -eq 0
if ($testResult) {
$testResultMarkdown = "Well Done. Microsoft Online Exchange Routing Addresses (MOERA) are not in use for sending email in the past 7 days.`n`n"
} else {
$testResultMarkdown = "Microsoft Online Exchange Routing Addresses (MOERA) are in use for sending email in the past 7 days.`n`n"
$testResultMarkdown += "| User Principal Name | Send Count |`n"
$testResultMarkdown += "| --- | --- |`n"
foreach ($result in $filteredResults) {
$testResultMarkdown += "| $($result.'User Principal Name') | $($result.'Send Count') |`n"
}
}

Write-Verbose $testResultMarkdown
Add-MtTestResultDetail -Result $testResultMarkdown

return $testResult
}

end {
# Re-enable report obfuscation if we disabled it
if ($obfuscationWasDisabled) {
try {
Write-Verbose 'Re-enabling report obfuscation'
[void](Invoke-MgGraphRequest -Method PATCH -Uri 'v1.0/admin/reportSettings' -Body (@{displayConcealedNames = $true } | ConvertTo-Json))
} catch {
# If we fail to re-enable obfuscation, log a warning but do not fail the test
Write-Warning "Failed to re-enable report obfuscation: $_"
}
}

Write-Verbose 'Removing temp report file'
Remove-Item $file -ErrorAction SilentlyContinue
}
}