diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index a8c73d300..3bedbe72d 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -262,7 +262,8 @@ 'Test-MtEntitlementManagementOrphanedResources', 'Test-MtEntitlementManagementValidApprovers', 'Test-MtEntitlementManagementValidResourceRoles', 'Test-MtEntraDeviceJoinRestricted', 'Test-MtEntraIDConnectSsso', 'Test-MtEntraIDConnectSyncOnPremisesObjectIdentifierUpdatesBlocked', - 'Test-MtEntraIDConnectSyncSoftHardMatching', 'Test-MtKrbtgtAzureADNotSynced', 'Test-MtExoDelicensingResiliency', + 'Test-MtEntraIDConnectSyncSoftHardMatching', 'Test-MtEntraMsolPowerShellBlocked', + 'Test-MtKrbtgtAzureADNotSynced', 'Test-MtExoDelicensingResiliency', 'Test-MtExoMailTip', 'Test-MtExoModernAuth', 'Test-MtExoMoeraMailActivity', 'Test-MtExoOutlookAddin', 'Test-MtExoRejectDirectSend', 'Test-MtExoSetScl', 'Test-MtFeatureUpdatePolicy', 'Test-MtGroupCreationRestricted', 'Test-MtHighRiskAppPermissions', 'Test-MtIntuneAppControl', 'Test-MtIntuneASRRules', 'Test-MtIntuneDiagnosticSettings', diff --git a/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.md b/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.md new file mode 100644 index 000000000..0aafd00c9 --- /dev/null +++ b/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.md @@ -0,0 +1,34 @@ +## Description + +Checks if the legacy MSOnline (MSOL) PowerShell module is blocked from authenticating to the tenant. + +## Why This Matters + +The MSOnline (MSOL) and Azure AD PowerShell modules were retired by Microsoft and no longer receive security updates. Because they predate modern authentication controls, requests made through them can be a weaker, less-monitored path into a tenant's identity administration than the current Microsoft Graph PowerShell SDK. + +The `blockMsolPowerShell` setting on the tenant's authorization policy lets an admin explicitly block authentication requests from the legacy MSOnline PowerShell module's service principal. This isn't enabled by default for every tenant, so it needs to be checked explicitly rather than assumed to already be in place — leaving it unblocked keeps an unsupported and unmonitored administrative access path open. + +### Remediation action: + +1. Connect to Graph using **Connect-MgGraph -Scopes "Policy.ReadWrite.Authorization"**. +2. Run the following PowerShell command to review the current value: +```powershell +Get-MgPolicyAuthorizationPolicy | Select-Object BlockMsolPowerShell +``` +3. If `BlockMsolPowerShell` is `$false`, block the legacy MSOnline PowerShell module: +```powershell +# This example uses the cmdlet syntax published in the Microsoft Learn documentation: +# https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.signins/update-mgpolicyauthorizationpolicy +$params = @{ + blockMsolPowerShell = $true +} +Update-MgPolicyAuthorizationPolicy -BodyParameter $params +``` + +### Related links + +* [Authorization policy in Entra ID | Microsoft Learn](https://learn.microsoft.com/en-us/graph/api/resources/authorizationpolicy) +* [Update-MgPolicyAuthorizationPolicy | Microsoft Learn - Graph PowerShell v1.0](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.signins/update-mgpolicyauthorizationpolicy) + + +%TestResult% diff --git a/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.ps1 b/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.ps1 new file mode 100644 index 000000000..a91972d01 --- /dev/null +++ b/powershell/public/maester/entra/Test-MtEntraMsolPowerShellBlocked.ps1 @@ -0,0 +1,54 @@ +function Test-MtEntraMsolPowerShellBlocked { + <# + .SYNOPSIS + Checks if the legacy MSOnline (MSOL) PowerShell module is blocked from authenticating to the tenant + + .DESCRIPTION + The MSOnline (MSOL) and Azure AD PowerShell modules were retired by Microsoft and no longer receive + security updates. The blockMsolPowerShell setting on the tenant's authorization policy lets an admin + explicitly block authentication requests from the legacy MSOnline PowerShell module's service + principal, closing an unsupported and unmonitored administrative access path. + + This setting isn't enabled by default for every tenant, so it needs to be checked explicitly rather + than assumed to already be in place. + + .EXAMPLE + Test-MtEntraMsolPowerShellBlocked + + Returns true if the legacy MSOnline (MSOL) PowerShell module is blocked from authenticating to the tenant + + .LINK + https://maester.dev/docs/commands/Test-MtEntraMsolPowerShellBlocked + #> + [CmdletBinding()] + [OutputType([bool])] + param() + + if (-not (Test-MtConnection Graph)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedGraph + return $null + } + + Write-Verbose "Checking if the legacy MSOnline (MSOL) PowerShell module is blocked..." + try { + $authorizationPolicy = Invoke-MtGraphRequest -RelativeUri "policies/authorizationPolicy" -Select "blockMsolPowerShell" -ErrorAction Stop + + $msolPowerShellBlocked = $authorizationPolicy.blockMsolPowerShell -eq $true + + if ($msolPowerShellBlocked) { + $testResult = "Well done. The legacy MSOnline (MSOL) PowerShell module is blocked from authenticating to this tenant." + } else { + $testResult = "The legacy MSOnline (MSOL) PowerShell module is **not** blocked for this tenant.`n`n" ` + + "The MSOnline module was retired by Microsoft and no longer receives security updates, so leaving it unblocked keeps an unsupported and unmonitored administrative access path open." + } + Add-MtTestResultDetail -Result $testResult + return $msolPowerShellBlocked + } catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 403) { + Add-MtTestResultDetail -SkippedBecause NotAuthorized + } else { + Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ + } + return $null + } +} diff --git a/tests/Maester/Entra/Test-MtEntraMsolPowerShellBlocked.Tests.ps1 b/tests/Maester/Entra/Test-MtEntraMsolPowerShellBlocked.Tests.ps1 new file mode 100644 index 000000000..e651ac618 --- /dev/null +++ b/tests/Maester/Entra/Test-MtEntraMsolPowerShellBlocked.Tests.ps1 @@ -0,0 +1,6 @@ +Describe "Maester/Entra" -Tag "Maester", "Entra" { + It "MT.1185: Block legacy MSOnline (MSOL) PowerShell module. See https://maester.dev/docs/tests/MT.1185" -Tag "MT.1185" { + $result = Test-MtEntraMsolPowerShellBlocked + $result | Should -Be $true -Because "the legacy MSOnline (MSOL) PowerShell module should be blocked from authenticating to the tenant." + } +} diff --git a/tests/maester-config.json b/tests/maester-config.json index 390cd83aa..0599fadcc 100644 --- a/tests/maester-config.json +++ b/tests/maester-config.json @@ -1538,6 +1538,11 @@ "Severity": "Medium", "Title": "Conditional Access policy without any target resources configured" }, + { + "Id": "MT.1185", + "Severity": "High", + "Title": "Block legacy MSOnline (MSOL) PowerShell module" + }, { "Id": "MT.1178", "Severity": "High",