Checks/Teams/MET-Teams012-CallReporting.ps1
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'METCheckInfo', Justification = 'Check metadata. Read from the AST by Get-METCheck and never executed.')] param() $METCheckInfo = @{ Name = 'Call Reporting' Severity = 'Medium' Description = 'Checks ReportCall and SpamFilteringEnabledType across all Get-CsTeamsCallingPolicy instances, the closest native controls to helpdesk-vishing attacks over a Teams or PSTN call.' RequiresModule = @('MicrosoftTeams') } $issues = [System.Collections.Generic.List[string]]::new() $referenceUrl = 'https://learn.microsoft.com/en-us/powershell/module/microsoftteams/new-csteamscallingpolicy' try { $policies = @(Get-CsTeamsCallingPolicy -ErrorAction Stop) } catch { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'Call Reporting' ` -Result Fail -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding 'Unable to retrieve Teams calling policies.' ` -Recommendation 'Ensure the account has Teams administrator or higher permissions.' ` -ReferenceUrl $referenceUrl -ErrorMessage $_.ToString() return } $withProperty = @($policies | Where-Object { $null -ne $_.PSObject.Properties['ReportCall'] -and $null -ne $_.ReportCall }) $withoutProperty = @($policies | Where-Object { $null -eq $_.PSObject.Properties['ReportCall'] -or $null -eq $_.ReportCall }) if ($withProperty.Count -eq 0) { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'Call Reporting' ` -Result NotApplicable -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding 'No Teams calling policy returned a ReportCall property, so whether users can report a suspicious call was not established for any policy. An unconfirmed state is reported as unassessed rather than a pass, because nothing here distinguishes a tenant with call reporting enabled from one with it switched off.' ` -Recommendation 'Confirm the state directly (Get-CsTeamsCallingPolicy | Format-List Identity, ReportCall). If the property is absent there too, update the MicrosoftTeams module to a version that exposes it and re-run this check.' ` -ReferenceUrl $referenceUrl ` -ErrorMessage 'The ReportCall property was not returned by Get-CsTeamsCallingPolicy - the installed MicrosoftTeams module version may not expose it.' } else { $disabledPolicies = @($withProperty | Where-Object { $_.ReportCall -ne 'Enabled' }) if ($disabledPolicies.Count -gt 0) { $names = ($disabledPolicies | Select-Object -ExpandProperty Identity) -join ', ' $issues.Add("Call reporting (ReportCall) is disabled in the following Teams calling policy/policies: $names - users assigned to these policies cannot report a suspicious call, such as a helpdesk-vishing attempt") } if ($withoutProperty.Count -gt 0) { $unknownNames = ($withoutProperty | Select-Object -ExpandProperty Identity) -join ', ' $issues.Add("The ReportCall property was not returned for the following Teams calling policy/policies: $unknownNames - call reporting was not established for the users they are assigned to") } $confirmNote = "Confirm the policies whose ReportCall property was not returned directly (Get-CsTeamsCallingPolicy -Identity <name> | Format-List ReportCall)." if ($disabledPolicies.Count -gt 0) { $recommendation = 'Set-CsTeamsCallingPolicy -Identity <name> -ReportCall Enabled' if ($withoutProperty.Count -gt 0) { $recommendation = "$recommendation. $confirmNote" } New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'Call Reporting' ` -Result Fail -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding ($issues -join '; ') ` -Recommendation $recommendation ` -ReferenceUrl $referenceUrl } elseif ($withoutProperty.Count -gt 0) { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'Call Reporting' ` -Result Warning -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding ($issues -join '; ') ` -Recommendation $confirmNote ` -ReferenceUrl $referenceUrl } else { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'Call Reporting' ` -Result Pass -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding 'Call reporting is enabled in all Teams calling policies, allowing users to report suspicious calls such as helpdesk-vishing attempts.' ` -ReferenceUrl $referenceUrl } } $spamReferenceUrl = 'https://learn.microsoft.com/en-us/microsoftteams/configure-call-spam-filtering' $spamWith = @($policies | Where-Object { $null -ne $_.PSObject.Properties['SpamFilteringEnabledType'] -and "$($_.SpamFilteringEnabledType)" -ne '' }) $spamWithout = @($policies | Where-Object { $null -eq $_.PSObject.Properties['SpamFilteringEnabledType'] -or "$($_.SpamFilteringEnabledType)" -eq '' }) if ($spamWith.Count -eq 0) { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'PSTN Call Spam Filtering' ` -Result NotApplicable -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding 'No Teams calling policy returned a SpamFilteringEnabledType property, so whether inbound PSTN calls are screened for spam was not established for any policy. An unconfirmed state is reported as unassessed rather than a pass, because nothing here distinguishes a tenant with call spam filtering on from one with it switched off.' ` -Recommendation 'Confirm the state directly (Get-CsTeamsCallingPolicy | Format-List Identity, SpamFilteringEnabledType). If the property is absent there too, update the MicrosoftTeams module and re-run this check.' ` -ReferenceUrl $spamReferenceUrl ` -ErrorMessage 'The SpamFilteringEnabledType property was not returned by Get-CsTeamsCallingPolicy - the installed MicrosoftTeams module version may not expose it.' return } $spamIssues = [System.Collections.Generic.List[string]]::new() $spamDisabled = @($spamWith | Where-Object { "$($_.SpamFilteringEnabledType)" -eq 'Disabled' }) $spamUnknown = @($spamWith | Where-Object { "$($_.SpamFilteringEnabledType)" -ne 'Disabled' -and "$($_.SpamFilteringEnabledType)" -notlike 'Enabled*' }) if ($spamDisabled.Count -gt 0) { $names = ($spamDisabled | Select-Object -ExpandProperty Identity) -join ', ' $spamIssues.Add("PSTN call spam filtering (SpamFilteringEnabledType) is disabled in the following Teams calling policy/policies: $names - users assigned to these policies get no Spam Likely warning on inbound phone calls, the delivery channel for helpdesk-vishing and callback-phishing follow-ups") } foreach ($policy in $spamUnknown) { $spamIssues.Add("SpamFilteringEnabledType returned the unrecognized value '$($policy.SpamFilteringEnabledType)' for $($policy.Identity) - call spam filtering was not established for the users it is assigned to") } if ($spamWithout.Count -gt 0) { $unknownNames = ($spamWithout | Select-Object -ExpandProperty Identity) -join ', ' $spamIssues.Add("The SpamFilteringEnabledType property was not returned for the following Teams calling policy/policies: $unknownNames - call spam filtering was not established for the users they are assigned to") } if ($spamDisabled.Count -gt 0) { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'PSTN Call Spam Filtering' ` -Result Fail -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding ($spamIssues -join '; ') ` -Recommendation 'Set-CsTeamsCallingPolicy -Identity <name> -SpamFilteringEnabledType Enabled' ` -ReferenceUrl $spamReferenceUrl } elseif ($spamIssues.Count -gt 0) { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'PSTN Call Spam Filtering' ` -Result Warning -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding ($spamIssues -join '; ') ` -Recommendation 'Confirm the named policies directly (Get-CsTeamsCallingPolicy -Identity <name> | Format-List SpamFilteringEnabledType) and set -SpamFilteringEnabledType Enabled explicitly.' ` -ReferenceUrl $spamReferenceUrl } else { New-METCheckResult -CheckId 'MET-Teams012' -Category Teams -Name 'PSTN Call Spam Filtering' ` -Result Pass -Severity Medium -AffectedObject 'Teams Calling Policies' ` -Finding 'PSTN call spam filtering is enabled in all Teams calling policies, so likely spam calls are labelled Spam Likely before the user answers.' ` -ReferenceUrl $spamReferenceUrl } |